Skip to content

Commit 12326f5

Browse files
[RISCV][GISEL] lowerFormalArguments for variadic arguments (#73064)
This is based of the varargs coe in RISCVTargetLowering::LowerFormalArguments.
1 parent 3ccba24 commit 12326f5

File tree

3 files changed

+452
-8
lines changed

3 files changed

+452
-8
lines changed

llvm/lib/Target/RISCV/GISel/RISCVCallLowering.cpp

Lines changed: 82 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -423,18 +423,84 @@ bool RISCVCallLowering::lowerReturn(MachineIRBuilder &MIRBuilder,
423423
return true;
424424
}
425425

426+
static const MCPhysReg ArgGPRs[] = {RISCV::X10, RISCV::X11, RISCV::X12,
427+
RISCV::X13, RISCV::X14, RISCV::X15,
428+
RISCV::X16, RISCV::X17};
429+
430+
/// If there are varargs that were passed in a0-a7, the data in those registers
431+
/// must be copied to the varargs save area on the stack.
432+
void RISCVCallLowering::saveVarArgRegisters(
433+
MachineIRBuilder &MIRBuilder, CallLowering::IncomingValueHandler &Handler,
434+
IncomingValueAssigner &Assigner, CCState &CCInfo) const {
435+
MachineFunction &MF = MIRBuilder.getMF();
436+
const RISCVSubtarget &Subtarget = MF.getSubtarget<RISCVSubtarget>();
437+
unsigned XLenInBytes = Subtarget.getXLen() / 8;
438+
ArrayRef<MCPhysReg> ArgRegs(ArgGPRs);
439+
unsigned Idx = CCInfo.getFirstUnallocated(ArgRegs);
440+
441+
// Offset of the first variable argument from stack pointer, and size of
442+
// the vararg save area. For now, the varargs save area is either zero or
443+
// large enough to hold a0-a7.
444+
int VaArgOffset, VarArgsSaveSize;
445+
// If all registers are allocated, then all varargs must be passed on the
446+
// stack and we don't need to save any argregs.
447+
if (ArgRegs.size() == Idx) {
448+
VaArgOffset = Assigner.StackSize;
449+
VarArgsSaveSize = 0;
450+
} else {
451+
VarArgsSaveSize = XLenInBytes * (ArgRegs.size() - Idx);
452+
VaArgOffset = -VarArgsSaveSize;
453+
}
454+
455+
// Record the frame index of the first variable argument which is a value
456+
// necessary to G_VASTART.
457+
MachineFrameInfo &MFI = MF.getFrameInfo();
458+
int FI = MFI.CreateFixedObject(XLenInBytes, VaArgOffset, true);
459+
RISCVMachineFunctionInfo *RVFI = MF.getInfo<RISCVMachineFunctionInfo>();
460+
RVFI->setVarArgsFrameIndex(FI);
461+
462+
// If saving an odd number of registers then create an extra stack slot to
463+
// ensure that the frame pointer is 2*XLEN-aligned, which in turn ensures
464+
// offsets to even-numbered registered remain 2*XLEN-aligned.
465+
if (Idx % 2) {
466+
MFI.CreateFixedObject(XLenInBytes, VaArgOffset - (int)XLenInBytes, true);
467+
VarArgsSaveSize += XLenInBytes;
468+
}
469+
RVFI->setVarArgsSaveSize(VarArgsSaveSize);
470+
471+
// Copy the integer registers that may have been used for passing varargs
472+
// to the vararg save area.
473+
const LLT p0 = LLT::pointer(MF.getDataLayout().getAllocaAddrSpace(),
474+
Subtarget.getXLen());
475+
const LLT sXLen = LLT::scalar(Subtarget.getXLen());
476+
const MVT XLenVT = Subtarget.getXLenVT();
477+
MachineRegisterInfo &MRI = MF.getRegInfo();
478+
for (unsigned I = Idx; I < ArgRegs.size(); ++I, VaArgOffset += XLenInBytes) {
479+
const Register VReg = MRI.createGenericVirtualRegister(sXLen);
480+
Handler.assignValueToReg(
481+
VReg, ArgRegs[I],
482+
CCValAssign::getReg(I + MF.getFunction().getNumOperands(), XLenVT,
483+
ArgRegs[I], XLenVT, CCValAssign::Full));
484+
FI = MFI.CreateFixedObject(XLenInBytes, VaArgOffset, true);
485+
auto FIN = MIRBuilder.buildFrameIndex(p0, FI);
486+
auto MPO = MachinePointerInfo::getFixedStack(MF, FI);
487+
auto Store =
488+
MIRBuilder.buildStore(VReg, FIN, MPO, inferAlignFromPtrInfo(MF, MPO));
489+
// This was taken from SelectionDAG, but we are not sure why it exists.
490+
// It is being investigated in github.com/llvm/llvm-project/issues/73735.
491+
Store->memoperands()[0]->setValue((Value *)nullptr);
492+
}
493+
}
494+
426495
bool RISCVCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
427496
const Function &F,
428497
ArrayRef<ArrayRef<Register>> VRegs,
429498
FunctionLoweringInfo &FLI) const {
430-
// Early exit if there are no arguments.
431-
if (F.arg_empty())
499+
// Early exit if there are no arguments. varargs are not part of F.args() but
500+
// must be lowered.
501+
if (F.arg_empty() && !F.isVarArg())
432502
return true;
433503

434-
// TODO: Support vararg functions.
435-
if (F.isVarArg())
436-
return false;
437-
438504
const RISCVSubtarget &Subtarget =
439505
MIRBuilder.getMF().getSubtarget<RISCVSubtarget>();
440506
for (auto &Arg : F.args()) {
@@ -467,8 +533,16 @@ bool RISCVCallLowering::lowerFormalArguments(MachineIRBuilder &MIRBuilder,
467533
/*IsRet=*/false);
468534
RISCVFormalArgHandler Handler(MIRBuilder, MF.getRegInfo());
469535

470-
return determineAndHandleAssignments(Handler, Assigner, SplitArgInfos,
471-
MIRBuilder, CC, F.isVarArg());
536+
SmallVector<CCValAssign, 16> ArgLocs;
537+
CCState CCInfo(CC, F.isVarArg(), MIRBuilder.getMF(), ArgLocs, F.getContext());
538+
if (!determineAssignments(Assigner, SplitArgInfos, CCInfo) ||
539+
!handleAssignments(Handler, SplitArgInfos, CCInfo, ArgLocs, MIRBuilder))
540+
return false;
541+
542+
if (F.isVarArg())
543+
saveVarArgRegisters(MIRBuilder, Handler, Assigner, CCInfo);
544+
545+
return true;
472546
}
473547

474548
bool RISCVCallLowering::lowerCall(MachineIRBuilder &MIRBuilder,

llvm/lib/Target/RISCV/GISel/RISCVCallLowering.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,11 @@ class RISCVCallLowering : public CallLowering {
4242
private:
4343
bool lowerReturnVal(MachineIRBuilder &MIRBuilder, const Value *Val,
4444
ArrayRef<Register> VRegs, MachineInstrBuilder &Ret) const;
45+
46+
void saveVarArgRegisters(MachineIRBuilder &MIRBuilder,
47+
CallLowering::IncomingValueHandler &Handler,
48+
IncomingValueAssigner &Assigner,
49+
CCState &CCInfo) const;
4550
};
4651

4752
} // end namespace llvm

0 commit comments

Comments
 (0)