Add randomized register allocation for fuzz testing.

This must be explicitly enabled with: -DLUAJIT_RANDOM_RA
Thanks to Peter Cawley. #1062
This commit is contained in:
Mike Pall 2023-08-30 01:10:52 +02:00
parent 2f6c451ce8
commit 41fb94defa
4 changed files with 58 additions and 7 deletions

View File

@ -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 \
lj_buf.h lj_str.h lj_tab.h lj_frame.h lj_bc.h lj_ctype.h lj_ir.h \
lj_jit.h lj_ircall.h lj_iropt.h lj_mcode.h lj_trace.h lj_dispatch.h \
lj_traceerr.h lj_snap.h lj_asm.h lj_vm.h lj_target.h lj_target_*.h \
lj_emit_*.h lj_asm_*.h
lj_prng.h lj_emit_*.h lj_asm_*.h
lj_assert.o: lj_assert.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h
lj_bc.o: lj_bc.c lj_obj.h lua.h luaconf.h lj_def.h lj_arch.h lj_bc.h \
lj_bcdef.h

View File

@ -29,6 +29,7 @@
#include "lj_dispatch.h"
#include "lj_vm.h"
#include "lj_target.h"
#include "lj_prng.h"
#ifdef LUA_USE_ASSERT
#include <stdio.h>
@ -93,6 +94,12 @@ typedef struct ASMState {
MCode *flagmcp; /* Pending opportunity to merge flag setting ins. */
MCode *realign; /* Realign loop if not NULL. */
#ifdef LUAJIT_RANDOM_RA
/* Randomize register allocation. OK for fuzz testing, not for production. */
uint64_t prngbits;
PRNGState prngstate;
#endif
#ifdef RID_NUM_KREF
intptr_t krefk[RID_NUM_KREF];
#endif
@ -173,6 +180,41 @@ IRFLDEF(FLOFS)
0
};
#ifdef LUAJIT_RANDOM_RA
/* Return a fixed number of random bits from the local PRNG state. */
static uint32_t ra_random_bits(ASMState *as, uint32_t nbits) {
uint64_t b = as->prngbits;
uint32_t res = (1u << nbits) - 1u;
if (b <= res) b = lj_prng_u64(&as->prngstate) | (1ull << 63);
res &= (uint32_t)b;
as->prngbits = b >> nbits;
return res;
}
/* Pick a random register from a register set. */
static Reg rset_pickrandom(ASMState *as, RegSet rs)
{
Reg r = rset_pickbot_(rs);
rs >>= r;
if (rs > 1) { /* More than one bit set? */
while (1) {
/* We need to sample max. the GPR or FPR half of the set. */
uint32_t d = ra_random_bits(as, RSET_BITS-1);
if ((rs >> d) & 1) {
r += d;
break;
}
}
}
return r;
}
#define rset_picktop(rs) rset_pickrandom(as, rs)
#define rset_pickbot(rs) rset_pickrandom(as, rs)
#else
#define rset_picktop(rs) rset_picktop_(rs)
#define rset_pickbot(rs) rset_pickbot_(rs)
#endif
/* -- Target-specific instruction emitter --------------------------------- */
#if LJ_TARGET_X86ORX64
@ -2442,6 +2484,9 @@ void lj_asm_trace(jit_State *J, GCtrace *T)
as->realign = NULL;
as->loopinv = 0;
as->parent = J->parent ? traceref(J, J->parent) : NULL;
#ifdef LUAJIT_RANDOM_RA
(void)lj_prng_u64(&J2G(J)->prng); /* Ensure PRNG step between traces. */
#endif
/* Reserve MCode memory. */
as->mctop = as->mctoporig = lj_mcode_reserve(J, &as->mcbot);
@ -2483,6 +2528,10 @@ void lj_asm_trace(jit_State *J, GCtrace *T)
#endif
as->ir = J->curfinal->ir; /* Use the copied IR. */
as->curins = J->cur.nins = as->orignins;
#ifdef LUAJIT_RANDOM_RA
as->prngstate = J2G(J)->prng; /* Must (re)start from identical state. */
as->prngbits = 0;
#endif
RA_DBG_START();
RA_DBGX((as, "===== STOP ====="));

View File

@ -57,8 +57,10 @@ typedef uint32_t RegSP;
*/
#if LJ_TARGET_PPC || LJ_TARGET_MIPS || LJ_TARGET_ARM64
typedef uint64_t RegSet;
#define RSET_BITS 6
#else
typedef uint32_t RegSet;
#define RSET_BITS 5
#endif
#define RID2RSET(r) (((RegSet)1) << (r))
@ -70,11 +72,11 @@ typedef uint32_t RegSet;
#define rset_clear(rs, r) (rs &= ~RID2RSET(r))
#define rset_exclude(rs, r) (rs & ~RID2RSET(r))
#if LJ_TARGET_PPC || LJ_TARGET_MIPS || LJ_TARGET_ARM64
#define rset_picktop(rs) ((Reg)(__builtin_clzll(rs)^63))
#define rset_pickbot(rs) ((Reg)__builtin_ctzll(rs))
#define rset_picktop_(rs) ((Reg)(__builtin_clzll(rs)^63))
#define rset_pickbot_(rs) ((Reg)__builtin_ctzll(rs))
#else
#define rset_picktop(rs) ((Reg)lj_fls(rs))
#define rset_pickbot(rs) ((Reg)lj_ffs(rs))
#define rset_picktop_(rs) ((Reg)lj_fls(rs))
#define rset_pickbot_(rs) ((Reg)lj_ffs(rs))
#endif
/* -- Register allocation cost -------------------------------------------- */

View File

@ -116,8 +116,8 @@ enum {
#if LJ_64
/* Prefer the low 8 regs of each type to reduce REX prefixes. */
#undef rset_picktop
#define rset_picktop(rs) (lj_fls(lj_bswap(rs)) ^ 0x18)
#undef rset_picktop_
#define rset_picktop_(rs) (lj_fls(lj_bswap(rs)) ^ 0x18)
#endif
/* -- Spill slots --------------------------------------------------------- */