References:
CHERI_CCall calling conv:
Defined in .td file, code generated (during build) as MipsGenCallingConv.inc
// llvm/lib/Target/Mips/MipsCallingConv.td
def CC_CHERI_CCall : CallingConv<[
CCIfType<[iFATPTR64, iFATPTR128, iFATPTR256, iFATPTR512], CCAssignToReg<[C1, C2, C3, C4, C5, C6, C7, C8, C9, C10]>>,
CCIfType<[i64], CCAssignToReg<[V0_64]>>,
CCDelegateTo<CC_MipsN>
]>;
def CC_MipsN : CallingConv<[
CCIfType<[i8, i16, i32, i64],
CCIfSubtargetNot<"isLittle()",
CCIfInReg<CCPromoteToUpperBitsInType<i64>>>>,
// All integers (except soft-float integers) are promoted to 64-bit.
CCIfType<[i8, i16, i32], CCIfOrigArgWasNotFloat<CCPromoteToType<i64>>>,
// The only i32's we have left are soft-float arguments.
CCIfSubtarget<"useSoftFloat()", CCIfType<[i32],
CCDelegateTo<CC_MipsN_SoftFloat>>>,
// Integer arguments are passed in integer registers.
CCIfType<[i64], CCAssignToRegWithShadow<[A0_64, A1_64, A2_64, A3_64,
T0_64, T1_64, T2_64, T3_64],
[D12_64, D13_64, D14_64, D15_64,
D16_64, D17_64, D18_64, D19_64]>>,
// f32 arguments are passed in single precision FP registers.
CCIfType<[f32], CCAssignToRegWithShadow<[F12, F13, F14, F15,
F16, F17, F18, F19],
[A0_64, A1_64, A2_64, A3_64,
T0_64, T1_64, T2_64, T3_64]>>,
// f64 arguments are passed in double precision FP registers.
CCIfType<[f64], CCAssignToRegWithShadow<[D12_64, D13_64, D14_64, D15_64,
D16_64, D17_64, D18_64, D19_64],
[A0_64, A1_64, A2_64, A3_64,
T0_64, T1_64, T2_64, T3_64]>>,
// All stack parameter slots become 64-bit doublewords and are 8-byte aligned.
CCIfType<[f32], CCAssignToStack<4, 8>>,
CCIfType<[i64, f64], CCAssignToStack<8, 8>>,
CCIfType<[iFATPTR64, iFATPTR128, iFATPTR256, iFATPTR512], CCAssignToReg<[C3, C4, C5, C6, C7, C8, C9, C10]>>,
CCIfType<[iFATPTR64, iFATPTR128, iFATPTR256, iFATPTR512], CCDelegateTo<CC_MipsCheriCapOnStack>>
]>;
// build/lib/Target/Mips/MipsGenCallingConv.inc
static bool CC_CHERI_CCall(unsigned ValNo, MVT ValVT,
MVT LocVT, CCValAssign::LocInfo LocInfo,
ISD::ArgFlagsTy ArgFlags, CCState &State) {
if (LocVT == MVT::iFATPTR64 ||
LocVT == MVT::iFATPTR128 ||
LocVT == MVT::iFATPTR256 ||
LocVT == MVT::iFATPTR512) {
static const MCPhysReg RegList1[] = {
Mips::C1, Mips::C2, Mips::C3, Mips::C4, Mips::C5, Mips::C6, Mips::C7, Mips::C8, Mips::C9, Mips::C10
};
if (unsigned Reg = State.AllocateReg(RegList1)) {
State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
return false;
}
}
if (LocVT == MVT::i64) {
if (unsigned Reg = State.AllocateReg(Mips::V0_64)) {
State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
return false;
}
}
if (!CC_MipsN(ValNo, ValVT, LocVT, LocInfo, ArgFlags, State))
return false;
return true; // CC didn't match.
}
//
static bool CC_MipsN(unsigned ValNo, MVT ValVT,
MVT LocVT, CCValAssign::LocInfo LocInfo,
ISD::ArgFlagsTy ArgFlags, CCState &State) {
if (LocVT == MVT::i8 ||
LocVT == MVT::i16 ||
LocVT == MVT::i32 ||
LocVT == MVT::i64) {
if (!static_cast<const MipsSubtarget&>(State.getMachineFunction().getSubtarget()).isLittle()) {
if (ArgFlags.isInReg()) {
LocVT = MVT::i64;
if (ArgFlags.isSExt())
LocInfo = CCValAssign::SExtUpper;
else if (ArgFlags.isZExt())
LocInfo = CCValAssign::ZExtUpper;
else
LocInfo = CCValAssign::AExtUpper;
}
}
}
if (LocVT == MVT::i8 ||
LocVT == MVT::i16 ||
LocVT == MVT::i32) {
if (!static_cast<MipsCCState *>(&State)->WasOriginalArgFloat(ValNo)) {
LocVT = MVT::i64;
if (ArgFlags.isSExt())
LocInfo = CCValAssign::SExt;
else if (ArgFlags.isZExt())
LocInfo = CCValAssign::ZExt;
else
LocInfo = CCValAssign::AExt;
}
}
if (static_cast<const MipsSubtarget&>(State.getMachineFunction().getSubtarget()).useSoftFloat()) {
if (LocVT == MVT::i32) {
if (!CC_MipsN_SoftFloat(ValNo, ValVT, LocVT, LocInfo, ArgFlags, State))
return false;
}
}
if (LocVT == MVT::i64) {
static const MCPhysReg RegList1[] = {
Mips::A0_64, Mips::A1_64, Mips::A2_64, Mips::A3_64, Mips::T0_64, Mips::T1_64, Mips::T2_64, Mips::T3_64
};
static const MCPhysReg RegList2[] = {
Mips::D12_64, Mips::D13_64, Mips::D14_64, Mips::D15_64, Mips::D16_64, Mips::D17_64, Mips::D18_64, Mips::D19_64
};
if (unsigned Reg = State.AllocateReg(RegList1, RegList2)) {
State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
return false;
}
}
if (LocVT == MVT::f32) {
static const MCPhysReg RegList3[] = {
Mips::F12, Mips::F13, Mips::F14, Mips::F15, Mips::F16, Mips::F17, Mips::F18, Mips::F19
};
static const MCPhysReg RegList4[] = {
Mips::A0_64, Mips::A1_64, Mips::A2_64, Mips::A3_64, Mips::T0_64, Mips::T1_64, Mips::T2_64, Mips::T3_64
};
if (unsigned Reg = State.AllocateReg(RegList3, RegList4)) {
State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
return false;
}
}
if (LocVT == MVT::f64) {
static const MCPhysReg RegList5[] = {
Mips::D12_64, Mips::D13_64, Mips::D14_64, Mips::D15_64, Mips::D16_64, Mips::D17_64, Mips::D18_64, Mips::D19_64
};
static const MCPhysReg RegList6[] = {
Mips::A0_64, Mips::A1_64, Mips::A2_64, Mips::A3_64, Mips::T0_64, Mips::T1_64, Mips::T2_64, Mips::T3_64
};
if (unsigned Reg = State.AllocateReg(RegList5, RegList6)) {
State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
return false;
}
}
if (LocVT == MVT::f32) {
unsigned Offset7 = State.AllocateStack(4, 8);
State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset7, LocVT, LocInfo));
return false;
}
if (LocVT == MVT::i64 ||
LocVT == MVT::f64) {
unsigned Offset8 = State.AllocateStack(8, 8);
State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset8, LocVT, LocInfo));
return false;
}
if (LocVT == MVT::iFATPTR64 ||
LocVT == MVT::iFATPTR128 ||
LocVT == MVT::iFATPTR256 ||
LocVT == MVT::iFATPTR512) {
static const MCPhysReg RegList9[] = {
Mips::C3, Mips::C4, Mips::C5, Mips::C6, Mips::C7, Mips::C8, Mips::C9, Mips::C10
};
if (unsigned Reg = State.AllocateReg(RegList9)) {
State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
return false;
}
}
if (LocVT == MVT::iFATPTR64 ||
LocVT == MVT::iFATPTR128 ||
LocVT == MVT::iFATPTR256 ||
LocVT == MVT::iFATPTR512) {
if (!CC_MipsCheriCapOnStack(ValNo, ValVT, LocVT, LocInfo, ArgFlags, State))
return false;
}
return true; // CC didn't match.
}
Calling convention is set via setCallingConv()
.
CC_CHERI_CCall
is called in CC_Mips_FixedArg
:
// llvm/lib/Target/Mips/MipsCallingConv.td
def CC_Mips_FixedArg : CallingConv<[
// Mips16 needs special handling on some functions.
CCIf<"State.getCallingConv() != CallingConv::Fast",
CCIfSpecialCallingConv<"Mips16RetHelperConv",
CCDelegateTo<CC_Mips16RetHelper>>>,
CCIf<"State.getCallingConv() == CallingConv::CHERI_CCall",
CCDelegateTo<CC_CHERI_CCall>>,
CCIfByVal<CCDelegateTo<CC_Mips_ByVal>>,
// f128 needs to be handled similarly to f32 and f64 on hard-float. However,
// f128 is not legal and is lowered to i128 which is further lowered to a pair
// of i64's.
// This presents us with a problem for the calling convention since hard-float
// still needs to pass them in FPU registers. We therefore resort to a
// pre-analyze (see PreAnalyzeFormalArgsForF128()) step to pass information on
// whether the argument was originally an f128 into the tablegen-erated code.
//
// f128 should only occur for the N64 ABI where long double is 128-bit. On
// N32, long double is equivalent to double.
CCIfType<[i64],
CCIfSubtargetNot<"useSoftFloat()",
CCIfOrigArgWasF128<CCBitConvertToType<f64>>>>,
CCIfCC<"CallingConv::Fast", CCDelegateTo<CC_Mips_FastCC>>,
CCIfSubtarget<"isABI_O32()", CCDelegateTo<CC_MipsO32_FP>>,
CCDelegateTo<CC_MipsN>
]>;
CC_Mips_FixedArg
is called in CC_Mips
:
// llvm/lib/Target/Mips/MipsCallingConv.td
def CC_Mips : CallingConv<[
CCIfVarArg<CCIfArgIsVarArg<CCDelegateTo<CC_Mips_VarArg>>>,
CCDelegateTo<CC_Mips_FixedArg>
]>;
Now we have call path: CC_Mips
-> CC_Mips_FixedArg
-> CC_CHERI_CCall
. The generated code is MipsGenCallingConv.inc
.
MipsGenCallingConv.inc
is included in
MipsISelLowering.cpp
: calls CC_Mips
, CC_Mips_FixedArg
, RetCC_Mips
;MipsFastISel.cpp
:lib/Target/Mips/CMakeLists.txt
: tablegen(LLVM MipsGenCallingConv.inc -gen-callingconv)
Since FastISel
is not enabled by default, the default implementation of calling convention should be in MipsISelLowering.cpp
.
/////////////////////////////////
// Overview of Call paths:
SelectionDAGISel::LowerArguments() //
--> MipsCallLowering::lowerFormalArguments()
--> MipsTargetLowering::CCAssignFnForCall() --> return CC_Mips_FixedArg;
SelectionDAG/{SelectionDAG.cpp/SelectionDAGBuilder.cpp/LegalizeDAG.cpp/LegalizeIntegerType.cpp}
--> TargetLowering::LowerCallTo() // return pair<SDValue, SDValue>
--> MipsCallLowering::lowerCall() // return
--> MipsTargetLowering::CCAssignFnForCall() --> return CC_Mips_FixedArg;
CCAssignFnForReturn() --> return RetCC_Mips;
MipsTargetLowering::LowerCall() --> CCInfo.AnalyzeCallOperands(Outs, CC_Mips, CLI.getArgs(), ES ? ES->getSymbol() : nullptr);
////////////////////////////////
// Implementations:
// CCAssignFnForCall():
//llvm/lib/Target/Mips/MipsISelLowering.cpp
CCAssignFn *MipsTargetLowering::CCAssignFnForCall() const{
return CC_Mips_FixedArg;
}
// CCAssignFnForReturn():
// LowerCall():
If you could revise
the fundmental principles of
computer system design
to improve security...
... what would you change?