implement a ArgumentLayout class to factor code common to LowerFORMAL_ARGUMENTS and LowerCALL

implement FMDRR
add support for f64 function arguments


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@30754 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Rafael Espindola 2006-10-05 16:48:49 +00:00
parent bc588b8bbf
commit a284584352
3 changed files with 192 additions and 118 deletions

View File

@ -27,8 +27,7 @@
#include "llvm/Target/TargetLowering.h" #include "llvm/Target/TargetLowering.h"
#include "llvm/Support/Debug.h" #include "llvm/Support/Debug.h"
#include <iostream> #include <iostream>
#include <queue> #include <vector>
#include <set>
using namespace llvm; using namespace llvm;
namespace { namespace {
@ -89,7 +88,9 @@ namespace llvm {
FSITOD, FSITOD,
FMRRD FMRRD,
FMDRR
}; };
} }
} }
@ -124,9 +125,87 @@ const char *ARMTargetLowering::getTargetNodeName(unsigned Opcode) const {
case ARMISD::FSITOS: return "ARMISD::FSITOS"; case ARMISD::FSITOS: return "ARMISD::FSITOS";
case ARMISD::FSITOD: return "ARMISD::FSITOD"; case ARMISD::FSITOD: return "ARMISD::FSITOD";
case ARMISD::FMRRD: return "ARMISD::FMRRD"; case ARMISD::FMRRD: return "ARMISD::FMRRD";
case ARMISD::FMDRR: return "ARMISD::FMDRR";
} }
} }
class ArgumentLayout {
std::vector<bool> is_reg;
std::vector<unsigned> pos;
std::vector<MVT::ValueType> types;
public:
ArgumentLayout(std::vector<MVT::ValueType> Types) {
types = Types;
unsigned RegNum = 0;
unsigned StackOffset = 0;
for(std::vector<MVT::ValueType>::iterator I = Types.begin();
I != Types.end();
++I) {
MVT::ValueType VT = *I;
assert(VT == MVT::i32 || VT == MVT::f32 || VT == MVT::f64);
unsigned size = MVT::getSizeInBits(VT)/32;
RegNum = ((RegNum + size - 1) / size) * size;
if (RegNum < 4) {
pos.push_back(RegNum);
is_reg.push_back(true);
RegNum += size;
} else {
unsigned bytes = size * 32/8;
StackOffset = ((StackOffset + bytes - 1) / bytes) * bytes;
pos.push_back(StackOffset);
is_reg.push_back(false);
StackOffset += bytes;
}
}
}
unsigned getRegisterNum(unsigned argNum) {
assert(isRegister(argNum));
return pos[argNum];
}
unsigned getOffset(unsigned argNum) {
assert(isOffset(argNum));
return pos[argNum];
}
unsigned isRegister(unsigned argNum) {
assert(argNum < is_reg.size());
return is_reg[argNum];
}
unsigned isOffset(unsigned argNum) {
return !isRegister(argNum);
}
MVT::ValueType getType(unsigned argNum) {
assert(argNum < types.size());
return types[argNum];
}
unsigned getStackSize(void) {
int last = is_reg.size() - 1;
if (isRegister(last))
return 0;
return getOffset(last) + MVT::getSizeInBits(getType(last))/8;
}
int lastRegArg(void) {
int size = is_reg.size();
int last = 0;
while(last < size && isRegister(last))
last++;
last--;
return last;
}
unsigned lastRegNum(void) {
int l = lastRegArg();
if (l < 0)
return -1;
unsigned r = getRegisterNum(l);
MVT::ValueType t = getType(l);
assert(t == MVT::i32 || t == MVT::f32 || t == MVT::f64);
if (t == MVT::f64)
return r + 1;
return r;
}
};
// This transforms a ISD::CALL node into a // This transforms a ISD::CALL node into a
// callseq_star <- ARMISD:CALL <- callseq_end // callseq_star <- ARMISD:CALL <- callseq_end
// chain // chain
@ -139,59 +218,37 @@ static SDOperand LowerCALL(SDOperand Op, SelectionDAG &DAG) {
assert(isTailCall == false && "tail call not supported"); assert(isTailCall == false && "tail call not supported");
SDOperand Callee = Op.getOperand(4); SDOperand Callee = Op.getOperand(4);
unsigned NumOps = (Op.getNumOperands() - 5) / 2; unsigned NumOps = (Op.getNumOperands() - 5) / 2;
// Count how many bytes are to be pushed on the stack.
unsigned NumBytes = 0;
// Add up all the space actually used.
for (unsigned i = 4; i < NumOps; ++i)
NumBytes += MVT::getSizeInBits(Op.getOperand(5+2*i).getValueType())/8;
// Adjust the stack pointer for the new arguments...
// These operations are automatically eliminated by the prolog/epilog pass
Chain = DAG.getCALLSEQ_START(Chain,
DAG.getConstant(NumBytes, MVT::i32));
SDOperand StackPtr = DAG.getRegister(ARM::R13, MVT::i32); SDOperand StackPtr = DAG.getRegister(ARM::R13, MVT::i32);
static const unsigned regs[] = {
static const unsigned int num_regs = 4;
static const unsigned regs[num_regs] = {
ARM::R0, ARM::R1, ARM::R2, ARM::R3 ARM::R0, ARM::R1, ARM::R2, ARM::R3
}; };
std::vector<std::pair<unsigned, SDOperand> > RegsToPass; std::vector<MVT::ValueType> Types;
std::vector<SDOperand> MemOpChains; for (unsigned i = 0; i < NumOps; ++i) {
MVT::ValueType VT = Op.getOperand(5+2*i).getValueType();
Types.push_back(VT);
}
ArgumentLayout Layout(Types);
for (unsigned i = 0; i != NumOps; ++i) { unsigned NumBytes = Layout.getStackSize();
SDOperand Arg = Op.getOperand(5+2*i);
assert(Arg.getValueType() == MVT::i32); Chain = DAG.getCALLSEQ_START(Chain,
if (i < num_regs) DAG.getConstant(NumBytes, MVT::i32));
RegsToPass.push_back(std::make_pair(regs[i], Arg));
else { //Build a sequence of stores
unsigned ArgOffset = (i - num_regs) * 4; std::vector<SDOperand> MemOpChains;
SDOperand PtrOff = DAG.getConstant(ArgOffset, StackPtr.getValueType()); for (unsigned i = Layout.lastRegArg() + 1; i < NumOps; ++i) {
PtrOff = DAG.getNode(ISD::ADD, MVT::i32, StackPtr, PtrOff); SDOperand Arg = Op.getOperand(5+2*i);
MemOpChains.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain, unsigned ArgOffset = Layout.getOffset(i);
Arg, PtrOff, DAG.getSrcValue(NULL))); SDOperand PtrOff = DAG.getConstant(ArgOffset, StackPtr.getValueType());
} PtrOff = DAG.getNode(ISD::ADD, MVT::i32, StackPtr, PtrOff);
MemOpChains.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain,
Arg, PtrOff, DAG.getSrcValue(NULL)));
} }
if (!MemOpChains.empty()) if (!MemOpChains.empty())
Chain = DAG.getNode(ISD::TokenFactor, MVT::Other, Chain = DAG.getNode(ISD::TokenFactor, MVT::Other,
&MemOpChains[0], MemOpChains.size()); &MemOpChains[0], MemOpChains.size());
// Build a sequence of copy-to-reg nodes chained together with token chain
// and flag operands which copy the outgoing args into the appropriate regs.
SDOperand InFlag;
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
Chain = DAG.getCopyToReg(Chain, RegsToPass[i].first, RegsToPass[i].second,
InFlag);
InFlag = Chain.getValue(1);
}
std::vector<MVT::ValueType> NodeTys;
NodeTys.push_back(MVT::Other); // Returns a chain
NodeTys.push_back(MVT::Flag); // Returns a flag for retval copy to use.
// If the callee is a GlobalAddress/ExternalSymbol node (quite common, every // If the callee is a GlobalAddress/ExternalSymbol node (quite common, every
// direct call is) turn it into a TargetGlobalAddress/TargetExternalSymbol // direct call is) turn it into a TargetGlobalAddress/TargetExternalSymbol
// node so that legalize doesn't hack it. // node so that legalize doesn't hack it.
@ -204,11 +261,25 @@ static SDOperand LowerCALL(SDOperand Op, SelectionDAG &DAG) {
Ops.push_back(Chain); Ops.push_back(Chain);
Ops.push_back(Callee); Ops.push_back(Callee);
// Add argument registers to the end of the list so that they are known live // Build a sequence of copy-to-reg nodes chained together with token chain
// into the call. // and flag operands which copy the outgoing args into the appropriate regs.
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) SDOperand InFlag;
Ops.push_back(DAG.getRegister(RegsToPass[i].first, for (unsigned i = 0, e = Layout.lastRegArg(); i <= e; ++i) {
RegsToPass[i].second.getValueType())); SDOperand Arg = Op.getOperand(5+2*i);
unsigned Reg = regs[Layout.getRegisterNum(i)];
assert(Layout.getType(i) == Arg.getValueType());
assert(Layout.getType(i) == MVT::i32);
Chain = DAG.getCopyToReg(Chain, Reg, Arg, InFlag);
InFlag = Chain.getValue(1);
// Add argument register to the end of the list so that it is known live
// into the call.
Ops.push_back(DAG.getRegister(Reg, Arg.getValueType()));
}
std::vector<MVT::ValueType> NodeTys;
NodeTys.push_back(MVT::Other); // Returns a chain
NodeTys.push_back(MVT::Flag); // Returns a flag for retval copy to use.
unsigned CallOpc = ARMISD::CALL; unsigned CallOpc = ARMISD::CALL;
if (InFlag.Val) if (InFlag.Val)
@ -295,44 +366,6 @@ static SDOperand LowerRET(SDOperand Op, SelectionDAG &DAG) {
return DAG.getNode(ARMISD::RET_FLAG, MVT::Other, Copy, Copy.getValue(1)); return DAG.getNode(ARMISD::RET_FLAG, MVT::Other, Copy, Copy.getValue(1));
} }
static SDOperand LowerFORMAL_ARGUMENT(SDOperand Op, SelectionDAG &DAG,
unsigned *vRegs,
unsigned ArgNo) {
MachineFunction &MF = DAG.getMachineFunction();
MVT::ValueType ObjectVT = Op.getValue(ArgNo).getValueType();
assert (ObjectVT == MVT::i32);
SDOperand Root = Op.getOperand(0);
SSARegMap *RegMap = MF.getSSARegMap();
unsigned num_regs = 4;
static const unsigned REGS[] = {
ARM::R0, ARM::R1, ARM::R2, ARM::R3
};
if(ArgNo < num_regs) {
unsigned VReg = RegMap->createVirtualRegister(&ARM::IntRegsRegClass);
MF.addLiveIn(REGS[ArgNo], VReg);
vRegs[ArgNo] = VReg;
return DAG.getCopyFromReg(Root, VReg, MVT::i32);
} else {
// If the argument is actually used, emit a load from the right stack
// slot.
if (!Op.Val->hasNUsesOfValue(0, ArgNo)) {
unsigned ArgOffset = (ArgNo - num_regs) * 4;
MachineFrameInfo *MFI = MF.getFrameInfo();
unsigned ObjSize = MVT::getSizeInBits(ObjectVT)/8;
int FI = MFI->CreateFixedObject(ObjSize, ArgOffset);
SDOperand FIN = DAG.getFrameIndex(FI, MVT::i32);
return DAG.getLoad(ObjectVT, Root, FIN,
DAG.getSrcValue(NULL));
} else {
// Don't emit a dead load.
return DAG.getNode(ISD::UNDEF, ObjectVT);
}
}
}
static SDOperand LowerConstantPool(SDOperand Op, SelectionDAG &DAG) { static SDOperand LowerConstantPool(SDOperand Op, SelectionDAG &DAG) {
MVT::ValueType PtrVT = Op.getValueType(); MVT::ValueType PtrVT = Op.getValueType();
ConstantPoolSDNode *CP = cast<ConstantPoolSDNode>(Op); ConstantPoolSDNode *CP = cast<ConstantPoolSDNode>(Op);
@ -363,45 +396,75 @@ static SDOperand LowerVASTART(SDOperand Op, SelectionDAG &DAG,
static SDOperand LowerFORMAL_ARGUMENTS(SDOperand Op, SelectionDAG &DAG, static SDOperand LowerFORMAL_ARGUMENTS(SDOperand Op, SelectionDAG &DAG,
int &VarArgsFrameIndex) { int &VarArgsFrameIndex) {
MachineFunction &MF = DAG.getMachineFunction();
MachineFrameInfo *MFI = MF.getFrameInfo();
SSARegMap *RegMap = MF.getSSARegMap();
unsigned NumArgs = Op.Val->getNumValues()-1;
SDOperand Root = Op.getOperand(0);
bool isVarArg = cast<ConstantSDNode>(Op.getOperand(2))->getValue() != 0;
static const unsigned REGS[] = {
ARM::R0, ARM::R1, ARM::R2, ARM::R3
};
std::vector<MVT::ValueType> Types(Op.Val->value_begin(), Op.Val->value_end() - 1);
ArgumentLayout Layout(Types);
std::vector<SDOperand> ArgValues; std::vector<SDOperand> ArgValues;
SDOperand Root = Op.getOperand(0);
unsigned VRegs[4];
unsigned NumArgs = Op.Val->getNumValues()-1;
for (unsigned ArgNo = 0; ArgNo < NumArgs; ++ArgNo) { for (unsigned ArgNo = 0; ArgNo < NumArgs; ++ArgNo) {
SDOperand ArgVal = LowerFORMAL_ARGUMENT(Op, DAG, VRegs, ArgNo); MVT::ValueType VT = Types[ArgNo];
ArgValues.push_back(ArgVal); SDOperand Value;
if (Layout.isRegister(ArgNo)) {
assert(VT == MVT::i32 || VT == MVT::f32 || VT == MVT::f64);
unsigned RegNum = Layout.getRegisterNum(ArgNo);
unsigned Reg1 = REGS[RegNum];
unsigned VReg1 = RegMap->createVirtualRegister(&ARM::IntRegsRegClass);
SDOperand Value1 = DAG.getCopyFromReg(Root, VReg1, MVT::i32);
MF.addLiveIn(Reg1, VReg1);
if (VT == MVT::f64) {
unsigned Reg2 = REGS[RegNum + 1];
unsigned VReg2 = RegMap->createVirtualRegister(&ARM::IntRegsRegClass);
SDOperand Value2 = DAG.getCopyFromReg(Root, VReg2, MVT::i32);
MF.addLiveIn(Reg2, VReg2);
Value = DAG.getNode(ARMISD::FMDRR, MVT::f64, Value1, Value2);
} else {
Value = Value1;
if (VT == MVT::f32)
Value = DAG.getNode(ISD::BIT_CONVERT, VT, Value);
}
} else {
// If the argument is actually used, emit a load from the right stack
// slot.
if (!Op.Val->hasNUsesOfValue(0, ArgNo)) {
unsigned Offset = Layout.getOffset(ArgNo);
unsigned Size = MVT::getSizeInBits(VT)/8;
int FI = MFI->CreateFixedObject(Size, Offset);
SDOperand FIN = DAG.getFrameIndex(FI, VT);
Value = DAG.getLoad(VT, Root, FIN, DAG.getSrcValue(NULL));
} else {
Value = DAG.getNode(ISD::UNDEF, VT);
}
}
ArgValues.push_back(Value);
} }
bool isVarArg = cast<ConstantSDNode>(Op.getOperand(2))->getValue() != 0; unsigned NextRegNum = Layout.lastRegNum() + 1;
if (isVarArg) { if (isVarArg) {
MachineFunction &MF = DAG.getMachineFunction(); //If this function is vararg we must store the remaing
SSARegMap *RegMap = MF.getSSARegMap(); //registers so that they can be acessed with va_start
MachineFrameInfo *MFI = MF.getFrameInfo();
VarArgsFrameIndex = MFI->CreateFixedObject(MVT::getSizeInBits(MVT::i32)/8, VarArgsFrameIndex = MFI->CreateFixedObject(MVT::getSizeInBits(MVT::i32)/8,
-16 + NumArgs * 4); -16 + NextRegNum * 4);
static const unsigned REGS[] = {
ARM::R0, ARM::R1, ARM::R2, ARM::R3
};
// If this function is vararg, store r0-r3 to their spots on the stack
// so that they may be loaded by deferencing the result of va_next.
SmallVector<SDOperand, 4> MemOps; SmallVector<SDOperand, 4> MemOps;
for (unsigned ArgNo = 0; ArgNo < 4; ++ArgNo) { for (unsigned RegNo = NextRegNum; RegNo < 4; ++RegNo) {
int ArgOffset = - (4 - ArgNo) * 4; int RegOffset = - (4 - RegNo) * 4;
int FI = MFI->CreateFixedObject(MVT::getSizeInBits(MVT::i32)/8, int FI = MFI->CreateFixedObject(MVT::getSizeInBits(MVT::i32)/8,
ArgOffset); RegOffset);
SDOperand FIN = DAG.getFrameIndex(FI, MVT::i32); SDOperand FIN = DAG.getFrameIndex(FI, MVT::i32);
unsigned VReg; unsigned VReg = RegMap->createVirtualRegister(&ARM::IntRegsRegClass);
if (ArgNo < NumArgs) MF.addLiveIn(REGS[RegNo], VReg);
VReg = VRegs[ArgNo];
else
VReg = RegMap->createVirtualRegister(&ARM::IntRegsRegClass);
if (ArgNo >= NumArgs)
MF.addLiveIn(REGS[ArgNo], VReg);
SDOperand Val = DAG.getCopyFromReg(Root, VReg, MVT::i32); SDOperand Val = DAG.getCopyFromReg(Root, VReg, MVT::i32);
SDOperand Store = DAG.getNode(ISD::STORE, MVT::Other, Val.getValue(1), SDOperand Store = DAG.getNode(ISD::STORE, MVT::Other, Val.getValue(1),

View File

@ -80,6 +80,9 @@ def armfsitod : SDNode<"ARMISD::FSITOD", SDTUnaryOp>;
def SDTarmfmrrd : SDTypeProfile<0, 3, [SDTCisInt<0>, SDTCisInt<1>, SDTCisFP<2>]>; def SDTarmfmrrd : SDTypeProfile<0, 3, [SDTCisInt<0>, SDTCisInt<1>, SDTCisFP<2>]>;
def armfmrrd : SDNode<"ARMISD::FMRRD", SDTarmfmrrd, [SDNPHasChain, SDNPOutFlag]>; def armfmrrd : SDNode<"ARMISD::FMRRD", SDTarmfmrrd, [SDNPHasChain, SDNPOutFlag]>;
def SDTarmfmdrr : SDTypeProfile<1, 2, [SDTCisFP<0>, SDTCisInt<1>, SDTCisInt<2>]>;
def armfmdrr : SDNode<"ARMISD::FMDRR", SDTarmfmdrr, []>;
def ADJCALLSTACKUP : InstARM<(ops i32imm:$amt), def ADJCALLSTACKUP : InstARM<(ops i32imm:$amt),
"!ADJCALLSTACKUP $amt", "!ADJCALLSTACKUP $amt",
[(callseq_end imm:$amt)]>; [(callseq_end imm:$amt)]>;
@ -175,6 +178,9 @@ def FMRS : InstARM<(ops IntRegs:$dst, FPRegs:$src),
def FMRRD : InstARM<(ops IntRegs:$i0, IntRegs:$i1, DFPRegs:$src), def FMRRD : InstARM<(ops IntRegs:$i0, IntRegs:$i1, DFPRegs:$src),
"fmrrd $i0, $i1, $src", [(armfmrrd IntRegs:$i0, IntRegs:$i1, DFPRegs:$src)]>; "fmrrd $i0, $i1, $src", [(armfmrrd IntRegs:$i0, IntRegs:$i1, DFPRegs:$src)]>;
def FMDRR : InstARM<(ops DFPRegs:$dst, IntRegs:$i0, IntRegs:$i1),
"fmdrr $dst, $i0, $i1", [(set DFPRegs:$dst, (armfmdrr IntRegs:$i0, IntRegs:$i1))]>;
def FSITOS : InstARM<(ops FPRegs:$dst, FPRegs:$src), def FSITOS : InstARM<(ops FPRegs:$dst, FPRegs:$src),
"fsitos $dst, $src", [(set FPRegs:$dst, (armfsitos FPRegs:$src))]>; "fsitos $dst, $src", [(set FPRegs:$dst, (armfsitos FPRegs:$src))]>;

View File

@ -1,9 +1,10 @@
; RUN: llvm-as < %s | llc -march=arm && ; RUN: llvm-as < %s | llc -march=arm &&
; RUN: llvm-as < %s | llc -march=arm | grep fmsr | wc -l | grep 2 && ; RUN: llvm-as < %s | llc -march=arm | grep fmsr | wc -l | grep 2 &&
; RUN: llvm-as < %s | llc -march=arm | grep fsitos && ; RUN: llvm-as < %s | llc -march=arm | grep fsitos &&
; RUN: llvm-as < %s | llc -march=arm | grep fmrs && ; RUN: llvm-as < %s | llc -march=arm | grep fmrs &&
; RUN: llvm-as < %s | llc -march=arm | grep fsitod && ; RUN: llvm-as < %s | llc -march=arm | grep fsitod &&
; RUN: llvm-as < %s | llc -march=arm | grep fmrrd && ; RUN: llvm-as < %s | llc -march=arm | grep fmrrd | wc -l | grep 2 &&
; RUN: llvm-as < %s | llc -march=arm | grep fmdrr | wc -l | grep 1 &&
; RUN: llvm-as < %s | llc -march=arm | grep flds && ; RUN: llvm-as < %s | llc -march=arm | grep flds &&
; RUN: llvm-as < %s | llc -march=arm | grep ".word.*1065353216" ; RUN: llvm-as < %s | llc -march=arm | grep ".word.*1065353216"
@ -23,3 +24,7 @@ float %h() {
entry: entry:
ret float 1.000000e+00 ret float 1.000000e+00
} }
double %f2(double %a) {
ret double %a
}