Skip to content

Commit dd1dc37

Browse files
[RyuJit/WASM] Register allocator skeleton (#122414)
Force all locals to stack and add an interface for the SP/FP. Implement `GT_LCL_ADDR` / `GT_LCL_FLD` as samples. Next step is to add the stackifier (it'll run before RA and liveness, since it may need to introduce locals and we want to be able to enregister them). After that - parameter homing, and that should bring us to syntactically (if not yet semantically) valid WASM. --------- Co-authored-by: Andy Ayers <[email protected]>
1 parent b1e550c commit dd1dc37

File tree

12 files changed

+507
-180
lines changed

12 files changed

+507
-180
lines changed

src/coreclr/jit/CMakeLists.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ set( JIT_SOURCES
162162
rangecheckcloning.cpp
163163
rationalize.cpp
164164
redundantbranchopts.cpp
165+
regalloc.cpp
165166
regset.cpp
166167
scev.cpp
167168
scopeinfo.cpp
@@ -182,7 +183,6 @@ set( JIT_SOURCES
182183
set ( JIT_NATIVE_TARGET_SOURCES
183184
lsra.cpp
184185
lsrabuild.cpp
185-
regalloc.cpp
186186
regMaskTPOps.cpp
187187
gcdecode.cpp
188188
gcencode.cpp
@@ -385,6 +385,7 @@ set( JIT_HEADERS
385385
rangecheckcloning.h
386386
rationalize.h
387387
regalloc.h
388+
regallocimpl.h
388389
register.h
389390
regset.h
390391
scev.h

src/coreclr/jit/codegeninterface.h

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,42 @@ class CodeGenInterface
254254
m_cgFrameRequired = value;
255255
}
256256

257+
#if !HAS_FIXED_REGISTER_SET
258+
private:
259+
// For targets without a fixed SP/FP, these are the registers with which they are associated.
260+
PhasedVar<regNumber> m_cgStackPointerReg = REG_NA;
261+
PhasedVar<regNumber> m_cgFramePointerReg = REG_NA;
262+
263+
public:
264+
void SetStackPointerReg(regNumber reg)
265+
{
266+
assert(reg != REG_NA);
267+
m_cgStackPointerReg = reg;
268+
}
269+
void SetFramePointerReg(regNumber reg)
270+
{
271+
assert(reg != REG_NA);
272+
m_cgFramePointerReg = reg;
273+
}
274+
regNumber GetStackPointerReg() const
275+
{
276+
return m_cgStackPointerReg;
277+
}
278+
regNumber GetFramePointerReg() const
279+
{
280+
return m_cgFramePointerReg;
281+
}
282+
#else // HAS_FIXED_REGISTER_SET
283+
regNumber GetStackPointerReg() const
284+
{
285+
return REG_SPBASE;
286+
}
287+
regNumber GetFramePointerReg() const
288+
{
289+
return REG_FPBASE;
290+
}
291+
#endif // HAS_FIXED_REGISTER_SET
292+
257293
public:
258294
int genCallerSPtoFPdelta() const;
259295
int genCallerSPtoInitialSPdelta() const;

src/coreclr/jit/codegenwasm.cpp

Lines changed: 56 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@
99
#include "codegen.h"
1010
#include "fgwasm.h"
1111

12+
#ifdef TARGET_64BIT
13+
static const instruction INS_I_const = INS_i64_const;
14+
static const instruction INS_I_add = INS_i64_add;
15+
#else // !TARGET_64BIT
16+
static const instruction INS_I_const = INS_i32_const;
17+
static const instruction INS_I_add = INS_i32_add;
18+
#endif // !TARGET_64BIT
19+
1220
void CodeGen::genMarkLabelsForCodegen()
1321
{
1422
// No work needed here for now.
@@ -268,6 +276,14 @@ void CodeGen::genCodeForTreeNode(GenTree* treeNode)
268276
genCodeForCompare(treeNode->AsOp());
269277
break;
270278

279+
case GT_LCL_ADDR:
280+
genCodeForLclAddr(treeNode->AsLclFld());
281+
break;
282+
283+
case GT_LCL_FLD:
284+
genCodeForLclFld(treeNode->AsLclFld());
285+
break;
286+
271287
case GT_LCL_VAR:
272288
genCodeForLclVar(treeNode->AsLclVar());
273289
break;
@@ -741,6 +757,38 @@ void CodeGen::genCodeForNegNot(GenTreeOp* tree)
741757
genProduceReg(tree);
742758
}
743759

760+
//------------------------------------------------------------------------
761+
// genCodeForLclAddr: Generates the code for GT_LCL_ADDR.
762+
//
763+
// Arguments:
764+
// lclAddrNode - the node.
765+
//
766+
void CodeGen::genCodeForLclAddr(GenTreeLclFld* lclAddrNode)
767+
{
768+
assert(lclAddrNode->OperIs(GT_LCL_ADDR));
769+
770+
GetEmitter()->emitIns_I(INS_local_get, EA_PTRSIZE, WasmRegToIndex(GetFramePointerReg()));
771+
GetEmitter()->emitIns_S(INS_I_const, EA_PTRSIZE, lclAddrNode->GetLclNum(), lclAddrNode->GetLclOffs());
772+
GetEmitter()->emitIns(INS_I_add);
773+
genProduceReg(lclAddrNode);
774+
}
775+
776+
//------------------------------------------------------------------------
777+
// genCodeForLclFld: Produce code for a GT_LCL_FLD node.
778+
//
779+
// Arguments:
780+
// tree - the GT_LCL_FLD node
781+
//
782+
void CodeGen::genCodeForLclFld(GenTreeLclFld* tree)
783+
{
784+
assert(tree->OperIs(GT_LCL_FLD));
785+
LclVarDsc* varDsc = compiler->lvaGetDesc(tree);
786+
787+
GetEmitter()->emitIns_I(INS_local_get, EA_PTRSIZE, WasmRegToIndex(GetFramePointerReg()));
788+
GetEmitter()->emitIns_S(ins_Load(tree->TypeGet()), emitTypeSize(tree), tree->GetLclNum(), tree->GetLclOffs());
789+
genProduceReg(tree);
790+
}
791+
744792
//------------------------------------------------------------------------
745793
// genCodeForLclVar: Produce code for a GT_LCL_VAR node.
746794
//
@@ -759,14 +807,14 @@ void CodeGen::genCodeForLclVar(GenTreeLclVar* tree)
759807
if (!varDsc->lvIsRegCandidate())
760808
{
761809
var_types type = varDsc->GetRegisterType(tree);
762-
// TODO-WASM: actually local.get the frame base local here.
810+
GetEmitter()->emitIns_I(INS_local_get, EA_PTRSIZE, WasmRegToIndex(GetFramePointerReg()));
763811
GetEmitter()->emitIns_S(ins_Load(type), emitTypeSize(tree), tree->GetLclNum(), 0);
764812
genProduceReg(tree);
765813
}
766814
else
767815
{
768816
assert(genIsValidReg(varDsc->GetRegNum()));
769-
unsigned wasmLclIndex = UnpackWasmReg(varDsc->GetRegNum());
817+
unsigned wasmLclIndex = WasmRegToIndex(varDsc->GetRegNum());
770818
GetEmitter()->emitIns_I(INS_local_get, emitTypeSize(tree), wasmLclIndex);
771819
}
772820
}
@@ -785,23 +833,15 @@ void CodeGen::genCodeForStoreLclVar(GenTreeLclVar* tree)
785833
assert(!op1->IsMultiRegNode());
786834
genConsumeRegs(op1);
787835

836+
// We rewrite all stack stores to STOREIND because the address must be first on the operand stack, so here only
837+
// enregistered locals need to be handled.
788838
LclVarDsc* varDsc = compiler->lvaGetDesc(tree);
789839
regNumber targetReg = varDsc->GetRegNum();
840+
assert(genIsValidReg(targetReg) && varDsc->lvIsRegCandidate());
790841

791-
if (!varDsc->lvIsRegCandidate())
792-
{
793-
// TODO-WASM: handle these cases in lower/ra.
794-
// Emit drop for now to simulate the store effect on the wasm stack.
795-
GetEmitter()->emitIns(INS_drop);
796-
genUpdateLife(tree);
797-
}
798-
else
799-
{
800-
assert(genIsValidReg(targetReg));
801-
unsigned wasmLclIndex = UnpackWasmReg(targetReg);
802-
GetEmitter()->emitIns_I(INS_local_set, emitTypeSize(tree), wasmLclIndex);
803-
genUpdateLifeStore(tree, targetReg, varDsc);
804-
}
842+
unsigned wasmLclIndex = WasmRegToIndex(targetReg);
843+
GetEmitter()->emitIns_I(INS_local_set, emitTypeSize(tree), wasmLclIndex);
844+
genUpdateLifeStore(tree, targetReg, varDsc);
805845
}
806846

807847
//------------------------------------------------------------------------

src/coreclr/jit/emitwasm.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ void emitter::emitIns_J(instruction ins, emitAttr attr, cnsval_ssize_t imm, Basi
7373
}
7474

7575
//------------------------------------------------------------------------
76-
// emitIns_S: Emit a memory instruction with a stack-based address mode operand.
76+
// emitIns_S: Emit an instruction with a stack offset immediate.
7777
//
7878
void emitter::emitIns_S(instruction ins, emitAttr attr, int varx, int offs)
7979
{
@@ -498,8 +498,7 @@ void emitter::emitDispIns(
498498

499499
case IF_MEMARG:
500500
{
501-
// TODO-WASM: decide what our strategy for alignment hints is and display these accordingly.
502-
unsigned log2align = emitGetAlignHintLog2(id) + 1;
501+
unsigned log2align = emitGetAlignHintLog2(id);
503502
cnsval_ssize_t offset = emitGetInsSC(id);
504503
printf(" %u %llu", log2align, (uint64_t)offset);
505504
}

src/coreclr/jit/lclvars.cpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4609,7 +4609,14 @@ void Compiler::lvaFixVirtualFrameOffsets()
46094609

46104610
JITDUMP("--- delta bump %d for FP frame\n", delta);
46114611
}
4612-
#endif // !TARGET_LOONGARCH64 || !TARGET_RISCV64
4612+
#elif defined(TARGET_WASM)
4613+
else
4614+
{
4615+
// The FP always points at the bottom of the fixed portion of the frame.
4616+
JITDUMP("--- delta bump %d for FP frame\n", codeGen->genTotalFrameSize());
4617+
delta += codeGen->genTotalFrameSize();
4618+
}
4619+
#endif
46134620

46144621
if (opts.IsOSR())
46154622
{
@@ -6260,7 +6267,7 @@ void Compiler::lvaDumpFrameLocation(unsigned lclNum, int minLength)
62606267
#else
62616268
bool EBPbased;
62626269
offset = lvaFrameAddress(lclNum, &EBPbased);
6263-
baseReg = EBPbased ? REG_FPBASE : REG_SPBASE;
6270+
baseReg = EBPbased ? codeGen->GetFramePointerReg() : codeGen->GetStackPointerReg();
62646271
#endif
62656272

62666273
int printed =

src/coreclr/jit/lower.h

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,7 @@ XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
1717
#include "compiler.h"
1818
#include "phase.h"
1919
#include "sideeffects.h"
20-
21-
#if HAS_FIXED_REGISTER_SET
22-
#include "lsra.h"
23-
#endif
24-
25-
#ifdef TARGET_WASM
26-
#include "regallocwasm.h"
27-
#endif
20+
#include "regallocimpl.h"
2821

2922
class Lowering final : public Phase
3023
{

0 commit comments

Comments
 (0)