diff options
| author | Mike Pall <mike> | 2023-08-30 01:10:52 +0200 |
|---|---|---|
| committer | Mike Pall <mike> | 2023-08-30 01:10:52 +0200 |
| commit | 41fb94defa8f830ce69a8122b03f6ac3216d392a (patch) | |
| tree | 0c66d794528b585a138f4aea5e598f1d0bbcfd4e | |
| parent | 2f6c451ce8db5b5bc88126c9856e15f25fd5beae (diff) | |
| download | luajit-41fb94defa8f830ce69a8122b03f6ac3216d392a.tar.gz luajit-41fb94defa8f830ce69a8122b03f6ac3216d392a.tar.bz2 luajit-41fb94defa8f830ce69a8122b03f6ac3216d392a.zip | |
Add randomized register allocation for fuzz testing.
This must be explicitly enabled with: -DLUAJIT_RANDOM_RA
Thanks to Peter Cawley. #1062
| -rw-r--r-- | src/Makefile.dep | 2 | ||||
| -rw-r--r-- | src/lj_asm.c | 49 | ||||
| -rw-r--r-- | src/lj_target.h | 10 | ||||
| -rw-r--r-- | src/lj_target_x86.h | 4 |
4 files changed, 58 insertions, 7 deletions
diff --git a/src/Makefile.dep b/src/Makefile.dep index 400ef8b0..fda77c83 100644 --- a/src/Makefile.dep +++ b/src/Makefile.dep | |||
| @@ -55,7 +55,7 @@ lj_asm.o: lj_asm.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_gc.h \ | |||
| 55 | lj_buf.h lj_str.h lj_tab.h lj_frame.h lj_bc.h lj_ctype.h lj_ir.h \ | 55 | lj_buf.h lj_str.h lj_tab.h lj_frame.h lj_bc.h lj_ctype.h lj_ir.h \ |
| 56 | lj_jit.h lj_ircall.h lj_iropt.h lj_mcode.h lj_trace.h lj_dispatch.h \ | 56 | lj_jit.h lj_ircall.h lj_iropt.h lj_mcode.h lj_trace.h lj_dispatch.h \ |
| 57 | lj_traceerr.h lj_snap.h lj_asm.h lj_vm.h lj_target.h lj_target_*.h \ | 57 | lj_traceerr.h lj_snap.h lj_asm.h lj_vm.h lj_target.h lj_target_*.h \ |
| 58 | lj_emit_*.h lj_asm_*.h | 58 | lj_prng.h lj_emit_*.h lj_asm_*.h |
| 59 | lj_assert.o: lj_assert.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h | 59 | lj_assert.o: lj_assert.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h |
| 60 | lj_bc.o: lj_bc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_bc.h \ | 60 | lj_bc.o: lj_bc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_bc.h \ |
| 61 | lj_bcdef.h | 61 | lj_bcdef.h |
diff --git a/src/lj_asm.c b/src/lj_asm.c index 71079b30..c02a1b9e 100644 --- a/src/lj_asm.c +++ b/src/lj_asm.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include "lj_dispatch.h" | 29 | #include "lj_dispatch.h" |
| 30 | #include "lj_vm.h" | 30 | #include "lj_vm.h" |
| 31 | #include "lj_target.h" | 31 | #include "lj_target.h" |
| 32 | #include "lj_prng.h" | ||
| 32 | 33 | ||
| 33 | #ifdef LUA_USE_ASSERT | 34 | #ifdef LUA_USE_ASSERT |
| 34 | #include <stdio.h> | 35 | #include <stdio.h> |
| @@ -93,6 +94,12 @@ typedef struct ASMState { | |||
| 93 | MCode *flagmcp; /* Pending opportunity to merge flag setting ins. */ | 94 | MCode *flagmcp; /* Pending opportunity to merge flag setting ins. */ |
| 94 | MCode *realign; /* Realign loop if not NULL. */ | 95 | MCode *realign; /* Realign loop if not NULL. */ |
| 95 | 96 | ||
| 97 | #ifdef LUAJIT_RANDOM_RA | ||
| 98 | /* Randomize register allocation. OK for fuzz testing, not for production. */ | ||
| 99 | uint64_t prngbits; | ||
| 100 | PRNGState prngstate; | ||
| 101 | #endif | ||
| 102 | |||
| 96 | #ifdef RID_NUM_KREF | 103 | #ifdef RID_NUM_KREF |
| 97 | intptr_t krefk[RID_NUM_KREF]; | 104 | intptr_t krefk[RID_NUM_KREF]; |
| 98 | #endif | 105 | #endif |
| @@ -173,6 +180,41 @@ IRFLDEF(FLOFS) | |||
| 173 | 0 | 180 | 0 |
| 174 | }; | 181 | }; |
| 175 | 182 | ||
| 183 | #ifdef LUAJIT_RANDOM_RA | ||
| 184 | /* Return a fixed number of random bits from the local PRNG state. */ | ||
| 185 | static uint32_t ra_random_bits(ASMState *as, uint32_t nbits) { | ||
| 186 | uint64_t b = as->prngbits; | ||
| 187 | uint32_t res = (1u << nbits) - 1u; | ||
| 188 | if (b <= res) b = lj_prng_u64(&as->prngstate) | (1ull << 63); | ||
| 189 | res &= (uint32_t)b; | ||
| 190 | as->prngbits = b >> nbits; | ||
| 191 | return res; | ||
| 192 | } | ||
| 193 | |||
| 194 | /* Pick a random register from a register set. */ | ||
| 195 | static Reg rset_pickrandom(ASMState *as, RegSet rs) | ||
| 196 | { | ||
| 197 | Reg r = rset_pickbot_(rs); | ||
| 198 | rs >>= r; | ||
| 199 | if (rs > 1) { /* More than one bit set? */ | ||
| 200 | while (1) { | ||
| 201 | /* We need to sample max. the GPR or FPR half of the set. */ | ||
| 202 | uint32_t d = ra_random_bits(as, RSET_BITS-1); | ||
| 203 | if ((rs >> d) & 1) { | ||
| 204 | r += d; | ||
| 205 | break; | ||
| 206 | } | ||
| 207 | } | ||
| 208 | } | ||
| 209 | return r; | ||
| 210 | } | ||
| 211 | #define rset_picktop(rs) rset_pickrandom(as, rs) | ||
| 212 | #define rset_pickbot(rs) rset_pickrandom(as, rs) | ||
| 213 | #else | ||
| 214 | #define rset_picktop(rs) rset_picktop_(rs) | ||
| 215 | #define rset_pickbot(rs) rset_pickbot_(rs) | ||
| 216 | #endif | ||
| 217 | |||
| 176 | /* -- Target-specific instruction emitter --------------------------------- */ | 218 | /* -- Target-specific instruction emitter --------------------------------- */ |
| 177 | 219 | ||
| 178 | #if LJ_TARGET_X86ORX64 | 220 | #if LJ_TARGET_X86ORX64 |
| @@ -2442,6 +2484,9 @@ void lj_asm_trace(jit_State *J, GCtrace *T) | |||
| 2442 | as->realign = NULL; | 2484 | as->realign = NULL; |
| 2443 | as->loopinv = 0; | 2485 | as->loopinv = 0; |
| 2444 | as->parent = J->parent ? traceref(J, J->parent) : NULL; | 2486 | as->parent = J->parent ? traceref(J, J->parent) : NULL; |
| 2487 | #ifdef LUAJIT_RANDOM_RA | ||
| 2488 | (void)lj_prng_u64(&J2G(J)->prng); /* Ensure PRNG step between traces. */ | ||
| 2489 | #endif | ||
| 2445 | 2490 | ||
| 2446 | /* Reserve MCode memory. */ | 2491 | /* Reserve MCode memory. */ |
| 2447 | as->mctop = as->mctoporig = lj_mcode_reserve(J, &as->mcbot); | 2492 | as->mctop = as->mctoporig = lj_mcode_reserve(J, &as->mcbot); |
| @@ -2483,6 +2528,10 @@ void lj_asm_trace(jit_State *J, GCtrace *T) | |||
| 2483 | #endif | 2528 | #endif |
| 2484 | as->ir = J->curfinal->ir; /* Use the copied IR. */ | 2529 | as->ir = J->curfinal->ir; /* Use the copied IR. */ |
| 2485 | as->curins = J->cur.nins = as->orignins; | 2530 | as->curins = J->cur.nins = as->orignins; |
| 2531 | #ifdef LUAJIT_RANDOM_RA | ||
| 2532 | as->prngstate = J2G(J)->prng; /* Must (re)start from identical state. */ | ||
| 2533 | as->prngbits = 0; | ||
| 2534 | #endif | ||
| 2486 | 2535 | ||
| 2487 | RA_DBG_START(); | 2536 | RA_DBG_START(); |
| 2488 | RA_DBGX((as, "===== STOP =====")); | 2537 | RA_DBGX((as, "===== STOP =====")); |
diff --git a/src/lj_target.h b/src/lj_target.h index 2f4d21c1..09d19bd9 100644 --- a/src/lj_target.h +++ b/src/lj_target.h | |||
| @@ -57,8 +57,10 @@ typedef uint32_t RegSP; | |||
| 57 | */ | 57 | */ |
| 58 | #if LJ_TARGET_PPC || LJ_TARGET_MIPS || LJ_TARGET_ARM64 | 58 | #if LJ_TARGET_PPC || LJ_TARGET_MIPS || LJ_TARGET_ARM64 |
| 59 | typedef uint64_t RegSet; | 59 | typedef uint64_t RegSet; |
| 60 | #define RSET_BITS 6 | ||
| 60 | #else | 61 | #else |
| 61 | typedef uint32_t RegSet; | 62 | typedef uint32_t RegSet; |
| 63 | #define RSET_BITS 5 | ||
| 62 | #endif | 64 | #endif |
| 63 | 65 | ||
| 64 | #define RID2RSET(r) (((RegSet)1) << (r)) | 66 | #define RID2RSET(r) (((RegSet)1) << (r)) |
| @@ -70,11 +72,11 @@ typedef uint32_t RegSet; | |||
| 70 | #define rset_clear(rs, r) (rs &= ~RID2RSET(r)) | 72 | #define rset_clear(rs, r) (rs &= ~RID2RSET(r)) |
| 71 | #define rset_exclude(rs, r) (rs & ~RID2RSET(r)) | 73 | #define rset_exclude(rs, r) (rs & ~RID2RSET(r)) |
| 72 | #if LJ_TARGET_PPC || LJ_TARGET_MIPS || LJ_TARGET_ARM64 | 74 | #if LJ_TARGET_PPC || LJ_TARGET_MIPS || LJ_TARGET_ARM64 |
| 73 | #define rset_picktop(rs) ((Reg)(__builtin_clzll(rs)^63)) | 75 | #define rset_picktop_(rs) ((Reg)(__builtin_clzll(rs)^63)) |
| 74 | #define rset_pickbot(rs) ((Reg)__builtin_ctzll(rs)) | 76 | #define rset_pickbot_(rs) ((Reg)__builtin_ctzll(rs)) |
| 75 | #else | 77 | #else |
| 76 | #define rset_picktop(rs) ((Reg)lj_fls(rs)) | 78 | #define rset_picktop_(rs) ((Reg)lj_fls(rs)) |
| 77 | #define rset_pickbot(rs) ((Reg)lj_ffs(rs)) | 79 | #define rset_pickbot_(rs) ((Reg)lj_ffs(rs)) |
| 78 | #endif | 80 | #endif |
| 79 | 81 | ||
| 80 | /* -- Register allocation cost -------------------------------------------- */ | 82 | /* -- Register allocation cost -------------------------------------------- */ |
diff --git a/src/lj_target_x86.h b/src/lj_target_x86.h index 7b8d62ad..3482309b 100644 --- a/src/lj_target_x86.h +++ b/src/lj_target_x86.h | |||
| @@ -116,8 +116,8 @@ enum { | |||
| 116 | 116 | ||
| 117 | #if LJ_64 | 117 | #if LJ_64 |
| 118 | /* Prefer the low 8 regs of each type to reduce REX prefixes. */ | 118 | /* Prefer the low 8 regs of each type to reduce REX prefixes. */ |
| 119 | #undef rset_picktop | 119 | #undef rset_picktop_ |
| 120 | #define rset_picktop(rs) (lj_fls(lj_bswap(rs)) ^ 0x18) | 120 | #define rset_picktop_(rs) (lj_fls(lj_bswap(rs)) ^ 0x18) |
| 121 | #endif | 121 | #endif |
| 122 | 122 | ||
| 123 | /* -- Spill slots --------------------------------------------------------- */ | 123 | /* -- Spill slots --------------------------------------------------------- */ |
