code.lua 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. -- $Id: testes/code.lua $
  2. -- See Copyright Notice in file all.lua
  3. if T==nil then
  4. (Message or print)('\n >>> testC not active: skipping opcode tests <<<\n')
  5. return
  6. end
  7. print "testing code generation and optimizations"
  8. -- to test constant propagation
  9. local <const> k0 = 0
  10. local <const> k1 = 1
  11. local <const> k3 = 3
  12. local <const> k6 = k3 + (k3 << k0)
  13. local <const> kFF0 = 0xFF0
  14. local <const> k3_78 = 3.78
  15. local <const> x, <const> k3_78_4 = 10, k3_78 / 4
  16. assert(x == 10)
  17. local <const> kx = "x"
  18. local <const> kTrue = true
  19. local <const> kFalse = false
  20. local <const> kNil = nil
  21. -- this code gave an error for the code checker
  22. do
  23. local function f (a)
  24. for k,v,w in a do end
  25. end
  26. end
  27. -- testing reuse in constant table
  28. local function checkKlist (func, list)
  29. local k = T.listk(func)
  30. assert(#k == #list)
  31. for i = 1, #k do
  32. assert(k[i] == list[i] and math.type(k[i]) == math.type(list[i]))
  33. end
  34. end
  35. local function foo ()
  36. local a
  37. a = k3;
  38. a = 0; a = 0.0; a = -7 + 7
  39. a = k3_78/4; a = k3_78_4
  40. a = -k3_78/4; a = k3_78/4; a = -3.78/4
  41. a = -3.79/4; a = 0.0; a = -0;
  42. a = k3; a = 3.0; a = 3; a = 3.0
  43. end
  44. checkKlist(foo, {3.78/4, -3.78/4, -3.79/4})
  45. -- testing opcodes
  46. -- check that 'f' opcodes match '...'
  47. function check (f, ...)
  48. local arg = {...}
  49. local c = T.listcode(f)
  50. for i=1, #arg do
  51. local opcode = string.match(c[i], "%u%w+")
  52. -- print(arg[i], opcode)
  53. assert(arg[i] == opcode)
  54. end
  55. assert(c[#arg+2] == undef)
  56. end
  57. -- check that 'f' opcodes match '...' and that 'f(p) == r'.
  58. function checkR (f, p, r, ...)
  59. local r1 = f(p)
  60. assert(r == r1 and math.type(r) == math.type(r1))
  61. check(f, ...)
  62. end
  63. -- check that 'a' and 'b' has the same opcodes
  64. function checkequal (a, b)
  65. a = T.listcode(a)
  66. b = T.listcode(b)
  67. assert(#a == #b)
  68. for i = 1, #a do
  69. a[i] = string.gsub(a[i], '%b()', '') -- remove line number
  70. b[i] = string.gsub(b[i], '%b()', '') -- remove line number
  71. assert(a[i] == b[i])
  72. end
  73. end
  74. -- some basic instructions
  75. check(function () -- function does not create upvalues
  76. (function () end){f()}
  77. end, 'CLOSURE', 'NEWTABLE', 'EXTRAARG', 'GETTABUP', 'CALL',
  78. 'SETLIST', 'CALL', 'RETURN0')
  79. check(function (x) -- function creates upvalues
  80. (function () return x end){f()}
  81. end, 'CLOSURE', 'NEWTABLE', 'EXTRAARG', 'GETTABUP', 'CALL',
  82. 'SETLIST', 'CALL', 'RETURN')
  83. -- sequence of LOADNILs
  84. check(function ()
  85. local <const> kNil = nil
  86. local a,b,c
  87. local d; local e;
  88. local f,g,h;
  89. d = nil; d=nil; b=nil; a=kNil; c=nil;
  90. end, 'LOADNIL', 'RETURN0')
  91. check(function ()
  92. local a,b,c,d = 1,1,1,1
  93. d=nil;c=nil;b=nil;a=nil
  94. end, 'LOADI', 'LOADI', 'LOADI', 'LOADI', 'LOADNIL', 'RETURN0')
  95. do
  96. local a,b,c,d = 1,1,1,1
  97. d=nil;c=nil;b=nil;a=nil
  98. assert(a == nil and b == nil and c == nil and d == nil)
  99. end
  100. -- single return
  101. check (function (a,b,c) return a end, 'RETURN1')
  102. -- infinite loops
  103. check(function () while kTrue do local a = -1 end end,
  104. 'LOADI', 'JMP', 'RETURN0')
  105. check(function () while 1 do local a = -1 end end,
  106. 'LOADI', 'JMP', 'RETURN0')
  107. check(function () repeat local x = 1 until true end,
  108. 'LOADI', 'RETURN0')
  109. -- concat optimization
  110. check(function (a,b,c,d) return a..b..c..d end,
  111. 'MOVE', 'MOVE', 'MOVE', 'MOVE', 'CONCAT', 'RETURN1')
  112. -- not
  113. check(function () return not not nil end, 'LOADBOOL', 'RETURN1')
  114. check(function () return not not kFalse end, 'LOADBOOL', 'RETURN1')
  115. check(function () return not not true end, 'LOADBOOL', 'RETURN1')
  116. check(function () return not not k3 end, 'LOADBOOL', 'RETURN1')
  117. -- direct access to locals
  118. check(function ()
  119. local a,b,c,d
  120. a = b*a
  121. c.x, a[b] = -((a + d/b - a[b]) ^ a.x), b
  122. end,
  123. 'LOADNIL',
  124. 'MUL',
  125. 'DIV', 'ADD', 'GETTABLE', 'SUB', 'GETFIELD', 'POW',
  126. 'UNM', 'SETTABLE', 'SETFIELD', 'RETURN0')
  127. -- direct access to constants
  128. check(function ()
  129. local a,b
  130. local c = kNil
  131. a[kx] = 3.2
  132. a.x = b
  133. a[b] = 'x'
  134. end,
  135. 'LOADNIL', 'SETFIELD', 'SETFIELD', 'SETTABLE', 'RETURN0')
  136. -- "get/set table" with numeric indices
  137. check(function (a)
  138. local <const> k255 = 255
  139. a[1] = a[100]
  140. a[k255] = a[256]
  141. a[256] = 5
  142. end,
  143. 'GETI', 'SETI',
  144. 'LOADI', 'GETTABLE', 'SETI',
  145. 'LOADI', 'SETTABLE', 'RETURN0')
  146. check(function ()
  147. local a,b
  148. a = a - a
  149. b = a/a
  150. b = 5-4
  151. end,
  152. 'LOADNIL', 'SUB', 'DIV', 'LOADI', 'RETURN0')
  153. check(function ()
  154. local a,b
  155. a[kTrue] = false
  156. end,
  157. 'LOADNIL', 'LOADBOOL', 'SETTABLE', 'RETURN0')
  158. -- equalities
  159. checkR(function (a) if a == 1 then return 2 end end, 1, 2,
  160. 'EQI', 'JMP', 'LOADI', 'RETURN1')
  161. checkR(function (a) if -4.0 == a then return 2 end end, -4, 2,
  162. 'EQI', 'JMP', 'LOADI', 'RETURN1')
  163. checkR(function (a) if a == "hi" then return 2 end end, 10, nil,
  164. 'EQK', 'JMP', 'LOADI', 'RETURN1')
  165. checkR(function (a) if a == 10000 then return 2 end end, 1, nil,
  166. 'EQK', 'JMP', 'LOADI', 'RETURN1') -- number too large
  167. checkR(function (a) if -10000 == a then return 2 end end, -10000, 2,
  168. 'EQK', 'JMP', 'LOADI', 'RETURN1') -- number too large
  169. -- comparisons
  170. checkR(function (a) if -10 <= a then return 2 end end, -10, 2,
  171. 'GEI', 'JMP', 'LOADI', 'RETURN1')
  172. checkR(function (a) if 128.0 > a then return 2 end end, 129, nil,
  173. 'LTI', 'JMP', 'LOADI', 'RETURN1')
  174. checkR(function (a) if -127.0 < a then return 2 end end, -127, nil,
  175. 'GTI', 'JMP', 'LOADI', 'RETURN1')
  176. checkR(function (a) if 10 < a then return 2 end end, 11, 2,
  177. 'GTI', 'JMP', 'LOADI', 'RETURN1')
  178. checkR(function (a) if 129 < a then return 2 end end, 130, 2,
  179. 'LOADI', 'LT', 'JMP', 'LOADI', 'RETURN1')
  180. checkR(function (a) if a >= 23.0 then return 2 end end, 25, 2,
  181. 'GEI', 'JMP', 'LOADI', 'RETURN1')
  182. checkR(function (a) if a >= 23.1 then return 2 end end, 0, nil,
  183. 'LOADK', 'LE', 'JMP', 'LOADI', 'RETURN1')
  184. checkR(function (a) if a > 2300.0 then return 2 end end, 0, nil,
  185. 'LOADF', 'LT', 'JMP', 'LOADI', 'RETURN1')
  186. -- constant folding
  187. local function checkK (func, val)
  188. check(func, 'LOADK', 'RETURN1')
  189. checkKlist(func, {val})
  190. assert(func() == val)
  191. end
  192. local function checkI (func, val)
  193. check(func, 'LOADI', 'RETURN1')
  194. checkKlist(func, {})
  195. assert(func() == val)
  196. end
  197. local function checkF (func, val)
  198. check(func, 'LOADF', 'RETURN1')
  199. checkKlist(func, {})
  200. assert(func() == val)
  201. end
  202. checkF(function () return 0.0 end, 0.0)
  203. checkI(function () return k0 end, 0)
  204. checkI(function () return -k0//1 end, 0)
  205. checkK(function () return 3^-1 end, 1/3)
  206. checkK(function () return (1 + 1)^(50 + 50) end, 2^100)
  207. checkK(function () return (-2)^(31 - 2) end, -0x20000000 + 0.0)
  208. checkF(function () return (-k3^0 + 5) // 3.0 end, 1.0)
  209. checkI(function () return -k3 % 5 end, 2)
  210. checkF(function () return -((2.0^8 + -(-1)) % 8)/2 * 4 - 3 end, -5.0)
  211. checkF(function () return -((2^8 + -(-1)) % 8)//2 * 4 - 3 end, -7.0)
  212. checkI(function () return 0xF0.0 | 0xCC.0 ~ 0xAA & 0xFD end, 0xF4)
  213. checkI(function () return ~(~kFF0 | kFF0) end, 0)
  214. checkI(function () return ~~-1024.0 end, -1024)
  215. checkI(function () return ((100 << k6) << -4) >> 2 end, 100)
  216. -- borders around MAXARG_sBx ((((1 << 17) - 1) >> 1) == 65535)
  217. local a = 17; local sbx = ((1 << a) - 1) >> 1 -- avoid folding
  218. local <const> border = 65535
  219. checkI(function () return border end, sbx)
  220. checkI(function () return -border end, -sbx)
  221. checkI(function () return border + 1 end, sbx + 1)
  222. checkK(function () return border + 2 end, sbx + 2)
  223. checkK(function () return -(border + 1) end, -(sbx + 1))
  224. local <const> border = 65535.0
  225. checkF(function () return border end, sbx + 0.0)
  226. checkF(function () return -border end, -sbx + 0.0)
  227. checkF(function () return border + 1 end, (sbx + 1.0))
  228. checkK(function () return border + 2 end, (sbx + 2.0))
  229. checkK(function () return -(border + 1) end, -(sbx + 1.0))
  230. -- immediate operands
  231. checkR(function (x) return x + k1 end, 10, 11, 'ADDI', 'RETURN1')
  232. checkR(function (x) return 128 + x end, 0.0, 128.0, 'ADDI', 'RETURN1')
  233. checkR(function (x) return x * -127 end, -1.0, 127.0, 'MULI', 'RETURN1')
  234. checkR(function (x) return 20 * x end, 2, 40, 'MULI', 'RETURN1')
  235. checkR(function (x) return x ^ -2 end, 2, 0.25, 'POWI', 'RETURN1')
  236. checkR(function (x) return x / 40 end, 40, 1.0, 'DIVI', 'RETURN1')
  237. checkR(function (x) return x // 1 end, 10.0, 10.0, 'IDIVI', 'RETURN1')
  238. checkR(function (x) return x % (100 - 10) end, 91, 1, 'MODI', 'RETURN1')
  239. checkR(function (x) return k1 << x end, 3, 8, 'SHLI', 'RETURN1')
  240. checkR(function (x) return x << 2 end, 10, 40, 'SHRI', 'RETURN1')
  241. checkR(function (x) return x >> 2 end, 8, 2, 'SHRI', 'RETURN1')
  242. checkR(function (x) return x & 1 end, 9, 1, 'BANDK', 'RETURN1')
  243. checkR(function (x) return 10 | x end, 1, 11, 'BORK', 'RETURN1')
  244. checkR(function (x) return -10 ~ x end, -1, 9, 'BXORK', 'RETURN1')
  245. -- K operands in arithmetic operations
  246. checkR(function (x) return x + 0.0 end, 1, 1.0, 'ADDK', 'RETURN1')
  247. -- check(function (x) return 128 + x end, 'ADDK', 'RETURN1')
  248. checkR(function (x) return x * -10000 end, 2, -20000, 'MULK', 'RETURN1')
  249. -- check(function (x) return 20 * x end, 'MULK', 'RETURN1')
  250. checkR(function (x) return x ^ 0.5 end, 4, 2.0, 'POWK', 'RETURN1')
  251. checkR(function (x) return x / 2.0 end, 4, 2.0, 'DIVK', 'RETURN1')
  252. checkR(function (x) return x // 10000 end, 10000, 1, 'IDIVK', 'RETURN1')
  253. checkR(function (x) return x % (100.0 - 10) end, 91, 1.0, 'MODK', 'RETURN1')
  254. -- no foldings (and immediate operands)
  255. check(function () return -0.0 end, 'LOADF', 'UNM', 'RETURN1')
  256. check(function () return k3/0 end, 'LOADI', 'DIVI', 'RETURN1')
  257. check(function () return 0%0 end, 'LOADI', 'MODI', 'RETURN1')
  258. check(function () return -4//0 end, 'LOADI', 'IDIVI', 'RETURN1')
  259. check(function (x) return x >> 2.0 end, 'LOADF', 'SHR', 'RETURN1')
  260. check(function (x) return x & 2.0 end, 'LOADF', 'BAND', 'RETURN1')
  261. -- basic 'for' loops
  262. check(function () for i = -10, 10.5 do end end,
  263. 'LOADI', 'LOADK', 'LOADI', 'FORPREP', 'FORLOOP', 'RETURN0')
  264. check(function () for i = 0xfffffff, 10.0, 1 do end end,
  265. 'LOADK', 'LOADF', 'LOADI', 'FORPREP', 'FORLOOP', 'RETURN0')
  266. -- bug in constant folding for 5.1
  267. check(function () return -nil end, 'LOADNIL', 'UNM', 'RETURN1')
  268. check(function ()
  269. local a,b,c
  270. b[c], a = c, b
  271. b[a], a = c, b
  272. a, b = c, a
  273. a = a
  274. end,
  275. 'LOADNIL',
  276. 'MOVE', 'MOVE', 'SETTABLE',
  277. 'MOVE', 'MOVE', 'MOVE', 'SETTABLE',
  278. 'MOVE', 'MOVE', 'MOVE',
  279. -- no code for a = a
  280. 'RETURN0')
  281. -- x == nil , x ~= nil
  282. -- checkequal(function (b) if (a==nil) then a=1 end; if a~=nil then a=1 end end,
  283. -- function () if (a==9) then a=1 end; if a~=9 then a=1 end end)
  284. -- check(function () if a==nil then a='a' end end,
  285. -- 'GETTABUP', 'EQ', 'JMP', 'SETTABUP', 'RETURN')
  286. do -- tests for table access in upvalues
  287. local t
  288. check(function () t[kx] = t.y end, 'GETTABUP', 'SETTABUP')
  289. check(function (a) t[a()] = t[a()] end,
  290. 'MOVE', 'CALL', 'GETUPVAL', 'MOVE', 'CALL',
  291. 'GETUPVAL', 'GETTABLE', 'SETTABLE')
  292. end
  293. -- de morgan
  294. checkequal(function () local a; if not (a or b) then b=a end end,
  295. function () local a; if (not a and not b) then b=a end end)
  296. checkequal(function (l) local a; return 0 <= a and a <= l end,
  297. function (l) local a; return not (not(a >= 0) or not(a <= l)) end)
  298. -- if-break optimizations
  299. check(function (a, b)
  300. while a do
  301. if b then break else a = a + 1 end
  302. end
  303. end,
  304. 'TEST', 'JMP', 'TEST', 'JMP', 'ADDI', 'JMP', 'RETURN0')
  305. checkequal(
  306. function (a) while a < 10 do a = a + 1 end end,
  307. function (a)
  308. ::loop::
  309. if not (a < 10) then goto exit end
  310. a = a + 1
  311. goto loop
  312. ::exit::
  313. end
  314. )
  315. checkequal(
  316. function (a) repeat local x = a + 1; a = x until a > 0 end,
  317. function (a)
  318. ::loop:: do
  319. local x = a + 1
  320. a = x
  321. end
  322. if not (a > 0) then goto loop end
  323. end
  324. )
  325. checkequal(function () return 6 or true or nil end,
  326. function () return k6 or kTrue or kNil end)
  327. checkequal(function () return 6 and true or nil end,
  328. function () return k6 and kTrue or kNil end)
  329. print 'OK'