code.lua 11 KB

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