code.lua 13 KB

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