code.lua 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347
  1. -- $Id: code.lua,v 1.55 2018/03/12 14:19:36 roberto Exp $
  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. -- this code gave an error for the code checker
  9. do
  10. local function f (a)
  11. for k,v,w in a do end
  12. end
  13. end
  14. -- testing reuse in constant table
  15. local function checkKlist (func, list)
  16. local k = T.listk(func)
  17. assert(#k == #list)
  18. for i = 1, #k do
  19. assert(k[i] == list[i] and math.type(k[i]) == math.type(list[i]))
  20. end
  21. end
  22. local function foo ()
  23. local a
  24. a = 3;
  25. a = 0; a = 0.0; a = -7 + 7
  26. a = 3.78/4; a = 3.78/4
  27. a = -3.78/4; a = 3.78/4; a = -3.78/4
  28. a = -3.79/4; a = 0.0; a = -0;
  29. a = 3; a = 3.0; a = 3; a = 3.0
  30. end
  31. checkKlist(foo, {3.78/4, -3.78/4, -3.79/4})
  32. -- testing opcodes
  33. function check (f, ...)
  34. local arg = {...}
  35. local c = T.listcode(f)
  36. for i=1, #arg do
  37. local opcode = string.match(c[i], "%u%w+")
  38. -- print(arg[i], opcode)
  39. assert(arg[i] == opcode)
  40. end
  41. assert(c[#arg+2] == undef)
  42. end
  43. function checkequal (a, b)
  44. a = T.listcode(a)
  45. b = T.listcode(b)
  46. for i = 1, #a do
  47. a[i] = string.gsub(a[i], '%b()', '') -- remove line number
  48. b[i] = string.gsub(b[i], '%b()', '') -- remove line number
  49. assert(a[i] == b[i])
  50. end
  51. end
  52. -- some basic instructions
  53. check(function ()
  54. (function () end){f()}
  55. end, 'CLOSURE', 'NEWTABLE', 'GETTABUP', 'CALL', 'SETLIST', 'CALL', 'RETURN')
  56. -- sequence of LOADNILs
  57. check(function ()
  58. local a,b,c
  59. local d; local e;
  60. local f,g,h;
  61. d = nil; d=nil; b=nil; a=nil; c=nil;
  62. end, 'LOADNIL', 'RETURN0')
  63. check(function ()
  64. local a,b,c,d = 1,1,1,1
  65. d=nil;c=nil;b=nil;a=nil
  66. end, 'LOADI', 'LOADI', 'LOADI', 'LOADI', 'LOADNIL', 'RETURN0')
  67. do
  68. local a,b,c,d = 1,1,1,1
  69. d=nil;c=nil;b=nil;a=nil
  70. assert(a == nil and b == nil and c == nil and d == nil)
  71. end
  72. -- single return
  73. check (function (a,b,c) return a end, 'RETURN1')
  74. -- infinite loops
  75. check(function () while true do local a = -1 end end,
  76. 'LOADI', 'JMP', 'RETURN0')
  77. check(function () while 1 do local a = -1 end end,
  78. 'LOADI', 'JMP', 'RETURN0')
  79. check(function () repeat local x = 1 until true end,
  80. 'LOADI', 'RETURN0')
  81. -- concat optimization
  82. check(function (a,b,c,d) return a..b..c..d end,
  83. 'MOVE', 'MOVE', 'MOVE', 'MOVE', 'CONCAT', 'RETURN1')
  84. -- not
  85. check(function () return not not nil end, 'LOADBOOL', 'RETURN1')
  86. check(function () return not not false end, 'LOADBOOL', 'RETURN1')
  87. check(function () return not not true end, 'LOADBOOL', 'RETURN1')
  88. check(function () return not not 1 end, 'LOADBOOL', 'RETURN1')
  89. -- direct access to locals
  90. check(function ()
  91. local a,b,c,d
  92. a = b*a
  93. c.x, a[b] = -((a + d/b - a[b]) ^ a.x), b
  94. end,
  95. 'LOADNIL',
  96. 'MUL',
  97. 'DIV', 'ADD', 'GETTABLE', 'SUB', 'GETFIELD', 'POW',
  98. 'UNM', 'SETTABLE', 'SETFIELD', 'RETURN0')
  99. -- direct access to constants
  100. check(function ()
  101. local a,b
  102. a.x = 3.2
  103. a.x = b
  104. a[b] = 'x'
  105. end,
  106. 'LOADNIL', 'SETFIELD', 'SETFIELD', 'SETTABLE', 'RETURN0')
  107. -- "get/set table" with numeric indices
  108. check(function (a)
  109. a[1] = a[100]
  110. a[255] = a[256]
  111. a[256] = 5
  112. end,
  113. 'GETI', 'SETI',
  114. 'LOADI', 'GETTABLE', 'SETI',
  115. 'LOADI', 'SETTABLE', 'RETURN0')
  116. check(function ()
  117. local a,b
  118. a = a - a
  119. b = a/a
  120. b = 5-4
  121. end,
  122. 'LOADNIL', 'SUB', 'DIV', 'LOADI', 'RETURN0')
  123. check(function ()
  124. local a,b
  125. a[true] = false
  126. end,
  127. 'LOADNIL', 'LOADBOOL', 'SETTABLE', 'RETURN0')
  128. -- equalities
  129. check(function (a) if a == 1 then return 2 end end,
  130. 'EQI', 'JMP', 'LOADI', 'RETURN1')
  131. check(function (a) if -4.0 == a then return 2 end end,
  132. 'EQI', 'JMP', 'LOADI', 'RETURN1')
  133. check(function (a) if a == "hi" then return 2 end end,
  134. 'EQK', 'JMP', 'LOADI', 'RETURN1')
  135. check(function (a) if a == 10000 then return 2 end end,
  136. 'EQK', 'JMP', 'LOADI', 'RETURN1') -- number too large
  137. check(function (a) if -10000 == a then return 2 end end,
  138. 'EQK', 'JMP', 'LOADI', 'RETURN1') -- number too large
  139. -- comparisons
  140. check(function (a) if -10 <= a then return 2 end end,
  141. 'GEI', 'JMP', 'LOADI', 'RETURN1')
  142. check(function (a) if 128.0 > a then return 2 end end,
  143. 'LTI', 'JMP', 'LOADI', 'RETURN1')
  144. check(function (a) if -127.0 < a then return 2 end end,
  145. 'GTI', 'JMP', 'LOADI', 'RETURN1')
  146. check(function (a) if 10 < a then return 2 end end,
  147. 'GTI', 'JMP', 'LOADI', 'RETURN1')
  148. check(function (a) if 129 < a then return 2 end end,
  149. 'LOADI', 'LT', 'JMP', 'LOADI', 'RETURN1')
  150. check(function (a) if a >= 23.0 then return 2 end end,
  151. 'GEI', 'JMP', 'LOADI', 'RETURN1')
  152. check(function (a) if a >= 23.1 then return 2 end end,
  153. 'LOADK', 'LE', 'JMP', 'LOADI', 'RETURN1')
  154. check(function (a) if a > 2300.0 then return 2 end end,
  155. 'LOADF', 'LT', 'JMP', 'LOADI', 'RETURN1')
  156. -- constant folding
  157. local function checkK (func, val)
  158. check(func, 'LOADK', 'RETURN1')
  159. local k = T.listk(func)
  160. assert(#k == 1 and k[1] == val and math.type(k[1]) == math.type(val))
  161. assert(func() == val)
  162. end
  163. local function checkI (func, val)
  164. check(func, 'LOADI', 'RETURN1')
  165. assert(#T.listk(func) == 0)
  166. assert(func() == val)
  167. end
  168. local function checkF (func, val)
  169. check(func, 'LOADF', 'RETURN1')
  170. assert(#T.listk(func) == 0)
  171. assert(func() == val)
  172. end
  173. checkF(function () return 0.0 end, 0.0)
  174. checkI(function () return 0 end, 0)
  175. checkI(function () return -0//1 end, 0)
  176. checkK(function () return 3^-1 end, 1/3)
  177. checkK(function () return (1 + 1)^(50 + 50) end, 2^100)
  178. checkK(function () return (-2)^(31 - 2) end, -0x20000000 + 0.0)
  179. checkF(function () return (-3^0 + 5) // 3.0 end, 1.0)
  180. checkI(function () return -3 % 5 end, 2)
  181. checkF(function () return -((2.0^8 + -(-1)) % 8)/2 * 4 - 3 end, -5.0)
  182. checkF(function () return -((2^8 + -(-1)) % 8)//2 * 4 - 3 end, -7.0)
  183. checkI(function () return 0xF0.0 | 0xCC.0 ~ 0xAA & 0xFD end, 0xF4)
  184. checkI(function () return ~(~0xFF0 | 0xFF0) end, 0)
  185. checkI(function () return ~~-1024.0 end, -1024)
  186. checkI(function () return ((100 << 6) << -4) >> 2 end, 100)
  187. -- borders around MAXARG_sBx ((((1 << 17) - 1) >> 1) == 65535)
  188. local sbx = ((1 << "17") - 1) >> 1 -- avoid folding
  189. checkI(function () return 65535 end, sbx)
  190. checkI(function () return -65535 end, -sbx)
  191. checkI(function () return 65536 end, sbx + 1)
  192. checkK(function () return 65537 end, sbx + 2)
  193. checkK(function () return -65536 end, -(sbx + 1))
  194. checkF(function () return 65535.0 end, sbx + 0.0)
  195. checkF(function () return -65535.0 end, -sbx + 0.0)
  196. checkF(function () return 65536.0 end, (sbx + 1.0))
  197. checkK(function () return 65537.0 end, (sbx + 2.0))
  198. checkK(function () return -65536.0 end, -(sbx + 1.0))
  199. -- immediate operands
  200. check(function (x) return x + 1 end, 'ADDI', 'RETURN1')
  201. check(function (x) return 128 + x end, 'ADDI', 'RETURN1')
  202. check(function (x) return x * -127 end, 'MULI', 'RETURN1')
  203. check(function (x) return 20 * x end, 'MULI', 'RETURN1')
  204. check(function (x) return x ^ -2 end, 'POWI', 'RETURN1')
  205. check(function (x) return x / 40 end, 'DIVI', 'RETURN1')
  206. check(function (x) return x // 1 end, 'IDIVI', 'RETURN1')
  207. check(function (x) return x % (100 - 10) end, 'MODI', 'RETURN1')
  208. check(function (x) return 1 << x end, 'SHLI', 'RETURN1')
  209. check(function (x) return x << 2 end, 'SHRI', 'RETURN1')
  210. check(function (x) return x >> 2 end, 'SHRI', 'RETURN1')
  211. check(function (x) return x & 1 end, 'BANDK', 'RETURN1')
  212. check(function (x) return 10 | x end, 'BORK', 'RETURN1')
  213. check(function (x) return -10 ~ x end, 'BXORK', 'RETURN1')
  214. -- no foldings (and immediate operands)
  215. check(function () return -0.0 end, 'LOADF', 'UNM', 'RETURN1')
  216. check(function () return 3/0 end, 'LOADI', 'DIVI', 'RETURN1')
  217. check(function () return 0%0 end, 'LOADI', 'MODI', 'RETURN1')
  218. check(function () return -4//0 end, 'LOADI', 'IDIVI', 'RETURN1')
  219. check(function (x) return x >> 2.0 end, 'LOADF', 'SHR', 'RETURN1')
  220. check(function (x) return x & 2.0 end, 'LOADF', 'BAND', 'RETURN1')
  221. -- basic 'for' loops
  222. check(function () for i = -10, 10.5 do end end,
  223. 'LOADI', 'LOADK', 'LOADI', 'FORPREP1', 'FORLOOP1', 'RETURN0')
  224. check(function () for i = 0xfffffff, 10.0, 1 do end end,
  225. 'LOADK', 'LOADF', 'LOADI', 'FORPREP1', 'FORLOOP1', 'RETURN0')
  226. -- bug in constant folding for 5.1
  227. check(function () return -nil end, 'LOADNIL', 'UNM', 'RETURN1')
  228. check(function ()
  229. local a,b,c
  230. b[c], a = c, b
  231. b[a], a = c, b
  232. a, b = c, a
  233. a = a
  234. end,
  235. 'LOADNIL',
  236. 'MOVE', 'MOVE', 'SETTABLE',
  237. 'MOVE', 'MOVE', 'MOVE', 'SETTABLE',
  238. 'MOVE', 'MOVE', 'MOVE',
  239. -- no code for a = a
  240. 'RETURN0')
  241. -- x == nil , x ~= nil
  242. -- checkequal(function (b) if (a==nil) then a=1 end; if a~=nil then a=1 end end,
  243. -- function () if (a==9) then a=1 end; if a~=9 then a=1 end end)
  244. -- check(function () if a==nil then a='a' end end,
  245. -- 'GETTABUP', 'EQ', 'JMP', 'SETTABUP', 'RETURN')
  246. do -- tests for table access in upvalues
  247. local t
  248. check(function () t.x = t.y end, 'GETTABUP', 'SETTABUP')
  249. check(function (a) t[a()] = t[a()] end,
  250. 'MOVE', 'CALL', 'GETUPVAL', 'MOVE', 'CALL',
  251. 'GETUPVAL', 'GETTABLE', 'SETTABLE')
  252. end
  253. -- de morgan
  254. checkequal(function () local a; if not (a or b) then b=a end end,
  255. function () local a; if (not a and not b) then b=a end end)
  256. checkequal(function (l) local a; return 0 <= a and a <= l end,
  257. function (l) local a; return not (not(a >= 0) or not(a <= l)) end)
  258. -- if-goto optimizations
  259. check(function (a, b, c, d, e)
  260. if a == b then goto l1;
  261. elseif a == c then goto l2;
  262. elseif a == d then goto l2;
  263. else if a == e then goto l3;
  264. else goto l3
  265. end
  266. end
  267. ::l1:: ::l2:: ::l3:: ::l4::
  268. end, 'EQ', 'JMP', 'EQ', 'JMP', 'EQ', 'JMP', 'EQ', 'JMP', 'JMP',
  269. 'CLOSE', 'CLOSE', 'CLOSE', 'CLOSE', 'RETURN0')
  270. checkequal(
  271. function (a) while a < 10 do a = a + 1 end end,
  272. function (a) while true do if not(a < 10) then break end; a = a + 1; end end
  273. )
  274. print 'OK'