Skip to content

Commit 1e3c798

Browse files
fuad1502tomeksowiBruceForstall
authored
[RISC-V] Contain GT_CALL constant controlExpr to move lower 12 bits to JALR offset (#114728)
* Contain GT_CALL constant controlExpr to move lower 12 bits to JALR offset * Remove duplicate assertion Co-authored-by: Tomasz Sowiński <[email protected]> * Correct typo in comment Co-authored-by: Bruce Forstall <[email protected]> --------- Co-authored-by: Tomasz Sowiński <[email protected]> Co-authored-by: Bruce Forstall <[email protected]>
1 parent ae6a038 commit 1e3c798

File tree

4 files changed

+49
-7
lines changed

4 files changed

+49
-7
lines changed

src/coreclr/jit/codegenriscv64.cpp

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6176,18 +6176,37 @@ void CodeGen::genCallInstruction(GenTreeCall* call)
61766176
// For fast tailcall we have already consumed the target. We ensure in
61776177
// RA that the target was allocated into a volatile register that will
61786178
// not be messed up by epilog sequence.
6179-
if (!call->IsFastTailCall())
6179+
if (!call->IsFastTailCall() && !target->isContainedIntOrIImmed())
61806180
{
61816181
genConsumeReg(target);
61826182
}
61836183

6184+
regNumber targetReg;
6185+
ssize_t jalrOffset = 0;
6186+
6187+
if (target->isContainedIntOrIImmed())
6188+
{
6189+
// Load upper (64-12) bits to a temporary register. Lower 12 bits will be put inside JALR's instruction as
6190+
// offset.
6191+
targetReg = internalRegisters.GetSingle(call);
6192+
ssize_t imm = target->AsIntCon()->IconValue();
6193+
jalrOffset = (imm << (64 - 12)) >> (64 - 12);
6194+
imm -= jalrOffset;
6195+
GetEmitter()->emitLoadImmediate(EA_PTRSIZE, targetReg, imm);
6196+
}
6197+
else
6198+
{
6199+
targetReg = target->GetRegNum();
6200+
}
6201+
61846202
// We have already generated code for gtControlExpr evaluating it into a register.
61856203
// We just need to emit "call reg" in this case.
61866204
//
6187-
assert(genIsValidIntReg(target->GetRegNum()));
6205+
assert(genIsValidIntReg(targetReg));
61886206

61896207
params.callType = EC_INDIR_R;
6190-
params.ireg = target->GetRegNum();
6208+
params.ireg = targetReg;
6209+
params.addr = (jalrOffset == 0) ? nullptr : (void*)jalrOffset; // We use addr to pass offset value
61916210

61926211
genEmitCallWithCurrentGC(params);
61936212
}

src/coreclr/jit/emitriscv64.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1620,7 +1620,7 @@ void emitter::emitIns_Call(const EmitCallParams& params)
16201620
assert(params.callType < EC_COUNT);
16211621
assert((params.callType != EC_FUNC_TOKEN) ||
16221622
(params.ireg == REG_NA && params.xreg == REG_NA && params.xmul == 0 && params.disp == 0));
1623-
assert(params.callType < EC_INDIR_R || params.addr == NULL);
1623+
assert(params.callType < EC_INDIR_R || params.addr == nullptr || isValidSimm12((ssize_t)params.addr));
16241624
assert(params.callType != EC_INDIR_R ||
16251625
(params.ireg < REG_COUNT && params.xreg == REG_NA && params.xmul == 0 && params.disp == 0));
16261626

@@ -1726,7 +1726,7 @@ void emitter::emitIns_Call(const EmitCallParams& params)
17261726

17271727
// INS_OPTS_C: placeholders. 1/2/4-ins:
17281728
// if (callType == EC_INDIR_R)
1729-
// jalr REG_R0/REG_RA, ireg, 0 <---- 1-ins
1729+
// jalr REG_R0/REG_RA, ireg, offset <---- 1-ins
17301730
// else if (callType == EC_FUNC_TOKEN || callType == EC_FUNC_ADDR)
17311731
// if reloc:
17321732
// //pc + offset_38bits # only when reloc.
@@ -1750,6 +1750,12 @@ void emitter::emitIns_Call(const EmitCallParams& params)
17501750
regNumber reg_jalr = params.isJump ? REG_R0 : REG_RA;
17511751
id->idReg4(reg_jalr);
17521752
id->idReg3(params.ireg); // NOTE: for EC_INDIR_R, using idReg3.
1753+
id->idSmallCns(0); // SmallCns will contain JALR's offset.
1754+
if (params.addr != nullptr)
1755+
{
1756+
// If addr is not NULL, it must contain JALR's offset, which is set to the lower 12 bits of address.
1757+
id->idSmallCns((size_t)params.addr);
1758+
}
17531759
assert(params.xreg == REG_NA);
17541760

17551761
id->idCodeSize(4);
@@ -1853,10 +1859,12 @@ unsigned emitter::emitOutputCall(const insGroup* ig, BYTE* dst, instrDesc* id, c
18531859
assert(id->idIns() == INS_jalr);
18541860
if (id->idIsCallRegPtr())
18551861
{ // EC_INDIR_R
1862+
ssize_t offset = id->idSmallCns();
1863+
assert(isValidSimm12(offset));
18561864
code = emitInsCode(id->idIns());
18571865
code |= (code_t)id->idReg4() << 7;
18581866
code |= (code_t)id->idReg3() << 15;
1859-
// the offset default is 0;
1867+
code |= (code_t)offset << 20;
18601868
emitOutput_Instr(dst, code);
18611869
}
18621870
else if (id->idIsReloc())

src/coreclr/jit/lower.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2744,6 +2744,15 @@ GenTree* Lowering::LowerCall(GenTree* node)
27442744

27452745
BlockRange().InsertBefore(call, std::move(controlExprRange));
27462746
call->gtControlExpr = controlExpr;
2747+
2748+
#ifdef TARGET_RISCV64
2749+
// If controlExpr is a constant, we should contain it inside the call so that we can move the lower 12-bits of
2750+
// the value to call instruction's (JALR) offset.
2751+
if (controlExpr->IsCnsIntOrI() && !controlExpr->AsIntCon()->ImmedValNeedsReloc(comp) && !call->IsFastTailCall())
2752+
{
2753+
MakeSrcContained(call, controlExpr);
2754+
}
2755+
#endif // TARGET_RISCV64
27472756
}
27482757

27492758
if (comp->opts.IsCFGEnabled())

src/coreclr/jit/lsrariscv64.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -957,6 +957,12 @@ int LinearScan::BuildCall(GenTreeCall* call)
957957
}
958958
assert(ctrlExprCandidates != RBM_NONE);
959959
}
960+
961+
// In case ctrlExpr is a contained constant, we need a register to store the value.
962+
if (ctrlExpr->isContainedIntOrIImmed())
963+
{
964+
buildInternalIntRegisterDefForNode(call);
965+
}
960966
}
961967
else if (call->IsR2ROrVirtualStubRelativeIndir())
962968
{
@@ -994,7 +1000,7 @@ int LinearScan::BuildCall(GenTreeCall* call)
9941000

9951001
srcCount += BuildCallArgUses(call);
9961002

997-
if (ctrlExpr != nullptr)
1003+
if (ctrlExpr != nullptr && !ctrlExpr->isContainedIntOrIImmed())
9981004
{
9991005
BuildUse(ctrlExpr, ctrlExprCandidates);
10001006
srcCount++;

0 commit comments

Comments
 (0)