mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-07-18 12:29:27 +00:00
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:
parent
bc588b8bbf
commit
a284584352
@ -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),
|
||||||
|
@ -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))]>;
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user