code.lua 9.7 KB

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