code.lua 14 KB

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