From f37812e906a3abbdb8353e2eb9e8223ff9036b68 Mon Sep 17 00:00:00 2001 From: Jakob Stoklund Olesen Date: Tue, 2 Apr 2013 04:09:02 +0000 Subject: [PATCH] Add support for 64-bit calling convention. This is far from complete, but it is enough to make it possible to write test cases using i64 arguments. Missing features: - Floating point arguments. - Receiving arguments on the stack. - Calls. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@178523 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/Sparc/SparcCallingConv.td | 20 ++++++++ lib/Target/Sparc/SparcISelLowering.cpp | 94 ++++++++++++++++++++++++++++++---- lib/Target/Sparc/SparcISelLowering.h | 12 +++++ test/CodeGen/SPARC/64bit.ll | 7 +++ test/CodeGen/SPARC/ctpop.ll | 2 +- 5 files changed, 123 insertions(+), 12 deletions(-) create mode 100644 test/CodeGen/SPARC/64bit.ll diff --git a/lib/Target/Sparc/SparcCallingConv.td b/lib/Target/Sparc/SparcCallingConv.td index d4712208126..b38ac616dcf 100644 --- a/lib/Target/Sparc/SparcCallingConv.td +++ b/lib/Target/Sparc/SparcCallingConv.td @@ -22,6 +22,14 @@ def RetCC_Sparc32 : CallingConv<[ CCIfType<[f64], CCAssignToReg<[D0, D1]>> ]>; +// Sparc 64-bit C return-value convention. +def RetCC_Sparc64 : CallingConv<[ + CCIfType<[i32], CCPromoteToType>, + CCIfType<[i64], CCAssignToReg<[I0, I1, I2, I3, I4, I5]>>, + CCIfType<[f32], CCAssignToReg<[F0, F1, F2, F3]>>, + CCIfType<[f64], CCAssignToReg<[D0, D1]>> +]>; + // Sparc 32-bit C Calling convention. def CC_Sparc32 : CallingConv<[ //Custom assign SRet to [sp+64]. @@ -34,3 +42,15 @@ def CC_Sparc32 : CallingConv<[ // Alternatively, they are assigned to the stack in 4-byte aligned units. CCAssignToStack<4, 4> ]>; + +// Sparc 64-bit C Calling convention. +def CC_Sparc64 : CallingConv<[ + // All integers are promoted to i64 by the caller. + CCIfType<[i32], CCPromoteToType>, + // Integer arguments get passed in integer registers if there is space. + CCIfType<[i64], CCAssignToReg<[I0, I1, I2, I3, I4, I5]>>, + // FIXME: Floating point arguments. + + // Alternatively, they are assigned to the stack in 8-byte aligned units. + CCAssignToStack<8, 8> +]>; diff --git a/lib/Target/Sparc/SparcISelLowering.cpp b/lib/Target/Sparc/SparcISelLowering.cpp index b345d5f13f3..789ef0c0721 100644 --- a/lib/Target/Sparc/SparcISelLowering.cpp +++ b/lib/Target/Sparc/SparcISelLowering.cpp @@ -93,7 +93,8 @@ SparcTargetLowering::LowerReturn(SDValue Chain, DAG.getTarget(), RVLocs, *DAG.getContext()); // Analize return values. - CCInfo.AnalyzeReturn(Outs, RetCC_Sparc32); + CCInfo.AnalyzeReturn(Outs, Subtarget->is64Bit() ? + RetCC_Sparc64 : RetCC_Sparc32); SDValue Flag; SmallVector RetOps(1, Chain); @@ -138,18 +139,32 @@ SparcTargetLowering::LowerReturn(SDValue Chain, &RetOps[0], RetOps.size()); } -/// LowerFormalArguments - V8 uses a very simple ABI, where all values are +SDValue SparcTargetLowering:: +LowerFormalArguments(SDValue Chain, + CallingConv::ID CallConv, + bool IsVarArg, + const SmallVectorImpl &Ins, + DebugLoc DL, + SelectionDAG &DAG, + SmallVectorImpl &InVals) const { + if (Subtarget->is64Bit()) + return LowerFormalArguments_64(Chain, CallConv, IsVarArg, Ins, + DL, DAG, InVals); + return LowerFormalArguments_32(Chain, CallConv, IsVarArg, Ins, + DL, DAG, InVals); +} + +/// LowerFormalArguments32 - V8 uses a very simple ABI, where all values are /// passed in either one or two GPRs, including FP values. TODO: we should /// pass FP values in FP registers for fastcc functions. -SDValue -SparcTargetLowering::LowerFormalArguments(SDValue Chain, - CallingConv::ID CallConv, bool isVarArg, - const SmallVectorImpl - &Ins, - DebugLoc dl, SelectionDAG &DAG, - SmallVectorImpl &InVals) - const { - +SDValue SparcTargetLowering:: +LowerFormalArguments_32(SDValue Chain, + CallingConv::ID CallConv, + bool isVarArg, + const SmallVectorImpl &Ins, + DebugLoc dl, + SelectionDAG &DAG, + SmallVectorImpl &InVals) const { MachineFunction &MF = DAG.getMachineFunction(); MachineRegisterInfo &RegInfo = MF.getRegInfo(); SparcMachineFunctionInfo *FuncInfo = MF.getInfo(); @@ -341,6 +356,63 @@ SparcTargetLowering::LowerFormalArguments(SDValue Chain, return Chain; } +// Lower formal arguments for the 64 bit ABI. +SDValue SparcTargetLowering:: +LowerFormalArguments_64(SDValue Chain, + CallingConv::ID CallConv, + bool IsVarArg, + const SmallVectorImpl &Ins, + DebugLoc DL, + SelectionDAG &DAG, + SmallVectorImpl &InVals) const { + MachineFunction &MF = DAG.getMachineFunction(); + + // Analyze arguments according to CC_Sparc64. + SmallVector ArgLocs; + CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), + getTargetMachine(), ArgLocs, *DAG.getContext()); + CCInfo.AnalyzeFormalArguments(Ins, CC_Sparc64); + + for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + CCValAssign &VA = ArgLocs[i]; + if (VA.isRegLoc()) { + // This argument is passed in a register. + // All integer register arguments are promoted by the caller to i64. + + // Create a virtual register for the promoted live-in value. + unsigned VReg = MF.addLiveIn(VA.getLocReg(), + getRegClassFor(VA.getLocVT())); + SDValue Arg = DAG.getCopyFromReg(Chain, DL, VReg, VA.getLocVT()); + + // The caller promoted the argument, so insert an Assert?ext SDNode so we + // won't promote the value again in this function. + switch (VA.getLocInfo()) { + case CCValAssign::SExt: + Arg = DAG.getNode(ISD::AssertSext, DL, VA.getLocVT(), Arg, + DAG.getValueType(VA.getValVT())); + break; + case CCValAssign::ZExt: + Arg = DAG.getNode(ISD::AssertZext, DL, VA.getLocVT(), Arg, + DAG.getValueType(VA.getValVT())); + break; + default: + break; + } + + // Truncate the register down to the argument type. + if (VA.isExtInLoc()) + Arg = DAG.getNode(ISD::TRUNCATE, DL, VA.getValVT(), Arg); + + InVals.push_back(Arg); + continue; + } + + // The registers are exhausted. This argument was passed on the stack. + assert(VA.isMemLoc()); + } + return Chain; +} + SDValue SparcTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, SmallVectorImpl &InVals) const { diff --git a/lib/Target/Sparc/SparcISelLowering.h b/lib/Target/Sparc/SparcISelLowering.h index b9937c84606..08e6f211bf3 100644 --- a/lib/Target/Sparc/SparcISelLowering.h +++ b/lib/Target/Sparc/SparcISelLowering.h @@ -77,6 +77,18 @@ namespace llvm { const SmallVectorImpl &Ins, DebugLoc dl, SelectionDAG &DAG, SmallVectorImpl &InVals) const; + SDValue LowerFormalArguments_32(SDValue Chain, + CallingConv::ID CallConv, + bool isVarArg, + const SmallVectorImpl &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl &InVals) const; + SDValue LowerFormalArguments_64(SDValue Chain, + CallingConv::ID CallConv, + bool isVarArg, + const SmallVectorImpl &Ins, + DebugLoc dl, SelectionDAG &DAG, + SmallVectorImpl &InVals) const; virtual SDValue LowerCall(TargetLowering::CallLoweringInfo &CLI, diff --git a/test/CodeGen/SPARC/64bit.ll b/test/CodeGen/SPARC/64bit.ll new file mode 100644 index 00000000000..1efbc15af64 --- /dev/null +++ b/test/CodeGen/SPARC/64bit.ll @@ -0,0 +1,7 @@ +; RUN: llc < %s -march=sparcv9 | FileCheck %s + +; CHECK: ret2: +; CHECK: or %g0, %i1, %i0 +define i64 @ret2(i64 %a, i64 %b) { + ret i64 %b +} diff --git a/test/CodeGen/SPARC/ctpop.ll b/test/CodeGen/SPARC/ctpop.ll index e56f4947b52..916a41496e2 100644 --- a/test/CodeGen/SPARC/ctpop.ll +++ b/test/CodeGen/SPARC/ctpop.ll @@ -1,5 +1,5 @@ ; RUN: llc < %s -march=sparc -mattr=-v9 | not grep popc -; RUN: llc < %s -march=sparcv9 -mattr=v9 | grep popc +; RUN: llc < %s -march=sparc -mattr=+v9 | grep popc declare i32 @llvm.ctpop.i32(i32) -- 2.11.0