code.lua 11 KB

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