code.lua 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484
  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. local 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. local 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. local 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. check(function (a, b)
  333. while a do
  334. if b then break else a = a + 1 end
  335. end
  336. end,
  337. 'TEST', 'JMP', 'TEST', 'JMP', 'JMP', 'CLOSE', 'JMP', 'ADDI', 'MMBINI', 'JMP', 'RETURN0')
  338. check(function ()
  339. do
  340. goto exit -- don't need to close
  341. local x <close> = nil
  342. goto exit -- must close
  343. end
  344. ::exit::
  345. end, 'JMP', 'CLOSE', 'LOADNIL', 'TBC',
  346. 'CLOSE', 'JMP', 'CLOSE', 'RETURN')
  347. checkequal(function () return 6 or true or nil end,
  348. function () return k6 or kTrue or kNil end)
  349. checkequal(function () return 6 and true or nil end,
  350. function () return k6 and kTrue or kNil end)
  351. do -- string constants
  352. local k0 <const> = "00000000000000000000000000000000000000000000000000"
  353. local function f1 ()
  354. local k <const> = k0
  355. return function ()
  356. return function () return k end
  357. end
  358. end
  359. local f2 = f1()
  360. local f3 = f2()
  361. assert(f3() == k0)
  362. checkK(f3, k0)
  363. -- string is not needed by other functions
  364. assert(T.listk(f1)[1] == nil)
  365. assert(T.listk(f2)[1] == nil)
  366. end
  367. do -- check number of available registers
  368. -- 1 register for local + 1 for function + 252 arguments
  369. local source = "local a; return a(" .. string.rep("a, ", 252) .. "a)"
  370. local prog = T.listcode(assert(load(source)))
  371. -- maximum valid register is 254
  372. for i = 1, 254 do
  373. assert(string.find(prog[2 + i], "MOVE%s*" .. i))
  374. end
  375. -- one more argument would need register #255 (but that is reserved)
  376. source = "local a; return a(" .. string.rep("a, ", 253) .. "a)"
  377. local _, msg = load(source)
  378. assert(string.find(msg, "too many registers"))
  379. end
  380. do -- basic check for SETLIST
  381. -- create a list constructor with 50 elements
  382. local source = "local a; return {" .. string.rep("a, ", 50) .. "}"
  383. local func = assert(load(source))
  384. local code = table.concat(T.listcode(func), "\n")
  385. local _, count = string.gsub(code, "SETLIST", "")
  386. -- code uses only 1 SETLIST for the constructor
  387. assert(count == 1)
  388. end
  389. print 'OK'