code.lua 13 KB

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