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