From b53db4fb321823a8a1f6abc372bdc7c36ef1447f Mon Sep 17 00:00:00 2001 From: Bruno Cardoso Lopes Date: Thu, 19 Mar 2009 02:12:28 +0000 Subject: [PATCH] Added support for Mips O32 Calling Convention git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@67280 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/Mips/MipsCallingConv.td | 17 +-- lib/Target/Mips/MipsISelLowering.cpp | 149 +++++++++++++++++++++++---- 2 files changed, 133 insertions(+), 33 deletions(-) diff --git a/lib/Target/Mips/MipsCallingConv.td b/lib/Target/Mips/MipsCallingConv.td index 034a8d16ca3..01fe92e6b73 100644 --- a/lib/Target/Mips/MipsCallingConv.td +++ b/lib/Target/Mips/MipsCallingConv.td @@ -16,18 +16,9 @@ class CCIfSubtarget: //===----------------------------------------------------------------------===// // Mips O32 Calling Convention //===----------------------------------------------------------------------===// -def CC_MipsO32 : CallingConv<[ - // Promote i8/i16 arguments to i32. - CCIfType<[i8, i16], CCPromoteToType>, - - // The first 4 integer arguments are passed in integer registers. - CCIfType<[i32], CCAssignToReg<[A0, A1, A2, A3]>>, - - // Integer values get stored in stack slots that are 4 bytes in - // size and 4-byte aligned. - CCIfType<[i32], CCAssignToStack<4, 4>> -]>; +// Only the return rules are defined here for O32. The rules for argument +// passing are defined in MipsISelLowering.cpp. def RetCC_MipsO32 : CallingConv<[ // i32 are returned in registers V0, V1 CCIfType<[i32], CCAssignToReg<[V0, V1]>>, @@ -42,6 +33,7 @@ def RetCC_MipsO32 : CallingConv<[ //===----------------------------------------------------------------------===// // Mips EABI Calling Convention //===----------------------------------------------------------------------===// + def CC_MipsEABI : CallingConv<[ // Promote i8/i16 arguments to i32. CCIfType<[i8, i16], CCPromoteToType>, @@ -85,8 +77,7 @@ def RetCC_MipsEABI : CallingConv<[ //===----------------------------------------------------------------------===// def CC_Mips : CallingConv<[ - CCIfSubtarget<"isABI_EABI()", CCDelegateTo>, - CCDelegateTo + CCIfSubtarget<"isABI_EABI()", CCDelegateTo> ]>; def RetCC_Mips : CallingConv<[ diff --git a/lib/Target/Mips/MipsISelLowering.cpp b/lib/Target/Mips/MipsISelLowering.cpp index da328fe3d15..bec6cf7fa26 100644 --- a/lib/Target/Mips/MipsISelLowering.cpp +++ b/lib/Target/Mips/MipsISelLowering.cpp @@ -581,6 +581,85 @@ LowerConstantPool(SDValue Op, SelectionDAG &DAG) #include "MipsGenCallingConv.inc" +//===----------------------------------------------------------------------===// +// TODO: Implement a generic logic using tblgen that can support this. +// Mips O32 ABI rules: +// --- +// i32 - Passed in A0, A1, A2, A3 and stack +// f32 - Only passed in f32 registers if no int reg has been used yet to hold +// an argument. Otherwise, passed in A1, A2, A3 and stack. +// f64 - Only passed in two aliased f32 registers if no int reg has been used +// yet to hold an argument. Otherwise, use A2, A3 and stack. If A1 is +// not used, it must be shadowed. If only A3 is avaiable, shadow it and +// go to stack. +//===----------------------------------------------------------------------===// + +static bool CC_MipsO32(unsigned ValNo, MVT ValVT, + MVT LocVT, CCValAssign::LocInfo LocInfo, + ISD::ArgFlagsTy ArgFlags, CCState &State) { + + static const unsigned IntRegsSize=4, FloatRegsSize=2; + + static const unsigned IntRegs[] = { + Mips::A0, Mips::A1, Mips::A2, Mips::A3 + }; + static const unsigned F32Regs[] = { + Mips::F12, Mips::F14 + }; + static const unsigned F64Regs[] = { + Mips::D6, Mips::D7 + }; + + unsigned Reg=0; + unsigned UnallocIntReg = State.getFirstUnallocated(IntRegs, IntRegsSize); + bool IntRegUsed = (IntRegs[UnallocIntReg] != (unsigned (Mips::A0))); + + // Promote i8 and i16 + if (LocVT == MVT::i8 || LocVT == MVT::i16) { + LocVT = MVT::i32; + if (ArgFlags.isSExt()) + LocInfo = CCValAssign::SExt; + else if (ArgFlags.isZExt()) + LocInfo = CCValAssign::ZExt; + else + LocInfo = CCValAssign::AExt; + } + + if (ValVT == MVT::i32 || (ValVT == MVT::f32 && IntRegUsed)) { + Reg = State.AllocateReg(IntRegs, IntRegsSize); + IntRegUsed = true; + LocVT = MVT::i32; + } + + if (ValVT.isFloatingPoint() && !IntRegUsed) { + if (ValVT == MVT::f32) + Reg = State.AllocateReg(F32Regs, FloatRegsSize); + else + Reg = State.AllocateReg(F64Regs, FloatRegsSize); + } + + if (ValVT == MVT::f64 && IntRegUsed) { + if (UnallocIntReg != IntRegsSize) { + // If we hit register A3 as the first not allocated, we must + // mark it as allocated (shadow) and use the stack instead. + if (IntRegs[UnallocIntReg] != (unsigned (Mips::A3))) + Reg = Mips::A2; + for (;UnallocIntReg < IntRegsSize; ++UnallocIntReg) + State.AllocateReg(UnallocIntReg); + } + LocVT = MVT::i32; + } + + if (!Reg) { + unsigned SizeInBytes = ValVT.getSizeInBits() >> 3; + unsigned Offset = State.AllocateStack(SizeInBytes, SizeInBytes); + State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo)); + } else + State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo)); + + return false; // CC must always match +} + //===----------------------------------------------------------------------===// // CALL Calling Convention Implementation //===----------------------------------------------------------------------===// @@ -611,9 +690,9 @@ LowerCALL(SDValue Op, SelectionDAG &DAG) if (Subtarget->isABI_O32()) { int VTsize = MVT(MVT::i32).getSizeInBits()/8; MFI->CreateFixedObject(VTsize, (VTsize*3)); - } - - CCInfo.AnalyzeCallOperands(TheCall, CC_Mips); + CCInfo.AnalyzeCallOperands(TheCall, CC_MipsO32); + } else + CCInfo.AnalyzeCallOperands(TheCall, CC_Mips); // Get a count of how many bytes are to be pushed on the stack. unsigned NumBytes = CCInfo.getNextStackOffset(); @@ -630,15 +709,28 @@ LowerCALL(SDValue Op, SelectionDAG &DAG) // Walk the register/memloc assignments, inserting copies/loads. for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { + SDValue Arg = TheCall->getArg(i); CCValAssign &VA = ArgLocs[i]; - // Arguments start after the 5 first operands of ISD::CALL - SDValue Arg = TheCall->getArg(i); - // Promote the value if needed. switch (VA.getLocInfo()) { default: assert(0 && "Unknown loc info!"); - case CCValAssign::Full: break; + case CCValAssign::Full: + if (Subtarget->isABI_O32() && VA.isRegLoc()) { + if (VA.getValVT() == MVT::f32 && VA.getLocVT() == MVT::i32) + Arg = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::i32, Arg); + if (VA.getValVT() == MVT::f64 && VA.getLocVT() == MVT::i32) { + Arg = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::i64, Arg); + SDValue Lo = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, Arg, + DAG.getConstant(0, getPointerTy())); + SDValue Hi = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, MVT::i32, Arg, + DAG.getConstant(1, getPointerTy())); + RegsToPass.push_back(std::make_pair(VA.getLocReg(), Lo)); + RegsToPass.push_back(std::make_pair(VA.getLocReg()+1, Hi)); + continue; + } + } + break; case CCValAssign::SExt: Arg = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Arg); break; @@ -657,7 +749,7 @@ LowerCALL(SDValue Op, SelectionDAG &DAG) continue; } - // Register cant get to this point... + // Register can't get to this point... assert(VA.isMemLoc()); // Create the frame index object for this incoming parameter @@ -700,7 +792,6 @@ LowerCALL(SDValue Op, SelectionDAG &DAG) else if (ExternalSymbolSDNode *S = dyn_cast(Callee)) Callee = DAG.getTargetExternalSymbol(S->getSymbol(), getPointerTy()); - // MipsJmpLink = #chain, #target_address, #opt_in_flags... // = Chain, Callee, Reg#1, Reg#2, ... // @@ -824,21 +915,24 @@ LowerFORMAL_ARGUMENTS(SDValue Op, SelectionDAG &DAG) SmallVector ArgLocs; CCState CCInfo(CC, isVarArg, getTargetMachine(), ArgLocs); - CCInfo.AnalyzeFormalArguments(Op.getNode(), CC_Mips); + if (Subtarget->isABI_O32()) + CCInfo.AnalyzeFormalArguments(Op.getNode(), CC_MipsO32); + else + CCInfo.AnalyzeFormalArguments(Op.getNode(), CC_Mips); + SmallVector ArgValues; SDValue StackPtr; unsigned FirstStackArgLoc = (Subtarget->isABI_EABI() ? 0 : 16); for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) { - CCValAssign &VA = ArgLocs[i]; // Arguments stored on registers if (VA.isRegLoc()) { MVT RegVT = VA.getLocVT(); TargetRegisterClass *RC = 0; - + if (RegVT == MVT::i32) RC = Mips::CPURegsRegisterClass; else if (RegVT == MVT::f32) { @@ -857,18 +951,33 @@ LowerFORMAL_ARGUMENTS(SDValue Op, SelectionDAG &DAG) unsigned Reg = AddLiveIn(DAG.getMachineFunction(), VA.getLocReg(), RC); SDValue ArgValue = DAG.getCopyFromReg(Root, dl, Reg, RegVT); - // If this is an 8 or 16-bit value, it is really passed promoted + // If this is an 8 or 16-bit value, it has been passed promoted // to 32 bits. Insert an assert[sz]ext to capture this, then // truncate to the right size. - if (VA.getLocInfo() == CCValAssign::SExt) - ArgValue = DAG.getNode(ISD::AssertSext, dl, RegVT, ArgValue, + if (VA.getLocInfo() != CCValAssign::Full) { + unsigned Opcode; + if (VA.getLocInfo() == CCValAssign::SExt) + Opcode = ISD::AssertSext; + else if (VA.getLocInfo() == CCValAssign::ZExt) + Opcode = ISD::AssertZext; + ArgValue = DAG.getNode(Opcode, dl, RegVT, ArgValue, DAG.getValueType(VA.getValVT())); - else if (VA.getLocInfo() == CCValAssign::ZExt) - ArgValue = DAG.getNode(ISD::AssertZext, dl, RegVT, ArgValue, - DAG.getValueType(VA.getValVT())); - - if (VA.getLocInfo() != CCValAssign::Full) ArgValue = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), ArgValue); + } + + // Handle O32 ABI cases: i32->f32 and (i32,i32)->f64 + if (Subtarget->isABI_O32()) { + if (RegVT == MVT::i32 && VA.getValVT() == MVT::f32) + ArgValue = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::f32, ArgValue); + if (RegVT == MVT::i32 && VA.getValVT() == MVT::f64) { + unsigned Reg2 = AddLiveIn(DAG.getMachineFunction(), + VA.getLocReg()+1, RC); + SDValue ArgValue2 = DAG.getCopyFromReg(Root, dl, Reg2, RegVT); + SDValue Hi = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::f32, ArgValue); + SDValue Lo = DAG.getNode(ISD::BIT_CONVERT, dl, MVT::f32, ArgValue2); + ArgValue = DAG.getNode(ISD::BUILD_PAIR, dl, MVT::f64, Lo, Hi); + } + } ArgValues.push_back(ArgValue);