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