lua

A copy of the Lua development repository
Log | Files | Refs | README

code.lua (14311B)


      1 -- $Id: testes/code.lua $
      2 -- See Copyright Notice in file all.lua
      3 
      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 
     10 -- to test constant propagation
     11 local k0aux <const> = 0
     12 local k0 <const> = k0aux
     13 local k1 <const> = 1
     14 local k3 <const> = 3
     15 local k6 <const> = k3 + (k3 << k0)
     16 local kFF0 <const> = 0xFF0
     17 local k3_78 <const> = 3.78
     18 local x, k3_78_4 <const> = 10, k3_78 / 4
     19 assert(x == 10)
     20 
     21 local kx <const> = "x"
     22 
     23 local kTrue <const> = true
     24 local kFalse <const> = false
     25 
     26 local kNil <const> = nil
     27 
     28 -- this code gave an error for the code checker
     29 do
     30   local function f (a)
     31   for k,v,w in a do end
     32   end
     33 end
     34 
     35 
     36 -- testing reuse in constant table
     37 local 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
     43 end
     44 
     45 local 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
     53 end
     54 
     55 checkKlist(foo, {3.78/4, -3.78/4, -3.79/4})
     56 
     57 
     58 foo = 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 
     69 checkKlist(foo, {100000, 100000.0, -100000, -100000.0})
     70 
     71 
     72 -- floats x integers
     73 foo = 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
     81 end
     82 
     83 checkKlist(foo, {1, 1.0, 2, 2.0, 0, 0.0})
     84 
     85 
     86 -- testing opcodes
     87 
     88 -- check that 'f' opcodes match '...'
     89 local 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)
     98 end
     99 
    100 
    101 -- check that 'f' opcodes match '...' and that 'f(p) == r'.
    102 local function checkR (f, p, r, ...)
    103   local r1 = f(p)
    104   assert(r == r1 and math.type(r) == math.type(r1))
    105   check(f, ...)
    106 end
    107 
    108 
    109 -- check that 'a' and 'b' has the same opcodes
    110 local 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
    119 end
    120 
    121 
    122 -- some basic instructions
    123 check(function ()   -- function does not create upvalues
    124   (function () end){f()}
    125 end, 'CLOSURE', 'NEWTABLE', 'EXTRAARG', 'GETTABUP', 'CALL',
    126      'SETLIST', 'CALL', 'RETURN0')
    127 
    128 check(function (x)   -- function creates upvalues
    129   (function () return x end){f()}
    130 end, 'CLOSURE', 'NEWTABLE', 'EXTRAARG', 'GETTABUP', 'CALL',
    131      'SETLIST', 'CALL', 'RETURN')
    132 
    133 
    134 -- sequence of LOADNILs
    135 check(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;
    141 end, 'LOADNIL', 'RETURN0')
    142 
    143 check(function ()
    144   local a,b,c,d = 1,1,1,1
    145   d=nil;c=nil;b=nil;a=nil
    146 end, 'LOADI', 'LOADI', 'LOADI', 'LOADI', 'LOADNIL', 'RETURN0')
    147 
    148 do
    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)
    152 end
    153 
    154 
    155 -- single return
    156 check (function (a,b,c) return a end, 'RETURN1')
    157 
    158 
    159 -- infinite loops
    160 check(function () while kTrue do local a = -1 end end,
    161 'LOADI', 'JMP', 'RETURN0')
    162 
    163 check(function () while 1 do local a = -1 end end,
    164 'LOADI', 'JMP', 'RETURN0')
    165 
    166 check(function () repeat local x = 1 until true end,
    167 'LOADI', 'RETURN0')
    168 
    169 
    170 -- concat optimization
    171 check(function (a,b,c,d) return a..b..c..d end,
    172   'MOVE', 'MOVE', 'MOVE', 'MOVE', 'CONCAT', 'RETURN1')
    173 
    174 -- not
    175 check(function () return not not nil end, 'LOADFALSE', 'RETURN1')
    176 check(function () return not not kFalse end, 'LOADFALSE', 'RETURN1')
    177 check(function () return not not true end, 'LOADTRUE', 'RETURN1')
    178 check(function () return not not k3 end, 'LOADTRUE', 'RETURN1')
    179 
    180 -- direct access to locals
    181 check(function ()
    182   local a,b,c,d
    183   a = b*a
    184   c.x, a[b] = -((a + d/b - a[b]) ^ a.x), b
    185 end,
    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
    193 check(function ()
    194   local a,b
    195   local c = kNil
    196   a[kx] = 3.2
    197   a.x = b
    198   a[b] = 'x'
    199 end,
    200   'LOADNIL', 'SETFIELD', 'SETFIELD', 'SETTABLE', 'RETURN0')
    201 
    202 -- "get/set table" with numeric indices
    203 check(function (a)
    204   local k255 <const> = 255
    205   a[1] = a[100]
    206   a[k255] = a[256]
    207   a[256] = 5
    208 end,
    209   'GETI', 'SETI',
    210   'LOADI', 'GETTABLE', 'SETI',
    211   'LOADI', 'SETTABLE',  'RETURN0')
    212 
    213 check(function ()
    214   local a,b
    215   a = a - a
    216   b = a/a
    217   b = 5-4
    218 end,
    219   'LOADNIL', 'SUB', 'MMBIN', 'DIV', 'MMBIN', 'LOADI', 'RETURN0')
    220 
    221 check(function ()
    222   local a,b
    223   a[kTrue] = false
    224 end,
    225   'LOADNIL', 'LOADTRUE', 'SETTABLE', 'RETURN0')
    226 
    227 
    228 -- equalities
    229 checkR(function (a) if a == 1 then return 2 end end, 1, 2,
    230   'EQI', 'JMP', 'LOADI', 'RETURN1')
    231 
    232 checkR(function (a) if -4.0 == a then return 2 end end, -4, 2,
    233   'EQI', 'JMP', 'LOADI', 'RETURN1')
    234 
    235 checkR(function (a) if a == "hi" then return 2 end end, 10, nil,
    236   'EQK', 'JMP', 'LOADI', 'RETURN1')
    237 
    238 checkR(function (a) if a == 10000 then return 2 end end, 1, nil,
    239   'EQK', 'JMP', 'LOADI', 'RETURN1')   -- number too large
    240 
    241 checkR(function (a) if -10000 == a then return 2 end end, -10000, 2,
    242   'EQK', 'JMP', 'LOADI', 'RETURN1')   -- number too large
    243 
    244 -- comparisons
    245 
    246 checkR(function (a) if -10 <= a then return 2 end end, -10, 2,
    247   'GEI', 'JMP', 'LOADI', 'RETURN1')
    248 
    249 checkR(function (a) if 128.0 > a then return 2 end end, 129, nil,
    250   'LTI', 'JMP', 'LOADI', 'RETURN1')
    251 
    252 checkR(function (a) if -127.0 < a then return 2 end end, -127, nil,
    253   'GTI', 'JMP', 'LOADI', 'RETURN1')
    254 
    255 checkR(function (a) if 10 < a then return 2 end end, 11, 2,
    256   'GTI', 'JMP', 'LOADI', 'RETURN1')
    257 
    258 checkR(function (a) if 129 < a then return 2 end end, 130, 2,
    259   'LOADI', 'LT', 'JMP', 'LOADI', 'RETURN1')
    260 
    261 checkR(function (a) if a >= 23.0 then return 2 end end, 25, 2,
    262   'GEI', 'JMP', 'LOADI', 'RETURN1')
    263 
    264 checkR(function (a) if a >= 23.1 then return 2 end end, 0, nil,
    265   'LOADK', 'LE', 'JMP', 'LOADI', 'RETURN1')
    266 
    267 checkR(function (a) if a > 2300.0 then return 2 end end, 0, nil,
    268   'LOADF', 'LT', 'JMP', 'LOADI', 'RETURN1')
    269 
    270 
    271 -- constant folding
    272 local function checkK (func, val)
    273   check(func, 'LOADK', 'RETURN1')
    274   checkKlist(func, {val})
    275   assert(func() == val)
    276 end
    277 
    278 local function checkI (func, val)
    279   check(func, 'LOADI', 'RETURN1')
    280   checkKlist(func, {})
    281   assert(func() == val)
    282 end
    283 
    284 local function checkF (func, val)
    285   check(func, 'LOADF', 'RETURN1')
    286   checkKlist(func, {})
    287   assert(func() == val)
    288 end
    289 
    290 checkF(function () return 0.0 end, 0.0)
    291 checkI(function () return k0 end, 0)
    292 checkI(function () return -k0//1 end, 0)
    293 checkK(function () return 3^-1 end, 1/3)
    294 checkK(function () return (1 + 1)^(50 + 50) end, 2^100)
    295 checkK(function () return (-2)^(31 - 2) end, -0x20000000 + 0.0)
    296 checkF(function () return (-k3^0 + 5) // 3.0 end, 1.0)
    297 checkI(function () return -k3 % 5 end, 2)
    298 checkF(function () return -((2.0^8 + -(-1)) % 8)/2 * 4 - 3 end, -5.0)
    299 checkF(function () return -((2^8 + -(-1)) % 8)//2 * 4 - 3 end, -7.0)
    300 checkI(function () return 0xF0.0 | 0xCC.0 ~ 0xAA & 0xFD end, 0xF4)
    301 checkI(function () return ~(~kFF0 | kFF0) end, 0)
    302 checkI(function () return ~~-1024.0 end, -1024)
    303 checkI(function () return ((100 << k6) << -4) >> 2 end, 100)
    304 
    305 -- borders around MAXARG_sBx ((((1 << 17) - 1) >> 1) == 65535)
    306 local a = 17; local sbx = ((1 << a) - 1) >> 1   -- avoid folding
    307 local border <const> = 65535
    308 checkI(function () return border end, sbx)
    309 checkI(function () return -border end, -sbx)
    310 checkI(function () return border + 1 end, sbx + 1)
    311 checkK(function () return border + 2 end, sbx + 2)
    312 checkK(function () return -(border + 1) end, -(sbx + 1))
    313 
    314 local border <const> = 65535.0
    315 checkF(function () return border end, sbx + 0.0)
    316 checkF(function () return -border end, -sbx + 0.0)
    317 checkF(function () return border + 1 end, (sbx + 1.0))
    318 checkK(function () return border + 2 end, (sbx + 2.0))
    319 checkK(function () return -(border + 1) end, -(sbx + 1.0))
    320 
    321 
    322 -- immediate operands
    323 checkR(function (x) return x + k1 end, 10, 11, 'ADDI', 'MMBINI', 'RETURN1')
    324 checkR(function (x) return x - 127 end, 10, -117, 'ADDI', 'MMBINI', 'RETURN1')
    325 checkR(function (x) return 128 + x end, 0.0, 128.0,
    326          'ADDI', 'MMBINI', 'RETURN1')
    327 checkR(function (x) return x * -127 end, -1.0, 127.0,
    328          'MULK', 'MMBINK', 'RETURN1')
    329 checkR(function (x) return 20 * x end, 2, 40, 'MULK', 'MMBINK', 'RETURN1')
    330 checkR(function (x) return x ^ -2 end, 2, 0.25, 'POWK', 'MMBINK', 'RETURN1')
    331 checkR(function (x) return x / 40 end, 40, 1.0, 'DIVK', 'MMBINK', 'RETURN1')
    332 checkR(function (x) return x // 1 end, 10.0, 10.0,
    333          'IDIVK', 'MMBINK', 'RETURN1')
    334 checkR(function (x) return x % (100 - 10) end, 91, 1,
    335          'MODK', 'MMBINK', 'RETURN1')
    336 checkR(function (x) return k1 << x end, 3, 8, 'SHLI', 'MMBINI', 'RETURN1')
    337 checkR(function (x) return x << 127 end, 10, 0, 'SHRI', 'MMBINI', 'RETURN1')
    338 checkR(function (x) return x << -127 end, 10, 0, 'SHRI', 'MMBINI', 'RETURN1')
    339 checkR(function (x) return x >> 128 end, 8, 0, 'SHRI', 'MMBINI', 'RETURN1')
    340 checkR(function (x) return x >> -127 end, 8, 0, 'SHRI', 'MMBINI', 'RETURN1')
    341 checkR(function (x) return x & 1 end, 9, 1, 'BANDK', 'MMBINK', 'RETURN1')
    342 checkR(function (x) return 10 | x end, 1, 11, 'BORK', 'MMBINK', 'RETURN1')
    343 checkR(function (x) return -10 ~ x end, -1, 9, 'BXORK', 'MMBINK', 'RETURN1')
    344 
    345 -- K operands in arithmetic operations
    346 checkR(function (x) return x + 0.0 end, 1, 1.0, 'ADDK', 'MMBINK', 'RETURN1')
    347 --  check(function (x) return 128 + x end, 'ADDK', 'MMBINK', 'RETURN1')
    348 checkR(function (x) return x * -10000 end, 2, -20000,
    349          'MULK', 'MMBINK', 'RETURN1')
    350 --  check(function (x) return 20 * x end, 'MULK', 'MMBINK', 'RETURN1')
    351 checkR(function (x) return x ^ 0.5 end, 4, 2.0, 'POWK', 'MMBINK', 'RETURN1')
    352 checkR(function (x) return x / 2.0 end, 4, 2.0, 'DIVK', 'MMBINK', 'RETURN1')
    353 checkR(function (x) return x // 10000 end, 10000, 1,
    354          'IDIVK', 'MMBINK', 'RETURN1')
    355 checkR(function (x) return x % (100.0 - 10) end, 91, 1.0,
    356          'MODK', 'MMBINK', 'RETURN1')
    357 
    358 -- no foldings (and immediate operands)
    359 check(function () return -0.0 end, 'LOADF', 'UNM', 'RETURN1')
    360 check(function () return k3/0 end, 'LOADI', 'DIVK', 'MMBINK', 'RETURN1')
    361 check(function () return 0%0 end, 'LOADI', 'MODK', 'MMBINK', 'RETURN1')
    362 check(function () return -4//0 end, 'LOADI', 'IDIVK', 'MMBINK', 'RETURN1')
    363 check(function (x) return x >> 2.0 end, 'LOADF', 'SHR', 'MMBIN', 'RETURN1')
    364 check(function (x) return x << 128 end, 'LOADI', 'SHL', 'MMBIN', 'RETURN1')
    365 check(function (x) return x & 2.0 end, 'LOADF', 'BAND', 'MMBIN', 'RETURN1')
    366 
    367 -- basic 'for' loops
    368 check(function () for i = -10, 10.5 do end end,
    369 'LOADI', 'LOADK', 'LOADI', 'FORPREP', 'FORLOOP', 'RETURN0')
    370 check(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
    374 check(function () return -nil end, 'LOADNIL', 'UNM', 'RETURN1')
    375 
    376 
    377 check(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
    383 end,
    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 
    399 do   -- 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')
    405 end
    406 
    407 -- de morgan
    408 checkequal(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 
    411 checkequal(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 check(function (a, b)
    416         while a do
    417           if b then break else a = a + 1 end
    418         end
    419       end,
    420 'TEST', 'JMP', 'TEST', 'JMP', 'JMP', 'CLOSE', 'JMP', 'ADDI', 'MMBINI', 'JMP', 'RETURN0')
    421 
    422 check(function ()
    423         do
    424           goto exit   -- don't need to close
    425           local x <close> = nil
    426           goto exit   -- must close
    427         end
    428         ::exit::
    429       end, 'JMP', 'CLOSE', 'LOADNIL', 'TBC',
    430            'CLOSE', 'JMP', 'CLOSE', 'RETURN')
    431 
    432 checkequal(function () return 6 or true or nil end,
    433            function () return k6 or kTrue or kNil end)
    434 
    435 checkequal(function () return 6 and true or nil end,
    436            function () return k6 and kTrue or kNil end)
    437 
    438 
    439 do   -- string constants
    440   local k0 <const> = "00000000000000000000000000000000000000000000000000"
    441   local function f1 ()
    442     local k <const> = k0
    443     return function ()
    444              return function () return k end
    445            end
    446   end
    447 
    448   local f2 = f1()
    449   local f3 = f2()
    450   assert(f3() == k0)
    451   checkK(f3, k0)
    452   -- string is not needed by other functions
    453   assert(T.listk(f1)[1] == nil)
    454   assert(T.listk(f2)[1] == nil)
    455 end
    456 
    457 
    458 do   -- check number of available registers
    459   -- 1 register for local + 1 for function + 252 arguments
    460   local source = "local a; return a(" .. string.rep("a, ", 252) .. "a)"
    461   local prog = T.listcode(assert(load(source)))
    462   -- maximum valid register is 254
    463   for i = 1, 254 do
    464     assert(string.find(prog[2 + i], "MOVE%s*" .. i))
    465   end
    466   -- one more argument would need register #255 (but that is reserved)
    467   source = "local a; return a(" .. string.rep("a, ", 253) .. "a)"
    468   local _, msg = load(source)
    469   assert(string.find(msg, "too many registers"))
    470 end
    471 
    472 
    473 do   -- basic check for SETLIST
    474   -- create a list constructor with 50 elements
    475   local source = "local a; return {" .. string.rep("a, ", 50) .. "}"
    476   local func = assert(load(source))
    477   local code = table.concat(T.listcode(func), "\n")
    478   local _, count = string.gsub(code, "SETLIST", "")
    479   -- code uses only 1 SETLIST for the constructor
    480   assert(count == 1)
    481 end
    482 
    483 print 'OK'
    484