The calling convention of CC_CHERI_CCall

References:

CHERI_CCall calling conv:

Definition

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>>
]>;
Tracking CC_CHERI_CCall

Usage

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():

More

Created Sep 12, 2020 // Last Updated Sep 14, 2020

If you could revise
the fundmental principles of
computer system design
to improve security...

... what would you change?