From 384e5efc0e0b23a0d6c51f991a1b382be0414a8c Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sun, 18 Dec 2005 13:33:06 +0000 Subject: [PATCH] Implement the full V8 ABI for incoming arguments. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@24825 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/Sparc/SparcISelDAGToDAG.cpp | 171 +++++++++++++++++---- lib/Target/Sparc/SparcV8ISelSimple.cpp | 2 +- lib/Target/SparcV8/SparcV8ISelDAGToDAG.cpp | 171 +++++++++++++++++---- lib/Target/SparcV8/SparcV8ISelSimple.cpp | 2 +- 4 files changed, 288 insertions(+), 58 deletions(-) diff --git a/lib/Target/Sparc/SparcISelDAGToDAG.cpp b/lib/Target/Sparc/SparcISelDAGToDAG.cpp index 56dba150439..fe6a2e1c09e 100644 --- a/lib/Target/Sparc/SparcISelDAGToDAG.cpp +++ b/lib/Target/Sparc/SparcISelDAGToDAG.cpp @@ -13,6 +13,7 @@ #include "SparcV8.h" #include "SparcV8TargetMachine.h" +#include "llvm/DerivedTypes.h" #include "llvm/Function.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" @@ -129,56 +130,170 @@ SparcV8TargetLowering::SparcV8TargetLowering(TargetMachine &TM) computeRegisterProperties(); } +/// LowerArguments - 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. std::vector SparcV8TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG) { MachineFunction &MF = DAG.getMachineFunction(); SSARegMap *RegMap = MF.getSSARegMap(); std::vector ArgValues; - static const unsigned GPR[] = { + static const unsigned ArgRegs[] = { V8::I0, V8::I1, V8::I2, V8::I3, V8::I4, V8::I5 }; - unsigned ArgNo = 0; + + const unsigned *CurArgReg = ArgRegs, *ArgRegEnd = ArgRegs+6; + unsigned ArgOffset = 68; + + SDOperand Root = DAG.getRoot(); + std::vector OutChains; + for (Function::arg_iterator I = F.arg_begin(), E = F.arg_end(); I != E; ++I) { MVT::ValueType ObjectVT = getValueType(I->getType()); - assert(ArgNo < 6 && "Only args in regs for now"); switch (ObjectVT) { default: assert(0 && "Unhandled argument type!"); - // TODO: MVT::i64 & FP + // TODO: FP case MVT::i1: case MVT::i8: case MVT::i16: - case MVT::i32: { - unsigned VReg = RegMap->createVirtualRegister(&V8::IntRegsRegClass); - MF.addLiveIn(GPR[ArgNo++], VReg); - SDOperand Arg = DAG.getCopyFromReg(DAG.getRoot(), VReg, MVT::i32); - DAG.setRoot(Arg.getValue(1)); - if (ObjectVT != MVT::i32) { - unsigned AssertOp = I->getType()->isSigned() ? ISD::AssertSext - : ISD::AssertZext; - Arg = DAG.getNode(AssertOp, MVT::i32, Arg, - DAG.getValueType(ObjectVT)); - Arg = DAG.getNode(ISD::TRUNCATE, ObjectVT, Arg); + case MVT::i32: + if (I->use_empty()) { // Argument is dead. + if (CurArgReg < ArgRegEnd) ++CurArgReg; + ArgValues.push_back(DAG.getNode(ISD::UNDEF, ObjectVT)); + } else if (CurArgReg < ArgRegEnd) { // Lives in an incoming GPR + unsigned VReg = RegMap->createVirtualRegister(&V8::IntRegsRegClass); + MF.addLiveIn(*CurArgReg++, VReg); + SDOperand Arg = DAG.getCopyFromReg(Root, VReg, MVT::i32); + if (ObjectVT != MVT::i32) { + unsigned AssertOp = I->getType()->isSigned() ? ISD::AssertSext + : ISD::AssertZext; + Arg = DAG.getNode(AssertOp, MVT::i32, Arg, + DAG.getValueType(ObjectVT)); + Arg = DAG.getNode(ISD::TRUNCATE, ObjectVT, Arg); + } + ArgValues.push_back(Arg); + } else { + int FrameIdx = MF.getFrameInfo()->CreateFixedObject(4, ArgOffset); + SDOperand FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32); + SDOperand Load; + if (ObjectVT == MVT::i32) { + Load = DAG.getLoad(MVT::i32, Root, FIPtr, DAG.getSrcValue(0)); + } else { + unsigned LoadOp = + I->getType()->isSigned() ? ISD::SEXTLOAD : ISD::ZEXTLOAD; + + Load = DAG.getExtLoad(LoadOp, MVT::i32, Root, FIPtr, + DAG.getSrcValue(0), ObjectVT); + } + ArgValues.push_back(Load); } - ArgValues.push_back(Arg); + + ArgOffset += 4; break; - } - case MVT::i64: { - unsigned VRegHi = RegMap->createVirtualRegister(&V8::IntRegsRegClass); - MF.addLiveIn(GPR[ArgNo++], VRegHi); - unsigned VRegLo = RegMap->createVirtualRegister(&V8::IntRegsRegClass); - MF.addLiveIn(GPR[ArgNo++], VRegLo); - SDOperand ArgLo = DAG.getCopyFromReg(DAG.getRoot(), VRegLo, MVT::i32); - SDOperand ArgHi = DAG.getCopyFromReg(ArgLo.getValue(1), VRegHi, MVT::i32); - DAG.setRoot(ArgHi.getValue(1)); - ArgValues.push_back(DAG.getNode(ISD::BUILD_PAIR, MVT::i64, ArgLo, ArgHi)); + case MVT::f32: + if (I->use_empty()) { // Argument is dead. + if (CurArgReg < ArgRegEnd) ++CurArgReg; + ArgValues.push_back(DAG.getNode(ISD::UNDEF, ObjectVT)); + } else if (CurArgReg < ArgRegEnd) { // Lives in an incoming GPR + // FP value is passed in an integer register. + unsigned VReg = RegMap->createVirtualRegister(&V8::IntRegsRegClass); + MF.addLiveIn(*CurArgReg++, VReg); + SDOperand Arg = DAG.getCopyFromReg(Root, VReg, MVT::i32); + + // We use the stack space that is already reserved for this reg. + int FrameIdx = MF.getFrameInfo()->CreateFixedObject(4, ArgOffset); + SDOperand FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32); + + SDOperand SV = DAG.getSrcValue(0); + SDOperand Store = DAG.getNode(ISD::STORE, MVT::Other, Root, + Arg, FIPtr, SV); + ArgValues.push_back(DAG.getLoad(MVT::f32, Store, FIPtr, SV)); + } + ArgOffset += 4; + break; + + case MVT::i64: + case MVT::f64: + if (I->use_empty()) { // Argument is dead. + if (CurArgReg < ArgRegEnd) ++CurArgReg; + if (CurArgReg < ArgRegEnd) ++CurArgReg; + ArgValues.push_back(DAG.getNode(ISD::UNDEF, ObjectVT)); + } else if (CurArgReg == ArgRegEnd && ObjectVT == MVT::f64 && + ((CurArgReg-ArgRegs) & 1) == 0) { + // If this is a double argument and the whole thing lives on the stack, + // and the argument is aligned, load the double straight from the stack. + // We can't do a load in cases like void foo([6ints], int,double), + // because the double wouldn't be aligned! + int FrameIdx = MF.getFrameInfo()->CreateFixedObject(8, ArgOffset); + SDOperand FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32); + ArgValues.push_back(DAG.getLoad(MVT::f64, Root, FIPtr, + DAG.getSrcValue(0))); + } else { + SDOperand HiVal; + if (CurArgReg < ArgRegEnd) { // Lives in an incoming GPR + unsigned VRegHi = RegMap->createVirtualRegister(&V8::IntRegsRegClass); + MF.addLiveIn(*CurArgReg++, VRegHi); + HiVal = DAG.getCopyFromReg(Root, VRegHi, MVT::i32); + } else { + int FrameIdx = MF.getFrameInfo()->CreateFixedObject(4, ArgOffset); + SDOperand FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32); + HiVal = DAG.getLoad(MVT::i32, Root, FIPtr, DAG.getSrcValue(0)); + } + + SDOperand LoVal; + if (CurArgReg < ArgRegEnd) { // Lives in an incoming GPR + unsigned VRegLo = RegMap->createVirtualRegister(&V8::IntRegsRegClass); + MF.addLiveIn(*CurArgReg++, VRegLo); + LoVal = DAG.getCopyFromReg(Root, VRegLo, MVT::i32); + } else { + int FrameIdx = MF.getFrameInfo()->CreateFixedObject(4, ArgOffset+4); + SDOperand FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32); + LoVal = DAG.getLoad(MVT::i32, Root, FIPtr, DAG.getSrcValue(0)); + } + + // Compose the two halves together into an i64 unit. + SDOperand WholeValue = + DAG.getNode(ISD::BUILD_PAIR, MVT::i64, LoVal, HiVal); + + if (ObjectVT == MVT::i64) { + // If we are emitting an i64, this is what we want. + ArgValues.push_back(WholeValue); + } else { + assert(ObjectVT == MVT::f64); + // Otherwise, emit a store to the stack and reload into FPR. + int FrameIdx = MF.getFrameInfo()->CreateStackObject(8, 8); + SDOperand FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32); + SDOperand SV = DAG.getSrcValue(0); + SDOperand Store = DAG.getNode(ISD::STORE, MVT::Other, Root, + WholeValue, FIPtr, SV); + ArgValues.push_back(DAG.getLoad(MVT::f64, Store, FIPtr, SV)); + } + } + ArgOffset += 8; break; - } } } - assert(!F.isVarArg() && "Unimp"); + // Store remaining ArgRegs to the stack if this is a varargs function. + if (F.getFunctionType()->isVarArg()) { + for (; CurArgReg != ArgRegEnd; ++CurArgReg) { + unsigned VReg = RegMap->createVirtualRegister(&V8::IntRegsRegClass); + MF.addLiveIn(*CurArgReg, VReg); + SDOperand Arg = DAG.getCopyFromReg(DAG.getRoot(), VReg, MVT::i32); + + int FrameIdx = MF.getFrameInfo()->CreateFixedObject(4, ArgOffset); + SDOperand FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32); + + OutChains.push_back(DAG.getNode(ISD::STORE, MVT::Other, DAG.getRoot(), + Arg, FIPtr, DAG.getSrcValue(0))); + ArgOffset += 4; + } + } + + if (!OutChains.empty()) + DAG.setRoot(DAG.getNode(ISD::TokenFactor, MVT::Other, OutChains)); // Finally, inform the code generator which regs we return values in. switch (getValueType(F.getReturnType())) { diff --git a/lib/Target/Sparc/SparcV8ISelSimple.cpp b/lib/Target/Sparc/SparcV8ISelSimple.cpp index c7d364d2fc7..f3c0d6e9711 100644 --- a/lib/Target/Sparc/SparcV8ISelSimple.cpp +++ b/lib/Target/Sparc/SparcV8ISelSimple.cpp @@ -367,7 +367,7 @@ void V8ISel::LoadArgumentsToVirtualRegs (Function *LF) { // FIXME: We could avoid storing any args onto the stack that don't // need to be in memory, because they come before the ellipsis in the // parameter list (and thus could never be accessed through va_arg). - if (LF->getFunctionType ()->isVarArg ()) { + if (LF->getFunctionType()->isVarArg()) { for (unsigned i = 0; i < 6; ++i) { int FI = F->getFrameInfo()->CreateFixedObject(4, ArgOffset); assert (IAR != IAREnd diff --git a/lib/Target/SparcV8/SparcV8ISelDAGToDAG.cpp b/lib/Target/SparcV8/SparcV8ISelDAGToDAG.cpp index 56dba150439..fe6a2e1c09e 100644 --- a/lib/Target/SparcV8/SparcV8ISelDAGToDAG.cpp +++ b/lib/Target/SparcV8/SparcV8ISelDAGToDAG.cpp @@ -13,6 +13,7 @@ #include "SparcV8.h" #include "SparcV8TargetMachine.h" +#include "llvm/DerivedTypes.h" #include "llvm/Function.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" @@ -129,56 +130,170 @@ SparcV8TargetLowering::SparcV8TargetLowering(TargetMachine &TM) computeRegisterProperties(); } +/// LowerArguments - 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. std::vector SparcV8TargetLowering::LowerArguments(Function &F, SelectionDAG &DAG) { MachineFunction &MF = DAG.getMachineFunction(); SSARegMap *RegMap = MF.getSSARegMap(); std::vector ArgValues; - static const unsigned GPR[] = { + static const unsigned ArgRegs[] = { V8::I0, V8::I1, V8::I2, V8::I3, V8::I4, V8::I5 }; - unsigned ArgNo = 0; + + const unsigned *CurArgReg = ArgRegs, *ArgRegEnd = ArgRegs+6; + unsigned ArgOffset = 68; + + SDOperand Root = DAG.getRoot(); + std::vector OutChains; + for (Function::arg_iterator I = F.arg_begin(), E = F.arg_end(); I != E; ++I) { MVT::ValueType ObjectVT = getValueType(I->getType()); - assert(ArgNo < 6 && "Only args in regs for now"); switch (ObjectVT) { default: assert(0 && "Unhandled argument type!"); - // TODO: MVT::i64 & FP + // TODO: FP case MVT::i1: case MVT::i8: case MVT::i16: - case MVT::i32: { - unsigned VReg = RegMap->createVirtualRegister(&V8::IntRegsRegClass); - MF.addLiveIn(GPR[ArgNo++], VReg); - SDOperand Arg = DAG.getCopyFromReg(DAG.getRoot(), VReg, MVT::i32); - DAG.setRoot(Arg.getValue(1)); - if (ObjectVT != MVT::i32) { - unsigned AssertOp = I->getType()->isSigned() ? ISD::AssertSext - : ISD::AssertZext; - Arg = DAG.getNode(AssertOp, MVT::i32, Arg, - DAG.getValueType(ObjectVT)); - Arg = DAG.getNode(ISD::TRUNCATE, ObjectVT, Arg); + case MVT::i32: + if (I->use_empty()) { // Argument is dead. + if (CurArgReg < ArgRegEnd) ++CurArgReg; + ArgValues.push_back(DAG.getNode(ISD::UNDEF, ObjectVT)); + } else if (CurArgReg < ArgRegEnd) { // Lives in an incoming GPR + unsigned VReg = RegMap->createVirtualRegister(&V8::IntRegsRegClass); + MF.addLiveIn(*CurArgReg++, VReg); + SDOperand Arg = DAG.getCopyFromReg(Root, VReg, MVT::i32); + if (ObjectVT != MVT::i32) { + unsigned AssertOp = I->getType()->isSigned() ? ISD::AssertSext + : ISD::AssertZext; + Arg = DAG.getNode(AssertOp, MVT::i32, Arg, + DAG.getValueType(ObjectVT)); + Arg = DAG.getNode(ISD::TRUNCATE, ObjectVT, Arg); + } + ArgValues.push_back(Arg); + } else { + int FrameIdx = MF.getFrameInfo()->CreateFixedObject(4, ArgOffset); + SDOperand FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32); + SDOperand Load; + if (ObjectVT == MVT::i32) { + Load = DAG.getLoad(MVT::i32, Root, FIPtr, DAG.getSrcValue(0)); + } else { + unsigned LoadOp = + I->getType()->isSigned() ? ISD::SEXTLOAD : ISD::ZEXTLOAD; + + Load = DAG.getExtLoad(LoadOp, MVT::i32, Root, FIPtr, + DAG.getSrcValue(0), ObjectVT); + } + ArgValues.push_back(Load); } - ArgValues.push_back(Arg); + + ArgOffset += 4; break; - } - case MVT::i64: { - unsigned VRegHi = RegMap->createVirtualRegister(&V8::IntRegsRegClass); - MF.addLiveIn(GPR[ArgNo++], VRegHi); - unsigned VRegLo = RegMap->createVirtualRegister(&V8::IntRegsRegClass); - MF.addLiveIn(GPR[ArgNo++], VRegLo); - SDOperand ArgLo = DAG.getCopyFromReg(DAG.getRoot(), VRegLo, MVT::i32); - SDOperand ArgHi = DAG.getCopyFromReg(ArgLo.getValue(1), VRegHi, MVT::i32); - DAG.setRoot(ArgHi.getValue(1)); - ArgValues.push_back(DAG.getNode(ISD::BUILD_PAIR, MVT::i64, ArgLo, ArgHi)); + case MVT::f32: + if (I->use_empty()) { // Argument is dead. + if (CurArgReg < ArgRegEnd) ++CurArgReg; + ArgValues.push_back(DAG.getNode(ISD::UNDEF, ObjectVT)); + } else if (CurArgReg < ArgRegEnd) { // Lives in an incoming GPR + // FP value is passed in an integer register. + unsigned VReg = RegMap->createVirtualRegister(&V8::IntRegsRegClass); + MF.addLiveIn(*CurArgReg++, VReg); + SDOperand Arg = DAG.getCopyFromReg(Root, VReg, MVT::i32); + + // We use the stack space that is already reserved for this reg. + int FrameIdx = MF.getFrameInfo()->CreateFixedObject(4, ArgOffset); + SDOperand FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32); + + SDOperand SV = DAG.getSrcValue(0); + SDOperand Store = DAG.getNode(ISD::STORE, MVT::Other, Root, + Arg, FIPtr, SV); + ArgValues.push_back(DAG.getLoad(MVT::f32, Store, FIPtr, SV)); + } + ArgOffset += 4; + break; + + case MVT::i64: + case MVT::f64: + if (I->use_empty()) { // Argument is dead. + if (CurArgReg < ArgRegEnd) ++CurArgReg; + if (CurArgReg < ArgRegEnd) ++CurArgReg; + ArgValues.push_back(DAG.getNode(ISD::UNDEF, ObjectVT)); + } else if (CurArgReg == ArgRegEnd && ObjectVT == MVT::f64 && + ((CurArgReg-ArgRegs) & 1) == 0) { + // If this is a double argument and the whole thing lives on the stack, + // and the argument is aligned, load the double straight from the stack. + // We can't do a load in cases like void foo([6ints], int,double), + // because the double wouldn't be aligned! + int FrameIdx = MF.getFrameInfo()->CreateFixedObject(8, ArgOffset); + SDOperand FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32); + ArgValues.push_back(DAG.getLoad(MVT::f64, Root, FIPtr, + DAG.getSrcValue(0))); + } else { + SDOperand HiVal; + if (CurArgReg < ArgRegEnd) { // Lives in an incoming GPR + unsigned VRegHi = RegMap->createVirtualRegister(&V8::IntRegsRegClass); + MF.addLiveIn(*CurArgReg++, VRegHi); + HiVal = DAG.getCopyFromReg(Root, VRegHi, MVT::i32); + } else { + int FrameIdx = MF.getFrameInfo()->CreateFixedObject(4, ArgOffset); + SDOperand FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32); + HiVal = DAG.getLoad(MVT::i32, Root, FIPtr, DAG.getSrcValue(0)); + } + + SDOperand LoVal; + if (CurArgReg < ArgRegEnd) { // Lives in an incoming GPR + unsigned VRegLo = RegMap->createVirtualRegister(&V8::IntRegsRegClass); + MF.addLiveIn(*CurArgReg++, VRegLo); + LoVal = DAG.getCopyFromReg(Root, VRegLo, MVT::i32); + } else { + int FrameIdx = MF.getFrameInfo()->CreateFixedObject(4, ArgOffset+4); + SDOperand FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32); + LoVal = DAG.getLoad(MVT::i32, Root, FIPtr, DAG.getSrcValue(0)); + } + + // Compose the two halves together into an i64 unit. + SDOperand WholeValue = + DAG.getNode(ISD::BUILD_PAIR, MVT::i64, LoVal, HiVal); + + if (ObjectVT == MVT::i64) { + // If we are emitting an i64, this is what we want. + ArgValues.push_back(WholeValue); + } else { + assert(ObjectVT == MVT::f64); + // Otherwise, emit a store to the stack and reload into FPR. + int FrameIdx = MF.getFrameInfo()->CreateStackObject(8, 8); + SDOperand FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32); + SDOperand SV = DAG.getSrcValue(0); + SDOperand Store = DAG.getNode(ISD::STORE, MVT::Other, Root, + WholeValue, FIPtr, SV); + ArgValues.push_back(DAG.getLoad(MVT::f64, Store, FIPtr, SV)); + } + } + ArgOffset += 8; break; - } } } - assert(!F.isVarArg() && "Unimp"); + // Store remaining ArgRegs to the stack if this is a varargs function. + if (F.getFunctionType()->isVarArg()) { + for (; CurArgReg != ArgRegEnd; ++CurArgReg) { + unsigned VReg = RegMap->createVirtualRegister(&V8::IntRegsRegClass); + MF.addLiveIn(*CurArgReg, VReg); + SDOperand Arg = DAG.getCopyFromReg(DAG.getRoot(), VReg, MVT::i32); + + int FrameIdx = MF.getFrameInfo()->CreateFixedObject(4, ArgOffset); + SDOperand FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32); + + OutChains.push_back(DAG.getNode(ISD::STORE, MVT::Other, DAG.getRoot(), + Arg, FIPtr, DAG.getSrcValue(0))); + ArgOffset += 4; + } + } + + if (!OutChains.empty()) + DAG.setRoot(DAG.getNode(ISD::TokenFactor, MVT::Other, OutChains)); // Finally, inform the code generator which regs we return values in. switch (getValueType(F.getReturnType())) { diff --git a/lib/Target/SparcV8/SparcV8ISelSimple.cpp b/lib/Target/SparcV8/SparcV8ISelSimple.cpp index c7d364d2fc7..f3c0d6e9711 100644 --- a/lib/Target/SparcV8/SparcV8ISelSimple.cpp +++ b/lib/Target/SparcV8/SparcV8ISelSimple.cpp @@ -367,7 +367,7 @@ void V8ISel::LoadArgumentsToVirtualRegs (Function *LF) { // FIXME: We could avoid storing any args onto the stack that don't // need to be in memory, because they come before the ellipsis in the // parameter list (and thus could never be accessed through va_arg). - if (LF->getFunctionType ()->isVarArg ()) { + if (LF->getFunctionType()->isVarArg()) { for (unsigned i = 0; i < 6; ++i) { int FI = F->getFrameInfo()->CreateFixedObject(4, ArgOffset); assert (IAR != IAREnd