mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 11:13:28 +01:00
Introduce codegen for the Signal Processing Engine
Summary: The Signal Processing Engine (SPE) is found on NXP/Freescale e500v1, e500v2, and several e200 cores. This adds support targeting the e500v2, as this is more common than the e500v1, and is in SoCs still on the market. This patch is very intrusive because the SPE is binary incompatible with the traditional FPU. After discussing with others, the cleanest solution was to make both SPE and FPU features on top of a base PowerPC subset, so all FPU instructions are now wrapped with HasFPU predicates. Supported by this are: * Code generation following the SPE ABI at the LLVM IR level (calling conventions) * Single- and Double-precision math at the level supported by the APU. Still to do: * Vector operations * SPE intrinsics As this changes the Callee-saved register list order, one test, which tests the precise generated code, was updated to account for the new register order. Reviewed by: nemanjai Differential Revision: https://reviews.llvm.org/D44830 llvm-svn: 337347
This commit is contained in:
parent
668c53374d
commit
3cb288f428
@ -83,6 +83,16 @@ static const MCPhysReg FRegs[32] = {
|
||||
PPC::F24, PPC::F25, PPC::F26, PPC::F27,
|
||||
PPC::F28, PPC::F29, PPC::F30, PPC::F31
|
||||
};
|
||||
static const MCPhysReg SPERegs[32] = {
|
||||
PPC::S0, PPC::S1, PPC::S2, PPC::S3,
|
||||
PPC::S4, PPC::S5, PPC::S6, PPC::S7,
|
||||
PPC::S8, PPC::S9, PPC::S10, PPC::S11,
|
||||
PPC::S12, PPC::S13, PPC::S14, PPC::S15,
|
||||
PPC::S16, PPC::S17, PPC::S18, PPC::S19,
|
||||
PPC::S20, PPC::S21, PPC::S22, PPC::S23,
|
||||
PPC::S24, PPC::S25, PPC::S26, PPC::S27,
|
||||
PPC::S28, PPC::S29, PPC::S30, PPC::S31
|
||||
};
|
||||
static const MCPhysReg VFRegs[32] = {
|
||||
PPC::VF0, PPC::VF1, PPC::VF2, PPC::VF3,
|
||||
PPC::VF4, PPC::VF5, PPC::VF6, PPC::VF7,
|
||||
@ -648,6 +658,16 @@ public:
|
||||
Inst.addOperand(MCOperand::createReg(QFRegs[getReg()]));
|
||||
}
|
||||
|
||||
void addRegSPE4RCOperands(MCInst &Inst, unsigned N) const {
|
||||
assert(N == 1 && "Invalid number of operands!");
|
||||
Inst.addOperand(MCOperand::createReg(RRegs[getReg()]));
|
||||
}
|
||||
|
||||
void addRegSPERCOperands(MCInst &Inst, unsigned N) const {
|
||||
assert(N == 1 && "Invalid number of operands!");
|
||||
Inst.addOperand(MCOperand::createReg(SPERegs[getReg()]));
|
||||
}
|
||||
|
||||
void addRegCRBITRCOperands(MCInst &Inst, unsigned N) const {
|
||||
assert(N == 1 && "Invalid number of operands!");
|
||||
Inst.addOperand(MCOperand::createReg(CRBITRegs[getCRBit()]));
|
||||
|
@ -226,6 +226,17 @@ static const unsigned QFRegs[] = {
|
||||
PPC::QF28, PPC::QF29, PPC::QF30, PPC::QF31
|
||||
};
|
||||
|
||||
static const unsigned SPERegs[] = {
|
||||
PPC::S0, PPC::S1, PPC::S2, PPC::S3,
|
||||
PPC::S4, PPC::S5, PPC::S6, PPC::S7,
|
||||
PPC::S8, PPC::S9, PPC::S10, PPC::S11,
|
||||
PPC::S12, PPC::S13, PPC::S14, PPC::S15,
|
||||
PPC::S16, PPC::S17, PPC::S18, PPC::S19,
|
||||
PPC::S20, PPC::S21, PPC::S22, PPC::S23,
|
||||
PPC::S24, PPC::S25, PPC::S26, PPC::S27,
|
||||
PPC::S28, PPC::S29, PPC::S30, PPC::S31
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
static DecodeStatus decodeRegisterClass(MCInst &Inst, uint64_t RegNo,
|
||||
const unsigned (&Regs)[N]) {
|
||||
@ -327,6 +338,18 @@ static DecodeStatus DecodeQFRCRegisterClass(MCInst &Inst, uint64_t RegNo,
|
||||
return decodeRegisterClass(Inst, RegNo, QFRegs);
|
||||
}
|
||||
|
||||
static DecodeStatus DecodeSPE4RCRegisterClass(MCInst &Inst, uint64_t RegNo,
|
||||
uint64_t Address,
|
||||
const void *Decoder) {
|
||||
return decodeRegisterClass(Inst, RegNo, GPRegs);
|
||||
}
|
||||
|
||||
static DecodeStatus DecodeSPERCRegisterClass(MCInst &Inst, uint64_t RegNo,
|
||||
uint64_t Address,
|
||||
const void *Decoder) {
|
||||
return decodeRegisterClass(Inst, RegNo, SPERegs);
|
||||
}
|
||||
|
||||
#define DecodeQSRCRegisterClass DecodeQFRCRegisterClass
|
||||
#define DecodeQBRCRegisterClass DecodeQFRCRegisterClass
|
||||
|
||||
|
@ -50,6 +50,9 @@ namespace PPC {
|
||||
PRED_UN_PLUS = (3 << 5) | 15,
|
||||
PRED_NU_PLUS = (3 << 5) | 7,
|
||||
|
||||
// SPE scalar compare instructions always set the GT bit.
|
||||
PRED_SPE = PRED_GT,
|
||||
|
||||
// When dealing with individual condition-register bits, we have simple set
|
||||
// and unset predicates.
|
||||
PRED_BIT_SET = 1024,
|
||||
|
@ -61,9 +61,12 @@ def Feature64BitRegs : SubtargetFeature<"64bitregs","Use64BitRegs", "true",
|
||||
"Enable 64-bit registers usage for ppc32 [beta]">;
|
||||
def FeatureCRBits : SubtargetFeature<"crbits", "UseCRBits", "true",
|
||||
"Use condition-register bits individually">;
|
||||
def FeatureFPU : SubtargetFeature<"fpu","HasFPU","true",
|
||||
"Enable classic FPU instructions",
|
||||
[FeatureHardFloat]>;
|
||||
def FeatureAltivec : SubtargetFeature<"altivec","HasAltivec", "true",
|
||||
"Enable Altivec instructions",
|
||||
[FeatureHardFloat]>;
|
||||
[FeatureFPU]>;
|
||||
def FeatureSPE : SubtargetFeature<"spe","HasSPE", "true",
|
||||
"Enable SPE instructions",
|
||||
[FeatureHardFloat]>;
|
||||
@ -71,36 +74,36 @@ def FeatureMFOCRF : SubtargetFeature<"mfocrf","HasMFOCRF", "true",
|
||||
"Enable the MFOCRF instruction">;
|
||||
def FeatureFSqrt : SubtargetFeature<"fsqrt","HasFSQRT", "true",
|
||||
"Enable the fsqrt instruction",
|
||||
[FeatureHardFloat]>;
|
||||
[FeatureFPU]>;
|
||||
def FeatureFCPSGN : SubtargetFeature<"fcpsgn", "HasFCPSGN", "true",
|
||||
"Enable the fcpsgn instruction",
|
||||
[FeatureHardFloat]>;
|
||||
[FeatureFPU]>;
|
||||
def FeatureFRE : SubtargetFeature<"fre", "HasFRE", "true",
|
||||
"Enable the fre instruction",
|
||||
[FeatureHardFloat]>;
|
||||
[FeatureFPU]>;
|
||||
def FeatureFRES : SubtargetFeature<"fres", "HasFRES", "true",
|
||||
"Enable the fres instruction",
|
||||
[FeatureHardFloat]>;
|
||||
[FeatureFPU]>;
|
||||
def FeatureFRSQRTE : SubtargetFeature<"frsqrte", "HasFRSQRTE", "true",
|
||||
"Enable the frsqrte instruction",
|
||||
[FeatureHardFloat]>;
|
||||
[FeatureFPU]>;
|
||||
def FeatureFRSQRTES : SubtargetFeature<"frsqrtes", "HasFRSQRTES", "true",
|
||||
"Enable the frsqrtes instruction",
|
||||
[FeatureHardFloat]>;
|
||||
[FeatureFPU]>;
|
||||
def FeatureRecipPrec : SubtargetFeature<"recipprec", "HasRecipPrec", "true",
|
||||
"Assume higher precision reciprocal estimates">;
|
||||
def FeatureSTFIWX : SubtargetFeature<"stfiwx","HasSTFIWX", "true",
|
||||
"Enable the stfiwx instruction",
|
||||
[FeatureHardFloat]>;
|
||||
[FeatureFPU]>;
|
||||
def FeatureLFIWAX : SubtargetFeature<"lfiwax","HasLFIWAX", "true",
|
||||
"Enable the lfiwax instruction",
|
||||
[FeatureHardFloat]>;
|
||||
[FeatureFPU]>;
|
||||
def FeatureFPRND : SubtargetFeature<"fprnd", "HasFPRND", "true",
|
||||
"Enable the fri[mnpz] instructions",
|
||||
[FeatureHardFloat]>;
|
||||
[FeatureFPU]>;
|
||||
def FeatureFPCVT : SubtargetFeature<"fpcvt", "HasFPCVT", "true",
|
||||
"Enable fc[ft]* (unsigned and single-precision) and lfiwzx instructions",
|
||||
[FeatureHardFloat]>;
|
||||
[FeatureFPU]>;
|
||||
def FeatureISEL : SubtargetFeature<"isel","HasISEL", "true",
|
||||
"Enable the isel instruction">;
|
||||
def FeatureBPERMD : SubtargetFeature<"bpermd", "HasBPERMD", "true",
|
||||
@ -129,7 +132,7 @@ def FeaturePPC6xx : SubtargetFeature<"ppc6xx", "IsPPC6xx", "true",
|
||||
"Enable PPC 6xx instructions">;
|
||||
def FeatureQPX : SubtargetFeature<"qpx","HasQPX", "true",
|
||||
"Enable QPX instructions",
|
||||
[FeatureHardFloat]>;
|
||||
[FeatureFPU]>;
|
||||
def FeatureVSX : SubtargetFeature<"vsx","HasVSX", "true",
|
||||
"Enable VSX instructions",
|
||||
[FeatureAltivec]>;
|
||||
@ -308,8 +311,8 @@ def : ProcessorModel<"450", PPC440Model, [Directive440, FeatureISEL,
|
||||
FeatureFRES, FeatureFRSQRTE,
|
||||
FeatureICBT, FeatureBookE,
|
||||
FeatureMSYNC, FeatureMFTB]>;
|
||||
def : Processor<"601", G3Itineraries, [Directive601, FeatureHardFloat]>;
|
||||
def : Processor<"602", G3Itineraries, [Directive602, FeatureHardFloat,
|
||||
def : Processor<"601", G3Itineraries, [Directive601, FeatureFPU]>;
|
||||
def : Processor<"602", G3Itineraries, [Directive602, FeatureFPU,
|
||||
FeatureMFTB]>;
|
||||
def : Processor<"603", G3Itineraries, [Directive603,
|
||||
FeatureFRES, FeatureFRSQRTE,
|
||||
|
@ -510,6 +510,32 @@ void PPCAsmPrinter::EmitInstruction(const MachineInstr *MI) {
|
||||
const Module *M = MF->getFunction().getParent();
|
||||
PICLevel::Level PL = M->getPICLevel();
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Validate that SPE and FPU are mutually exclusive in codegen
|
||||
if (!MI->isInlineAsm()) {
|
||||
for (const MachineOperand &MO: MI->operands()) {
|
||||
if (MO.isReg()) {
|
||||
unsigned Reg = MO.getReg();
|
||||
if (Subtarget->hasSPE()) {
|
||||
if (PPC::F4RCRegClass.contains(Reg) ||
|
||||
PPC::F8RCRegClass.contains(Reg) ||
|
||||
PPC::QBRCRegClass.contains(Reg) ||
|
||||
PPC::QFRCRegClass.contains(Reg) ||
|
||||
PPC::QSRCRegClass.contains(Reg) ||
|
||||
PPC::VFRCRegClass.contains(Reg) ||
|
||||
PPC::VRRCRegClass.contains(Reg) ||
|
||||
PPC::VSFRCRegClass.contains(Reg) ||
|
||||
PPC::VSSRCRegClass.contains(Reg)
|
||||
)
|
||||
llvm_unreachable("SPE targets cannot have FPRegs!");
|
||||
} else {
|
||||
if (PPC::SPERCRegClass.contains(Reg))
|
||||
llvm_unreachable("SPE register found in FPU-targeted code!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// Lower multi-instruction pseudo operations.
|
||||
switch (MI->getOpcode()) {
|
||||
default: break;
|
||||
|
@ -83,8 +83,14 @@ def RetCC_PPC : CallingConv<[
|
||||
|
||||
// Floating point types returned as "direct" go into F1 .. F8; note that
|
||||
// only the ELFv2 ABI fully utilizes all these registers.
|
||||
CCIfType<[f32], CCAssignToReg<[F1, F2, F3, F4, F5, F6, F7, F8]>>,
|
||||
CCIfType<[f64], CCAssignToReg<[F1, F2, F3, F4, F5, F6, F7, F8]>>,
|
||||
CCIfNotSubtarget<"hasSPE()",
|
||||
CCIfType<[f32], CCAssignToReg<[F1, F2, F3, F4, F5, F6, F7, F8]>>>,
|
||||
CCIfNotSubtarget<"hasSPE()",
|
||||
CCIfType<[f64], CCAssignToReg<[F1, F2, F3, F4, F5, F6, F7, F8]>>>,
|
||||
CCIfSubtarget<"hasSPE()",
|
||||
CCIfType<[f32], CCAssignToReg<[R3, R4, R5, R6, R7, R8, R9, R10]>>>,
|
||||
CCIfSubtarget<"hasSPE()",
|
||||
CCIfType<[f64], CCAssignToReg<[S3, S4, S5, S6, S7, S8, S9, S10]>>>,
|
||||
|
||||
// For P9, f128 are passed in vector registers.
|
||||
CCIfType<[f128],
|
||||
@ -188,7 +194,15 @@ def CC_PPC32_SVR4_Common : CallingConv<[
|
||||
CCIfType<[f64], CCIfSplit<CCCustom<"CC_PPC32_SVR4_Custom_AlignFPArgRegs">>>,
|
||||
|
||||
// FP values are passed in F1 - F8.
|
||||
CCIfType<[f32, f64], CCAssignToReg<[F1, F2, F3, F4, F5, F6, F7, F8]>>,
|
||||
CCIfType<[f32, f64],
|
||||
CCIfNotSubtarget<"hasSPE()",
|
||||
CCAssignToReg<[F1, F2, F3, F4, F5, F6, F7, F8]>>>,
|
||||
CCIfType<[f64],
|
||||
CCIfSubtarget<"hasSPE()",
|
||||
CCAssignToReg<[S3, S4, S5, S6, S7, S8, S9, S10]>>>,
|
||||
CCIfType<[f32],
|
||||
CCIfSubtarget<"hasSPE()",
|
||||
CCAssignToReg<[R3, R4, R5, R6, R7, R8, R9, R10]>>>,
|
||||
|
||||
// Split arguments have an alignment of 8 bytes on the stack.
|
||||
CCIfType<[i32], CCIfSplit<CCAssignToStack<4, 8>>>,
|
||||
@ -197,7 +211,11 @@ def CC_PPC32_SVR4_Common : CallingConv<[
|
||||
|
||||
// Floats are stored in double precision format, thus they have the same
|
||||
// alignment and size as doubles.
|
||||
CCIfType<[f32,f64], CCAssignToStack<8, 8>>,
|
||||
// With SPE floats are stored as single precision, so have alignment and
|
||||
// size of int.
|
||||
CCIfType<[f32,f64], CCIfNotSubtarget<"hasSPE()", CCAssignToStack<8, 8>>>,
|
||||
CCIfType<[f32], CCIfSubtarget<"hasSPE()", CCAssignToStack<4, 4>>>,
|
||||
CCIfType<[f64], CCIfSubtarget<"hasSPE()", CCAssignToStack<8, 8>>>,
|
||||
|
||||
// QPX vectors that are stored in double precision need 32-byte alignment.
|
||||
CCIfType<[v4f64, v4i1], CCAssignToStack<32, 32>>,
|
||||
@ -265,15 +283,23 @@ def CSR_Darwin32 : CalleeSavedRegs<(add R13, R14, R15, R16, R17, R18, R19, R20,
|
||||
|
||||
def CSR_Darwin32_Altivec : CalleeSavedRegs<(add CSR_Darwin32, CSR_Altivec)>;
|
||||
|
||||
def CSR_SVR432 : CalleeSavedRegs<(add R14, R15, R16, R17, R18, R19, R20,
|
||||
R21, R22, R23, R24, R25, R26, R27, R28,
|
||||
R29, R30, R31, F14, F15, F16, F17, F18,
|
||||
// SPE does not use FPRs, so break out the common register set as base.
|
||||
def CSR_SVR432_COMM : CalleeSavedRegs<(add R14, R15, R16, R17, R18, R19, R20,
|
||||
R21, R22, R23, R24, R25, R26, R27,
|
||||
R28, R29, R30, R31, CR2, CR3, CR4
|
||||
)>;
|
||||
def CSR_SVR432 : CalleeSavedRegs<(add CSR_SVR432_COMM, F14, F15, F16, F17, F18,
|
||||
F19, F20, F21, F22, F23, F24, F25, F26,
|
||||
F27, F28, F29, F30, F31, CR2, CR3, CR4
|
||||
F27, F28, F29, F30, F31
|
||||
)>;
|
||||
def CSR_SPE : CalleeSavedRegs<(add S14, S15, S16, S17, S18, S19, S20, S21, S22,
|
||||
S23, S24, S25, S26, S27, S28, S29, S30, S31
|
||||
)>;
|
||||
|
||||
def CSR_SVR432_Altivec : CalleeSavedRegs<(add CSR_SVR432, CSR_Altivec)>;
|
||||
|
||||
def CSR_SVR432_SPE : CalleeSavedRegs<(add CSR_SVR432_COMM, CSR_SPE)>;
|
||||
|
||||
def CSR_Darwin64 : CalleeSavedRegs<(add X13, X14, X15, X16, X17, X18, X19, X20,
|
||||
X21, X22, X23, X24, X25, X26, X27, X28,
|
||||
X29, X30, X31, F14, F15, F16, F17, F18,
|
||||
|
@ -153,7 +153,8 @@ class PPCFastISel final : public FastISel {
|
||||
return RC->getID() == PPC::VSSRCRegClassID;
|
||||
}
|
||||
bool PPCEmitCmp(const Value *Src1Value, const Value *Src2Value,
|
||||
bool isZExt, unsigned DestReg);
|
||||
bool isZExt, unsigned DestReg,
|
||||
const PPC::Predicate Pred);
|
||||
bool PPCEmitLoad(MVT VT, unsigned &ResultReg, Address &Addr,
|
||||
const TargetRegisterClass *RC, bool IsZExt = true,
|
||||
unsigned FP64LoadOpc = PPC::LFD);
|
||||
@ -466,6 +467,7 @@ bool PPCFastISel::PPCEmitLoad(MVT VT, unsigned &ResultReg, Address &Addr,
|
||||
bool IsZExt, unsigned FP64LoadOpc) {
|
||||
unsigned Opc;
|
||||
bool UseOffset = true;
|
||||
bool HasSPE = PPCSubTarget->hasSPE();
|
||||
|
||||
// If ResultReg is given, it determines the register class of the load.
|
||||
// Otherwise, RC is the register class to use. If the result of the
|
||||
@ -477,8 +479,8 @@ bool PPCFastISel::PPCEmitLoad(MVT VT, unsigned &ResultReg, Address &Addr,
|
||||
const TargetRegisterClass *UseRC =
|
||||
(ResultReg ? MRI.getRegClass(ResultReg) :
|
||||
(RC ? RC :
|
||||
(VT == MVT::f64 ? &PPC::F8RCRegClass :
|
||||
(VT == MVT::f32 ? &PPC::F4RCRegClass :
|
||||
(VT == MVT::f64 ? (HasSPE ? &PPC::SPERCRegClass : &PPC::F8RCRegClass) :
|
||||
(VT == MVT::f32 ? (HasSPE ? &PPC::SPE4RCRegClass : &PPC::F4RCRegClass) :
|
||||
(VT == MVT::i64 ? &PPC::G8RC_and_G8RC_NOX0RegClass :
|
||||
&PPC::GPRC_and_GPRC_NOR0RegClass)))));
|
||||
|
||||
@ -507,7 +509,7 @@ bool PPCFastISel::PPCEmitLoad(MVT VT, unsigned &ResultReg, Address &Addr,
|
||||
UseOffset = ((Addr.Offset & 3) == 0);
|
||||
break;
|
||||
case MVT::f32:
|
||||
Opc = PPC::LFS;
|
||||
Opc = PPCSubTarget->hasSPE() ? PPC::SPELWZ : PPC::LFS;
|
||||
break;
|
||||
case MVT::f64:
|
||||
Opc = FP64LoadOpc;
|
||||
@ -578,6 +580,8 @@ bool PPCFastISel::PPCEmitLoad(MVT VT, unsigned &ResultReg, Address &Addr,
|
||||
case PPC::LD: Opc = PPC::LDX; break;
|
||||
case PPC::LFS: Opc = IsVSSRC ? PPC::LXSSPX : PPC::LFSX; break;
|
||||
case PPC::LFD: Opc = IsVSFRC ? PPC::LXSDX : PPC::LFDX; break;
|
||||
case PPC::EVLDD: Opc = PPC::EVLDDX; break;
|
||||
case PPC::SPELWZ: Opc = PPC::SPELWZX; break;
|
||||
}
|
||||
|
||||
auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc),
|
||||
@ -620,7 +624,8 @@ bool PPCFastISel::SelectLoad(const Instruction *I) {
|
||||
AssignedReg ? MRI.getRegClass(AssignedReg) : nullptr;
|
||||
|
||||
unsigned ResultReg = 0;
|
||||
if (!PPCEmitLoad(VT, ResultReg, Addr, RC))
|
||||
if (!PPCEmitLoad(VT, ResultReg, Addr, RC, true,
|
||||
PPCSubTarget->hasSPE() ? PPC::EVLDD : PPC::LFD))
|
||||
return false;
|
||||
updateValueMap(I, ResultReg);
|
||||
return true;
|
||||
@ -653,10 +658,10 @@ bool PPCFastISel::PPCEmitStore(MVT VT, unsigned SrcReg, Address &Addr) {
|
||||
UseOffset = ((Addr.Offset & 3) == 0);
|
||||
break;
|
||||
case MVT::f32:
|
||||
Opc = PPC::STFS;
|
||||
Opc = PPCSubTarget->hasSPE() ? PPC::SPESTW : PPC::STFS;
|
||||
break;
|
||||
case MVT::f64:
|
||||
Opc = PPC::STFD;
|
||||
Opc = PPCSubTarget->hasSPE() ? PPC::EVSTDD : PPC::STFD;
|
||||
break;
|
||||
}
|
||||
|
||||
@ -721,6 +726,8 @@ bool PPCFastISel::PPCEmitStore(MVT VT, unsigned SrcReg, Address &Addr) {
|
||||
case PPC::STD: Opc = PPC::STDX; break;
|
||||
case PPC::STFS: Opc = IsVSSRC ? PPC::STXSSPX : PPC::STFSX; break;
|
||||
case PPC::STFD: Opc = IsVSFRC ? PPC::STXSDX : PPC::STFDX; break;
|
||||
case PPC::EVSTDD: Opc = PPC::EVSTDDX; break;
|
||||
case PPC::SPESTW: Opc = PPC::SPESTWX; break;
|
||||
}
|
||||
|
||||
auto MIB = BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc))
|
||||
@ -794,11 +801,12 @@ bool PPCFastISel::SelectBranch(const Instruction *I) {
|
||||
unsigned CondReg = createResultReg(&PPC::CRRCRegClass);
|
||||
|
||||
if (!PPCEmitCmp(CI->getOperand(0), CI->getOperand(1), CI->isUnsigned(),
|
||||
CondReg))
|
||||
CondReg, PPCPred))
|
||||
return false;
|
||||
|
||||
BuildMI(*BrBB, FuncInfo.InsertPt, DbgLoc, TII.get(PPC::BCC))
|
||||
.addImm(PPCPred).addReg(CondReg).addMBB(TBB);
|
||||
.addImm(PPCSubTarget->hasSPE() ? PPC::PRED_SPE : PPCPred)
|
||||
.addReg(CondReg).addMBB(TBB);
|
||||
finishCondBranch(BI->getParent(), TBB, FBB);
|
||||
return true;
|
||||
}
|
||||
@ -822,7 +830,8 @@ bool PPCFastISel::SelectBranch(const Instruction *I) {
|
||||
// Attempt to emit a compare of the two source values. Signed and unsigned
|
||||
// comparisons are supported. Return false if we can't handle it.
|
||||
bool PPCFastISel::PPCEmitCmp(const Value *SrcValue1, const Value *SrcValue2,
|
||||
bool IsZExt, unsigned DestReg) {
|
||||
bool IsZExt, unsigned DestReg,
|
||||
const PPC::Predicate Pred) {
|
||||
Type *Ty = SrcValue1->getType();
|
||||
EVT SrcEVT = TLI.getValueType(DL, Ty, true);
|
||||
if (!SrcEVT.isSimple())
|
||||
@ -838,6 +847,7 @@ bool PPCFastISel::PPCEmitCmp(const Value *SrcValue1, const Value *SrcValue2,
|
||||
// similar to ARM in this regard.
|
||||
long Imm = 0;
|
||||
bool UseImm = false;
|
||||
const bool HasSPE = PPCSubTarget->hasSPE();
|
||||
|
||||
// Only 16-bit integer constants can be represented in compares for
|
||||
// PowerPC. Others will be materialized into a register.
|
||||
@ -856,10 +866,38 @@ bool PPCFastISel::PPCEmitCmp(const Value *SrcValue1, const Value *SrcValue2,
|
||||
switch (SrcVT.SimpleTy) {
|
||||
default: return false;
|
||||
case MVT::f32:
|
||||
CmpOpc = PPC::FCMPUS;
|
||||
if (HasSPE) {
|
||||
switch (Pred) {
|
||||
default: return false;
|
||||
case PPC::PRED_EQ:
|
||||
CmpOpc = PPC::EFSCMPEQ;
|
||||
break;
|
||||
case PPC::PRED_LT:
|
||||
CmpOpc = PPC::EFSCMPLT;
|
||||
break;
|
||||
case PPC::PRED_GT:
|
||||
CmpOpc = PPC::EFSCMPGT;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
CmpOpc = PPC::FCMPUS;
|
||||
break;
|
||||
case MVT::f64:
|
||||
CmpOpc = PPC::FCMPUD;
|
||||
if (HasSPE) {
|
||||
switch (Pred) {
|
||||
default: return false;
|
||||
case PPC::PRED_EQ:
|
||||
CmpOpc = PPC::EFDCMPEQ;
|
||||
break;
|
||||
case PPC::PRED_LT:
|
||||
CmpOpc = PPC::EFDCMPLT;
|
||||
break;
|
||||
case PPC::PRED_GT:
|
||||
CmpOpc = PPC::EFDCMPGT;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
CmpOpc = PPC::FCMPUD;
|
||||
break;
|
||||
case MVT::i1:
|
||||
case MVT::i8:
|
||||
@ -947,9 +985,19 @@ bool PPCFastISel::SelectFPTrunc(const Instruction *I) {
|
||||
return false;
|
||||
|
||||
// Round the result to single precision.
|
||||
unsigned DestReg = createResultReg(&PPC::F4RCRegClass);
|
||||
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(PPC::FRSP), DestReg)
|
||||
.addReg(SrcReg);
|
||||
unsigned DestReg;
|
||||
|
||||
if (PPCSubTarget->hasSPE()) {
|
||||
DestReg = createResultReg(&PPC::SPE4RCRegClass);
|
||||
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
||||
TII.get(PPC::EFSCFD), DestReg)
|
||||
.addReg(SrcReg);
|
||||
} else {
|
||||
DestReg = createResultReg(&PPC::F4RCRegClass);
|
||||
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
|
||||
TII.get(PPC::FRSP), DestReg)
|
||||
.addReg(SrcReg);
|
||||
}
|
||||
|
||||
updateValueMap(I, DestReg);
|
||||
return true;
|
||||
@ -1031,6 +1079,22 @@ bool PPCFastISel::SelectIToFP(const Instruction *I, bool IsSigned) {
|
||||
if (SrcReg == 0)
|
||||
return false;
|
||||
|
||||
// Shortcut for SPE. Doesn't need to store/load, since it's all in the GPRs
|
||||
if (PPCSubTarget->hasSPE()) {
|
||||
unsigned Opc;
|
||||
if (DstVT == MVT::f32)
|
||||
Opc = IsSigned ? PPC::EFSCFSI : PPC::EFSCFUI;
|
||||
else
|
||||
Opc = IsSigned ? PPC::EFDCFSI : PPC::EFDCFUI;
|
||||
|
||||
unsigned DestReg = createResultReg(&PPC::SPERCRegClass);
|
||||
// Generate the convert.
|
||||
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), DestReg)
|
||||
.addReg(SrcReg);
|
||||
updateValueMap(I, DestReg);
|
||||
return true;
|
||||
}
|
||||
|
||||
// We can only lower an unsigned convert if we have the newer
|
||||
// floating-point conversion operations.
|
||||
if (!IsSigned && !PPCSubTarget->hasFPCVT())
|
||||
@ -1125,8 +1189,9 @@ bool PPCFastISel::SelectFPToI(const Instruction *I, bool IsSigned) {
|
||||
if (DstVT != MVT::i32 && DstVT != MVT::i64)
|
||||
return false;
|
||||
|
||||
// If we don't have FCTIDUZ and we need it, punt to SelectionDAG.
|
||||
if (DstVT == MVT::i64 && !IsSigned && !PPCSubTarget->hasFPCVT())
|
||||
// If we don't have FCTIDUZ, or SPE, and we need it, punt to SelectionDAG.
|
||||
if (DstVT == MVT::i64 && !IsSigned &&
|
||||
!PPCSubTarget->hasFPCVT() && !PPCSubTarget->hasSPE())
|
||||
return false;
|
||||
|
||||
Value *Src = I->getOperand(0);
|
||||
@ -1154,23 +1219,36 @@ bool PPCFastISel::SelectFPToI(const Instruction *I, bool IsSigned) {
|
||||
|
||||
// Determine the opcode for the conversion, which takes place
|
||||
// entirely within FPRs.
|
||||
unsigned DestReg = createResultReg(&PPC::F8RCRegClass);
|
||||
unsigned DestReg;
|
||||
unsigned Opc;
|
||||
|
||||
if (DstVT == MVT::i32)
|
||||
if (IsSigned)
|
||||
Opc = PPC::FCTIWZ;
|
||||
if (PPCSubTarget->hasSPE()) {
|
||||
if (DstVT == MVT::i32) {
|
||||
DestReg = createResultReg(&PPC::GPRCRegClass);
|
||||
if (IsSigned)
|
||||
Opc = InRC == &PPC::SPE4RCRegClass ? PPC::EFSCTSIZ : PPC::EFDCTSIZ;
|
||||
else
|
||||
Opc = InRC == &PPC::SPE4RCRegClass ? PPC::EFSCTUIZ : PPC::EFDCTUIZ;
|
||||
}
|
||||
} else {
|
||||
DestReg = createResultReg(&PPC::F8RCRegClass);
|
||||
if (DstVT == MVT::i32)
|
||||
if (IsSigned)
|
||||
Opc = PPC::FCTIWZ;
|
||||
else
|
||||
Opc = PPCSubTarget->hasFPCVT() ? PPC::FCTIWUZ : PPC::FCTIDZ;
|
||||
else
|
||||
Opc = PPCSubTarget->hasFPCVT() ? PPC::FCTIWUZ : PPC::FCTIDZ;
|
||||
else
|
||||
Opc = IsSigned ? PPC::FCTIDZ : PPC::FCTIDUZ;
|
||||
Opc = IsSigned ? PPC::FCTIDZ : PPC::FCTIDUZ;
|
||||
}
|
||||
|
||||
// Generate the convert.
|
||||
BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc, TII.get(Opc), DestReg)
|
||||
.addReg(SrcReg);
|
||||
|
||||
// Now move the integer value from a float register to an integer register.
|
||||
unsigned IntReg = PPCMoveToIntReg(I, DstVT, DestReg, IsSigned);
|
||||
unsigned IntReg = PPCSubTarget->hasSPE() ? DestReg :
|
||||
PPCMoveToIntReg(I, DstVT, DestReg, IsSigned);
|
||||
|
||||
if (IntReg == 0)
|
||||
return false;
|
||||
|
||||
@ -1918,8 +1996,13 @@ unsigned PPCFastISel::PPCMaterializeFP(const ConstantFP *CFP, MVT VT) {
|
||||
unsigned Align = DL.getPrefTypeAlignment(CFP->getType());
|
||||
assert(Align > 0 && "Unexpectedly missing alignment information!");
|
||||
unsigned Idx = MCP.getConstantPoolIndex(cast<Constant>(CFP), Align);
|
||||
const TargetRegisterClass *RC =
|
||||
(VT == MVT::f32) ? &PPC::F4RCRegClass : &PPC::F8RCRegClass;
|
||||
const bool HasSPE = PPCSubTarget->hasSPE();
|
||||
const TargetRegisterClass *RC;
|
||||
if (HasSPE)
|
||||
RC = ((VT == MVT::f32) ? &PPC::SPE4RCRegClass : &PPC::SPERCRegClass);
|
||||
else
|
||||
RC = ((VT == MVT::f32) ? &PPC::F4RCRegClass : &PPC::F8RCRegClass);
|
||||
|
||||
unsigned DestReg = createResultReg(RC);
|
||||
CodeModel::Model CModel = TM.getCodeModel();
|
||||
|
||||
@ -1927,7 +2010,13 @@ unsigned PPCFastISel::PPCMaterializeFP(const ConstantFP *CFP, MVT VT) {
|
||||
MachinePointerInfo::getConstantPool(*FuncInfo.MF),
|
||||
MachineMemOperand::MOLoad, (VT == MVT::f32) ? 4 : 8, Align);
|
||||
|
||||
unsigned Opc = (VT == MVT::f32) ? PPC::LFS : PPC::LFD;
|
||||
unsigned Opc;
|
||||
|
||||
if (HasSPE)
|
||||
Opc = ((VT == MVT::f32) ? PPC::SPELWZ : PPC::EVLDD);
|
||||
else
|
||||
Opc = ((VT == MVT::f32) ? PPC::LFS : PPC::LFD);
|
||||
|
||||
unsigned TmpReg = createResultReg(&PPC::G8RC_and_G8RC_NOX0RegClass);
|
||||
|
||||
PPCFuncInfo->setUsesTOCBasePtr();
|
||||
@ -2263,7 +2352,8 @@ bool PPCFastISel::tryToFoldLoadIntoMI(MachineInstr *MI, unsigned OpNo,
|
||||
|
||||
unsigned ResultReg = MI->getOperand(0).getReg();
|
||||
|
||||
if (!PPCEmitLoad(VT, ResultReg, Addr, nullptr, IsZExt))
|
||||
if (!PPCEmitLoad(VT, ResultReg, Addr, nullptr, IsZExt,
|
||||
PPCSubTarget->hasSPE() ? PPC::EVLDD : PPC::LFD))
|
||||
return false;
|
||||
|
||||
MI->eraseFromParent();
|
||||
|
@ -173,7 +173,27 @@ const PPCFrameLowering::SpillSlot *PPCFrameLowering::getCalleeSavedSpillSlots(
|
||||
{PPC::V23, -144},
|
||||
{PPC::V22, -160},
|
||||
{PPC::V21, -176},
|
||||
{PPC::V20, -192}};
|
||||
{PPC::V20, -192},
|
||||
|
||||
// SPE register save area (overlaps Vector save area).
|
||||
{PPC::S31, -8},
|
||||
{PPC::S30, -16},
|
||||
{PPC::S29, -24},
|
||||
{PPC::S28, -32},
|
||||
{PPC::S27, -40},
|
||||
{PPC::S26, -48},
|
||||
{PPC::S25, -56},
|
||||
{PPC::S24, -64},
|
||||
{PPC::S23, -72},
|
||||
{PPC::S22, -80},
|
||||
{PPC::S21, -88},
|
||||
{PPC::S20, -96},
|
||||
{PPC::S19, -104},
|
||||
{PPC::S18, -112},
|
||||
{PPC::S17, -120},
|
||||
{PPC::S16, -128},
|
||||
{PPC::S15, -136},
|
||||
{PPC::S14, -144}};
|
||||
|
||||
static const SpillSlot Offsets64[] = {
|
||||
// Floating-point register save area offsets.
|
||||
@ -1676,7 +1696,7 @@ void PPCFrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF,
|
||||
unsigned MinGPR = PPC::R31;
|
||||
unsigned MinG8R = PPC::X31;
|
||||
unsigned MinFPR = PPC::F31;
|
||||
unsigned MinVR = PPC::V31;
|
||||
unsigned MinVR = Subtarget.hasSPE() ? PPC::S31 : PPC::V31;
|
||||
|
||||
bool HasGPSaveArea = false;
|
||||
bool HasG8SaveArea = false;
|
||||
@ -1691,7 +1711,8 @@ void PPCFrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF,
|
||||
|
||||
for (unsigned i = 0, e = CSI.size(); i != e; ++i) {
|
||||
unsigned Reg = CSI[i].getReg();
|
||||
if (PPC::GPRCRegClass.contains(Reg)) {
|
||||
if (PPC::GPRCRegClass.contains(Reg) ||
|
||||
PPC::SPE4RCRegClass.contains(Reg)) {
|
||||
HasGPSaveArea = true;
|
||||
|
||||
GPRegs.push_back(CSI[i]);
|
||||
@ -1720,7 +1741,10 @@ void PPCFrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF,
|
||||
; // do nothing, as we already know whether CRs are spilled
|
||||
} else if (PPC::VRSAVERCRegClass.contains(Reg)) {
|
||||
HasVRSAVESaveArea = true;
|
||||
} else if (PPC::VRRCRegClass.contains(Reg)) {
|
||||
} else if (PPC::VRRCRegClass.contains(Reg) ||
|
||||
PPC::SPERCRegClass.contains(Reg)) {
|
||||
// Altivec and SPE are mutually exclusive, but have the same stack
|
||||
// alignment requirements, so overload the save area for both cases.
|
||||
HasVRSaveArea = true;
|
||||
|
||||
VRegs.push_back(CSI[i]);
|
||||
@ -1863,6 +1887,8 @@ void PPCFrameLowering::processFunctionBeforeFrameFinalized(MachineFunction &MF,
|
||||
LowerBound -= 4; // The VRSAVE save area is always 4 bytes long.
|
||||
}
|
||||
|
||||
// Both Altivec and SPE have the same alignment and padding requirements
|
||||
// within the stack frame.
|
||||
if (HasVRSaveArea) {
|
||||
// Insert alignment padding, we need 16-byte alignment. Note: for positive
|
||||
// number the alignment formula is : y = (x + (n-1)) & (~(n-1)). But since
|
||||
|
@ -3616,9 +3616,59 @@ SDValue PPCDAGToDAGISel::SelectCC(SDValue LHS, SDValue RHS, ISD::CondCode CC,
|
||||
Opc = PPC::CMPD;
|
||||
}
|
||||
} else if (LHS.getValueType() == MVT::f32) {
|
||||
Opc = PPC::FCMPUS;
|
||||
if (PPCSubTarget->hasSPE()) {
|
||||
switch (CC) {
|
||||
default:
|
||||
case ISD::SETEQ:
|
||||
case ISD::SETNE:
|
||||
Opc = PPC::EFSCMPEQ;
|
||||
break;
|
||||
case ISD::SETLT:
|
||||
case ISD::SETGE:
|
||||
case ISD::SETOLT:
|
||||
case ISD::SETOGE:
|
||||
case ISD::SETULT:
|
||||
case ISD::SETUGE:
|
||||
Opc = PPC::EFSCMPLT;
|
||||
break;
|
||||
case ISD::SETGT:
|
||||
case ISD::SETLE:
|
||||
case ISD::SETOGT:
|
||||
case ISD::SETOLE:
|
||||
case ISD::SETUGT:
|
||||
case ISD::SETULE:
|
||||
Opc = PPC::EFSCMPGT;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
Opc = PPC::FCMPUS;
|
||||
} else if (LHS.getValueType() == MVT::f64) {
|
||||
Opc = PPCSubTarget->hasVSX() ? PPC::XSCMPUDP : PPC::FCMPUD;
|
||||
if (PPCSubTarget->hasSPE()) {
|
||||
switch (CC) {
|
||||
default:
|
||||
case ISD::SETEQ:
|
||||
case ISD::SETNE:
|
||||
Opc = PPC::EFDCMPEQ;
|
||||
break;
|
||||
case ISD::SETLT:
|
||||
case ISD::SETGE:
|
||||
case ISD::SETOLT:
|
||||
case ISD::SETOGE:
|
||||
case ISD::SETULT:
|
||||
case ISD::SETUGE:
|
||||
Opc = PPC::EFDCMPLT;
|
||||
break;
|
||||
case ISD::SETGT:
|
||||
case ISD::SETLE:
|
||||
case ISD::SETOGT:
|
||||
case ISD::SETOLE:
|
||||
case ISD::SETUGT:
|
||||
case ISD::SETULE:
|
||||
Opc = PPC::EFDCMPGT;
|
||||
break;
|
||||
}
|
||||
} else
|
||||
Opc = PPCSubTarget->hasVSX() ? PPC::XSCMPUDP : PPC::FCMPUD;
|
||||
} else {
|
||||
assert(LHS.getValueType() == MVT::f128 && "Unknown vt!");
|
||||
assert(PPCSubTarget->hasVSX() && "__float128 requires VSX");
|
||||
@ -3896,7 +3946,7 @@ bool PPCDAGToDAGISel::trySETCC(SDNode *N) {
|
||||
// Altivec Vector compare instructions do not set any CR register by default and
|
||||
// vector compare operations return the same type as the operands.
|
||||
if (LHS.getValueType().isVector()) {
|
||||
if (PPCSubTarget->hasQPX())
|
||||
if (PPCSubTarget->hasQPX() || PPCSubTarget->hasSPE())
|
||||
return false;
|
||||
|
||||
EVT VecVT = LHS.getValueType();
|
||||
@ -3926,6 +3976,12 @@ bool PPCDAGToDAGISel::trySETCC(SDNode *N) {
|
||||
SDValue CCReg = SelectCC(LHS, RHS, CC, dl);
|
||||
SDValue IntCR;
|
||||
|
||||
// SPE e*cmp* instructions only set the 'gt' bit, so hard-code that
|
||||
// The correct compare instruction is already set by SelectCC()
|
||||
if (PPCSubTarget->hasSPE() && LHS.getValueType().isFloatingPoint()) {
|
||||
Idx = 1;
|
||||
}
|
||||
|
||||
// Force the ccreg into CR7.
|
||||
SDValue CR7Reg = CurDAG->getRegister(PPC::CR7, MVT::i32);
|
||||
|
||||
@ -4557,18 +4613,24 @@ void PPCDAGToDAGISel::Select(SDNode *N) {
|
||||
SelectCCOp = PPC::SELECT_CC_I4;
|
||||
else if (N->getValueType(0) == MVT::i64)
|
||||
SelectCCOp = PPC::SELECT_CC_I8;
|
||||
else if (N->getValueType(0) == MVT::f32)
|
||||
else if (N->getValueType(0) == MVT::f32) {
|
||||
if (PPCSubTarget->hasP8Vector())
|
||||
SelectCCOp = PPC::SELECT_CC_VSSRC;
|
||||
else if (PPCSubTarget->hasSPE())
|
||||
SelectCCOp = PPC::SELECT_CC_SPE4;
|
||||
else
|
||||
SelectCCOp = PPC::SELECT_CC_F4;
|
||||
else if (N->getValueType(0) == MVT::f64)
|
||||
} else if (N->getValueType(0) == MVT::f64) {
|
||||
if (PPCSubTarget->hasVSX())
|
||||
SelectCCOp = PPC::SELECT_CC_VSFRC;
|
||||
else if (PPCSubTarget->hasSPE())
|
||||
SelectCCOp = PPC::SELECT_CC_SPE;
|
||||
else
|
||||
SelectCCOp = PPC::SELECT_CC_F8;
|
||||
else if (N->getValueType(0) == MVT::f128)
|
||||
} else if (N->getValueType(0) == MVT::f128)
|
||||
SelectCCOp = PPC::SELECT_CC_F16;
|
||||
else if (PPCSubTarget->hasSPE())
|
||||
SelectCCOp = PPC::SELECT_CC_SPE;
|
||||
else if (PPCSubTarget->hasQPX() && N->getValueType(0) == MVT::v4f64)
|
||||
SelectCCOp = PPC::SELECT_CC_QFRC;
|
||||
else if (PPCSubTarget->hasQPX() && N->getValueType(0) == MVT::v4f32)
|
||||
@ -5352,6 +5414,8 @@ void PPCDAGToDAGISel::PeepholeCROps() {
|
||||
case PPC::SELECT_QFRC:
|
||||
case PPC::SELECT_QSRC:
|
||||
case PPC::SELECT_QBRC:
|
||||
case PPC::SELECT_SPE:
|
||||
case PPC::SELECT_SPE4:
|
||||
case PPC::SELECT_VRRC:
|
||||
case PPC::SELECT_VSFRC:
|
||||
case PPC::SELECT_VSSRC:
|
||||
@ -5671,6 +5735,8 @@ void PPCDAGToDAGISel::PeepholeCROps() {
|
||||
case PPC::SELECT_QFRC:
|
||||
case PPC::SELECT_QSRC:
|
||||
case PPC::SELECT_QBRC:
|
||||
case PPC::SELECT_SPE:
|
||||
case PPC::SELECT_SPE4:
|
||||
case PPC::SELECT_VRRC:
|
||||
case PPC::SELECT_VSFRC:
|
||||
case PPC::SELECT_VSSRC:
|
||||
|
@ -137,8 +137,13 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
|
||||
// Set up the register classes.
|
||||
addRegisterClass(MVT::i32, &PPC::GPRCRegClass);
|
||||
if (!useSoftFloat()) {
|
||||
addRegisterClass(MVT::f32, &PPC::F4RCRegClass);
|
||||
addRegisterClass(MVT::f64, &PPC::F8RCRegClass);
|
||||
if (hasSPE()) {
|
||||
addRegisterClass(MVT::f32, &PPC::SPE4RCRegClass);
|
||||
addRegisterClass(MVT::f64, &PPC::SPERCRegClass);
|
||||
} else {
|
||||
addRegisterClass(MVT::f32, &PPC::F4RCRegClass);
|
||||
addRegisterClass(MVT::f64, &PPC::F8RCRegClass);
|
||||
}
|
||||
}
|
||||
|
||||
// Match BITREVERSE to customized fast code sequence in the td file.
|
||||
@ -162,15 +167,17 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
|
||||
setIndexedLoadAction(ISD::PRE_INC, MVT::i16, Legal);
|
||||
setIndexedLoadAction(ISD::PRE_INC, MVT::i32, Legal);
|
||||
setIndexedLoadAction(ISD::PRE_INC, MVT::i64, Legal);
|
||||
setIndexedLoadAction(ISD::PRE_INC, MVT::f32, Legal);
|
||||
setIndexedLoadAction(ISD::PRE_INC, MVT::f64, Legal);
|
||||
setIndexedStoreAction(ISD::PRE_INC, MVT::i1, Legal);
|
||||
setIndexedStoreAction(ISD::PRE_INC, MVT::i8, Legal);
|
||||
setIndexedStoreAction(ISD::PRE_INC, MVT::i16, Legal);
|
||||
setIndexedStoreAction(ISD::PRE_INC, MVT::i32, Legal);
|
||||
setIndexedStoreAction(ISD::PRE_INC, MVT::i64, Legal);
|
||||
setIndexedStoreAction(ISD::PRE_INC, MVT::f32, Legal);
|
||||
setIndexedStoreAction(ISD::PRE_INC, MVT::f64, Legal);
|
||||
if (!Subtarget.hasSPE()) {
|
||||
setIndexedLoadAction(ISD::PRE_INC, MVT::f32, Legal);
|
||||
setIndexedLoadAction(ISD::PRE_INC, MVT::f64, Legal);
|
||||
setIndexedStoreAction(ISD::PRE_INC, MVT::f32, Legal);
|
||||
setIndexedStoreAction(ISD::PRE_INC, MVT::f64, Legal);
|
||||
}
|
||||
|
||||
// PowerPC uses ADDC/ADDE/SUBC/SUBE to propagate carry.
|
||||
const MVT ScalarIntVTs[] = { MVT::i32, MVT::i64 };
|
||||
@ -266,13 +273,18 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
|
||||
setOperationAction(ISD::FSINCOS, MVT::f64, Expand);
|
||||
setOperationAction(ISD::FREM , MVT::f64, Expand);
|
||||
setOperationAction(ISD::FPOW , MVT::f64, Expand);
|
||||
setOperationAction(ISD::FMA , MVT::f64, Legal);
|
||||
setOperationAction(ISD::FSIN , MVT::f32, Expand);
|
||||
setOperationAction(ISD::FCOS , MVT::f32, Expand);
|
||||
setOperationAction(ISD::FSINCOS, MVT::f32, Expand);
|
||||
setOperationAction(ISD::FREM , MVT::f32, Expand);
|
||||
setOperationAction(ISD::FPOW , MVT::f32, Expand);
|
||||
setOperationAction(ISD::FMA , MVT::f32, Legal);
|
||||
if (Subtarget.hasSPE()) {
|
||||
setOperationAction(ISD::FMA , MVT::f64, Expand);
|
||||
setOperationAction(ISD::FMA , MVT::f32, Expand);
|
||||
} else {
|
||||
setOperationAction(ISD::FMA , MVT::f64, Legal);
|
||||
setOperationAction(ISD::FMA , MVT::f32, Legal);
|
||||
}
|
||||
|
||||
setOperationAction(ISD::FLT_ROUNDS_, MVT::i32, Custom);
|
||||
|
||||
@ -355,12 +367,19 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
|
||||
|
||||
setOperationAction(ISD::BR_JT, MVT::Other, Expand);
|
||||
|
||||
// PowerPC turns FP_TO_SINT into FCTIWZ and some load/stores.
|
||||
setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom);
|
||||
if (Subtarget.hasSPE()) {
|
||||
// SPE has built-in conversions
|
||||
setOperationAction(ISD::FP_TO_SINT, MVT::i32, Legal);
|
||||
setOperationAction(ISD::SINT_TO_FP, MVT::i32, Legal);
|
||||
setOperationAction(ISD::UINT_TO_FP, MVT::i32, Legal);
|
||||
} else {
|
||||
// PowerPC turns FP_TO_SINT into FCTIWZ and some load/stores.
|
||||
setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom);
|
||||
|
||||
// PowerPC does not have [U|S]INT_TO_FP
|
||||
setOperationAction(ISD::SINT_TO_FP, MVT::i32, Expand);
|
||||
setOperationAction(ISD::UINT_TO_FP, MVT::i32, Expand);
|
||||
// PowerPC does not have [U|S]INT_TO_FP
|
||||
setOperationAction(ISD::SINT_TO_FP, MVT::i32, Expand);
|
||||
setOperationAction(ISD::UINT_TO_FP, MVT::i32, Expand);
|
||||
}
|
||||
|
||||
if (Subtarget.hasDirectMove() && isPPC64) {
|
||||
setOperationAction(ISD::BITCAST, MVT::f32, Legal);
|
||||
@ -458,6 +477,12 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
|
||||
setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom);
|
||||
|
||||
// Comparisons that require checking two conditions.
|
||||
if (Subtarget.hasSPE()) {
|
||||
setCondCodeAction(ISD::SETO, MVT::f32, Expand);
|
||||
setCondCodeAction(ISD::SETO, MVT::f64, Expand);
|
||||
setCondCodeAction(ISD::SETUO, MVT::f32, Expand);
|
||||
setCondCodeAction(ISD::SETUO, MVT::f64, Expand);
|
||||
}
|
||||
setCondCodeAction(ISD::SETULT, MVT::f32, Expand);
|
||||
setCondCodeAction(ISD::SETULT, MVT::f64, Expand);
|
||||
setCondCodeAction(ISD::SETUGT, MVT::f32, Expand);
|
||||
@ -485,7 +510,10 @@ PPCTargetLowering::PPCTargetLowering(const PPCTargetMachine &TM,
|
||||
setOperationAction(ISD::SINT_TO_FP, MVT::i32, Custom);
|
||||
} else {
|
||||
// PowerPC does not have FP_TO_UINT on 32-bit implementations.
|
||||
setOperationAction(ISD::FP_TO_UINT, MVT::i32, Expand);
|
||||
if (Subtarget.hasSPE())
|
||||
setOperationAction(ISD::FP_TO_UINT, MVT::i32, Legal);
|
||||
else
|
||||
setOperationAction(ISD::FP_TO_UINT, MVT::i32, Expand);
|
||||
}
|
||||
|
||||
// With the instructions enabled under FPCVT, we can do everything.
|
||||
@ -1195,10 +1223,34 @@ unsigned PPCTargetLowering::getByValTypeAlignment(Type *Ty,
|
||||
return Align;
|
||||
}
|
||||
|
||||
unsigned PPCTargetLowering::getNumRegistersForCallingConv(LLVMContext &Context,
|
||||
EVT VT) const {
|
||||
if (Subtarget.hasSPE() && VT == MVT::f64)
|
||||
return 2;
|
||||
return PPCTargetLowering::getNumRegisters(Context, VT);
|
||||
}
|
||||
|
||||
MVT PPCTargetLowering::getRegisterTypeForCallingConv(LLVMContext &Context,
|
||||
EVT VT) const {
|
||||
if (Subtarget.hasSPE() && VT == MVT::f64)
|
||||
return MVT::i32;
|
||||
return PPCTargetLowering::getRegisterType(Context, VT);
|
||||
}
|
||||
|
||||
MVT PPCTargetLowering::getRegisterTypeForCallingConv(MVT VT) const {
|
||||
if (Subtarget.hasSPE() && VT == MVT::f64)
|
||||
return MVT::i32;
|
||||
return PPCTargetLowering::getRegisterType(VT);
|
||||
}
|
||||
|
||||
bool PPCTargetLowering::useSoftFloat() const {
|
||||
return Subtarget.useSoftFloat();
|
||||
}
|
||||
|
||||
bool PPCTargetLowering::hasSPE() const {
|
||||
return Subtarget.hasSPE();
|
||||
}
|
||||
|
||||
const char *PPCTargetLowering::getTargetNodeName(unsigned Opcode) const {
|
||||
switch ((PPCISD::NodeType)Opcode) {
|
||||
case PPCISD::FIRST_NUMBER: break;
|
||||
@ -3362,7 +3414,7 @@ SDValue PPCTargetLowering::LowerFormalArguments_32SVR4(
|
||||
// Reserve space for the linkage area on the stack.
|
||||
unsigned LinkageSize = Subtarget.getFrameLowering()->getLinkageSize();
|
||||
CCInfo.AllocateStack(LinkageSize, PtrByteSize);
|
||||
if (useSoftFloat())
|
||||
if (useSoftFloat() || hasSPE())
|
||||
CCInfo.PreAnalyzeFormalArguments(Ins);
|
||||
|
||||
CCInfo.AnalyzeFormalArguments(Ins, CC_PPC32_SVR4);
|
||||
@ -3386,12 +3438,16 @@ SDValue PPCTargetLowering::LowerFormalArguments_32SVR4(
|
||||
case MVT::f32:
|
||||
if (Subtarget.hasP8Vector())
|
||||
RC = &PPC::VSSRCRegClass;
|
||||
else if (Subtarget.hasSPE())
|
||||
RC = &PPC::SPE4RCRegClass;
|
||||
else
|
||||
RC = &PPC::F4RCRegClass;
|
||||
break;
|
||||
case MVT::f64:
|
||||
if (Subtarget.hasVSX())
|
||||
RC = &PPC::VSFRCRegClass;
|
||||
else if (Subtarget.hasSPE())
|
||||
RC = &PPC::SPERCRegClass;
|
||||
else
|
||||
RC = &PPC::F8RCRegClass;
|
||||
break;
|
||||
@ -3480,7 +3536,7 @@ SDValue PPCTargetLowering::LowerFormalArguments_32SVR4(
|
||||
};
|
||||
unsigned NumFPArgRegs = array_lengthof(FPArgRegs);
|
||||
|
||||
if (useSoftFloat())
|
||||
if (useSoftFloat() || hasSPE())
|
||||
NumFPArgRegs = 0;
|
||||
|
||||
FuncInfo->setVarArgsNumGPR(CCInfo.getFirstUnallocated(GPArgRegs));
|
||||
@ -10230,6 +10286,8 @@ PPCTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
|
||||
MI.getOpcode() == PPC::SELECT_CC_VSFRC ||
|
||||
MI.getOpcode() == PPC::SELECT_CC_VSSRC ||
|
||||
MI.getOpcode() == PPC::SELECT_CC_VSRC ||
|
||||
MI.getOpcode() == PPC::SELECT_CC_SPE4 ||
|
||||
MI.getOpcode() == PPC::SELECT_CC_SPE ||
|
||||
MI.getOpcode() == PPC::SELECT_I4 ||
|
||||
MI.getOpcode() == PPC::SELECT_I8 ||
|
||||
MI.getOpcode() == PPC::SELECT_F4 ||
|
||||
@ -10238,6 +10296,8 @@ PPCTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
|
||||
MI.getOpcode() == PPC::SELECT_QFRC ||
|
||||
MI.getOpcode() == PPC::SELECT_QSRC ||
|
||||
MI.getOpcode() == PPC::SELECT_QBRC ||
|
||||
MI.getOpcode() == PPC::SELECT_SPE ||
|
||||
MI.getOpcode() == PPC::SELECT_SPE4 ||
|
||||
MI.getOpcode() == PPC::SELECT_VRRC ||
|
||||
MI.getOpcode() == PPC::SELECT_VSFRC ||
|
||||
MI.getOpcode() == PPC::SELECT_VSSRC ||
|
||||
@ -10271,6 +10331,8 @@ PPCTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
|
||||
if (MI.getOpcode() == PPC::SELECT_I4 || MI.getOpcode() == PPC::SELECT_I8 ||
|
||||
MI.getOpcode() == PPC::SELECT_F4 || MI.getOpcode() == PPC::SELECT_F8 ||
|
||||
MI.getOpcode() == PPC::SELECT_F16 ||
|
||||
MI.getOpcode() == PPC::SELECT_SPE4 ||
|
||||
MI.getOpcode() == PPC::SELECT_SPE ||
|
||||
MI.getOpcode() == PPC::SELECT_QFRC ||
|
||||
MI.getOpcode() == PPC::SELECT_QSRC ||
|
||||
MI.getOpcode() == PPC::SELECT_QBRC ||
|
||||
@ -13264,14 +13326,21 @@ PPCTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
|
||||
// really care overly much here so just give them all the same reg classes.
|
||||
case 'd':
|
||||
case 'f':
|
||||
if (VT == MVT::f32 || VT == MVT::i32)
|
||||
return std::make_pair(0U, &PPC::F4RCRegClass);
|
||||
if (VT == MVT::f64 || VT == MVT::i64)
|
||||
return std::make_pair(0U, &PPC::F8RCRegClass);
|
||||
if (VT == MVT::v4f64 && Subtarget.hasQPX())
|
||||
return std::make_pair(0U, &PPC::QFRCRegClass);
|
||||
if (VT == MVT::v4f32 && Subtarget.hasQPX())
|
||||
return std::make_pair(0U, &PPC::QSRCRegClass);
|
||||
if (Subtarget.hasSPE()) {
|
||||
if (VT == MVT::f32 || VT == MVT::i32)
|
||||
return std::make_pair(0U, &PPC::SPE4RCRegClass);
|
||||
if (VT == MVT::f64 || VT == MVT::i64)
|
||||
return std::make_pair(0U, &PPC::SPERCRegClass);
|
||||
} else {
|
||||
if (VT == MVT::f32 || VT == MVT::i32)
|
||||
return std::make_pair(0U, &PPC::F4RCRegClass);
|
||||
if (VT == MVT::f64 || VT == MVT::i64)
|
||||
return std::make_pair(0U, &PPC::F8RCRegClass);
|
||||
if (VT == MVT::v4f64 && Subtarget.hasQPX())
|
||||
return std::make_pair(0U, &PPC::QFRCRegClass);
|
||||
if (VT == MVT::v4f32 && Subtarget.hasQPX())
|
||||
return std::make_pair(0U, &PPC::QSRCRegClass);
|
||||
}
|
||||
break;
|
||||
case 'v':
|
||||
if (VT == MVT::v4f64 && Subtarget.hasQPX())
|
||||
|
@ -574,6 +574,8 @@ namespace llvm {
|
||||
|
||||
bool useSoftFloat() const override;
|
||||
|
||||
bool hasSPE() const;
|
||||
|
||||
MVT getScalarShiftAmountTy(const DataLayout &, EVT) const override {
|
||||
return MVT::i32;
|
||||
}
|
||||
@ -869,6 +871,13 @@ namespace llvm {
|
||||
unsigned JTI,
|
||||
MCContext &Ctx) const override;
|
||||
|
||||
unsigned getNumRegistersForCallingConv(LLVMContext &Context,
|
||||
EVT VT) const override;
|
||||
|
||||
MVT getRegisterTypeForCallingConv(MVT VT) const;
|
||||
MVT getRegisterTypeForCallingConv(LLVMContext &Context,
|
||||
EVT VT) const;
|
||||
|
||||
private:
|
||||
struct ReuseLoadInfo {
|
||||
SDValue Ptr;
|
||||
|
@ -90,6 +90,8 @@ enum SpillOpcodeKey {
|
||||
SOK_QuadFloat4Spill,
|
||||
SOK_QuadBitSpill,
|
||||
SOK_SpillToVSR,
|
||||
SOK_SPESpill,
|
||||
SOK_SPE4Spill,
|
||||
SOK_LastOpcodeSpill // This must be last on the enum.
|
||||
};
|
||||
|
||||
@ -949,8 +951,19 @@ void PPCInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
|
||||
BuildMI(MBB, I, DL, get(PPC::MFVSRD), DestReg).addReg(SrcReg);
|
||||
getKillRegState(KillSrc);
|
||||
return;
|
||||
} else if (PPC::SPERCRegClass.contains(SrcReg) &&
|
||||
PPC::SPE4RCRegClass.contains(DestReg)) {
|
||||
BuildMI(MBB, I, DL, get(PPC::EFSCFD), DestReg).addReg(SrcReg);
|
||||
getKillRegState(KillSrc);
|
||||
return;
|
||||
} else if (PPC::SPE4RCRegClass.contains(SrcReg) &&
|
||||
PPC::SPERCRegClass.contains(DestReg)) {
|
||||
BuildMI(MBB, I, DL, get(PPC::EFDCFS), DestReg).addReg(SrcReg);
|
||||
getKillRegState(KillSrc);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
unsigned Opc;
|
||||
if (PPC::GPRCRegClass.contains(DestReg, SrcReg))
|
||||
Opc = PPC::OR;
|
||||
@ -983,6 +996,8 @@ void PPCInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
|
||||
Opc = PPC::QVFMRb;
|
||||
else if (PPC::CRBITRCRegClass.contains(DestReg, SrcReg))
|
||||
Opc = PPC::CROR;
|
||||
else if (PPC::SPERCRegClass.contains(DestReg, SrcReg))
|
||||
Opc = PPC::EVOR;
|
||||
else
|
||||
llvm_unreachable("Impossible reg-to-reg copy");
|
||||
|
||||
@ -1011,6 +1026,10 @@ unsigned PPCInstrInfo::getStoreOpcodeForSpill(unsigned Reg,
|
||||
OpcodeIndex = SOK_Float8Spill;
|
||||
} else if (PPC::F4RCRegClass.hasSubClassEq(RC)) {
|
||||
OpcodeIndex = SOK_Float4Spill;
|
||||
} else if (PPC::SPERCRegClass.hasSubClassEq(RC)) {
|
||||
OpcodeIndex = SOK_SPESpill;
|
||||
} else if (PPC::SPE4RCRegClass.hasSubClassEq(RC)) {
|
||||
OpcodeIndex = SOK_SPE4Spill;
|
||||
} else if (PPC::CRRCRegClass.hasSubClassEq(RC)) {
|
||||
OpcodeIndex = SOK_CRSpill;
|
||||
} else if (PPC::CRBITRCRegClass.hasSubClassEq(RC)) {
|
||||
@ -1093,6 +1112,10 @@ PPCInstrInfo::getLoadOpcodeForSpill(unsigned Reg,
|
||||
OpcodeIndex = SOK_Float8Spill;
|
||||
} else if (PPC::F4RCRegClass.hasSubClassEq(RC)) {
|
||||
OpcodeIndex = SOK_Float4Spill;
|
||||
} else if (PPC::SPERCRegClass.hasSubClassEq(RC)) {
|
||||
OpcodeIndex = SOK_SPESpill;
|
||||
} else if (PPC::SPE4RCRegClass.hasSubClassEq(RC)) {
|
||||
OpcodeIndex = SOK_SPE4Spill;
|
||||
} else if (PPC::CRRCRegClass.hasSubClassEq(RC)) {
|
||||
OpcodeIndex = SOK_CRSpill;
|
||||
} else if (PPC::CRBITRCRegClass.hasSubClassEq(RC)) {
|
||||
@ -2321,7 +2344,7 @@ const unsigned *PPCInstrInfo::getStoreOpcodesForSpillArray() const {
|
||||
{PPC::STW, PPC::STD, PPC::STFD, PPC::STFS, PPC::SPILL_CR,
|
||||
PPC::SPILL_CRBIT, PPC::STVX, PPC::STXVD2X, PPC::STXSDX, PPC::STXSSPX,
|
||||
PPC::SPILL_VRSAVE, PPC::QVSTFDX, PPC::QVSTFSXs, PPC::QVSTFDXb,
|
||||
PPC::SPILLTOVSR_ST},
|
||||
PPC::SPILLTOVSR_ST, PPC::EVSTDD, PPC::SPESTW},
|
||||
// Power 9
|
||||
{PPC::STW, PPC::STD, PPC::STFD, PPC::STFS, PPC::SPILL_CR,
|
||||
PPC::SPILL_CRBIT, PPC::STVX, PPC::STXV, PPC::DFSTOREf64, PPC::DFSTOREf32,
|
||||
@ -2337,7 +2360,7 @@ const unsigned *PPCInstrInfo::getLoadOpcodesForSpillArray() const {
|
||||
{PPC::LWZ, PPC::LD, PPC::LFD, PPC::LFS, PPC::RESTORE_CR,
|
||||
PPC::RESTORE_CRBIT, PPC::LVX, PPC::LXVD2X, PPC::LXSDX, PPC::LXSSPX,
|
||||
PPC::RESTORE_VRSAVE, PPC::QVLFDX, PPC::QVLFSXs, PPC::QVLFDXb,
|
||||
PPC::SPILLTOVSR_LD},
|
||||
PPC::SPILLTOVSR_LD, PPC::EVLDD, PPC::SPELWZ},
|
||||
// Power 9
|
||||
{PPC::LWZ, PPC::LD, PPC::LFD, PPC::LFS, PPC::RESTORE_CR,
|
||||
PPC::RESTORE_CRBIT, PPC::LVX, PPC::LXV, PPC::DFLOADf64, PPC::DFLOADf32,
|
||||
|
@ -544,6 +544,19 @@ def crrc0 : RegisterOperand<CRRC0> {
|
||||
let ParserMatchClass = PPCRegCRRCAsmOperand;
|
||||
}
|
||||
|
||||
def PPCRegSPERCAsmOperand : AsmOperandClass {
|
||||
let Name = "RegSPERC"; let PredicateMethod = "isRegNumber";
|
||||
}
|
||||
def sperc : RegisterOperand<SPERC> {
|
||||
let ParserMatchClass = PPCRegSPERCAsmOperand;
|
||||
}
|
||||
def PPCRegSPE4RCAsmOperand : AsmOperandClass {
|
||||
let Name = "RegSPE4RC"; let PredicateMethod = "isRegNumber";
|
||||
}
|
||||
def spe4rc : RegisterOperand<SPE4RC> {
|
||||
let ParserMatchClass = PPCRegSPE4RCAsmOperand;
|
||||
}
|
||||
|
||||
def PPCU1ImmAsmOperand : AsmOperandClass {
|
||||
let Name = "U1Imm"; let PredicateMethod = "isU1Imm";
|
||||
let RenderMethod = "addImmOperands";
|
||||
@ -894,6 +907,7 @@ def NaNsFPMath : Predicate<"!TM.Options.NoNaNsFPMath">;
|
||||
def HasBPERMD : Predicate<"PPCSubTarget->hasBPERMD()">;
|
||||
def HasExtDiv : Predicate<"PPCSubTarget->hasExtDiv()">;
|
||||
def IsISA3_0 : Predicate<"PPCSubTarget->isISA3_0()">;
|
||||
def HasFPU : Predicate<"PPCSubTarget->hasFPU()">;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// PowerPC Multiclass Definitions.
|
||||
@ -1234,6 +1248,7 @@ let usesCustomInserter = 1, // Expanded after instruction selection.
|
||||
def SELECT_I8 : Pseudo<(outs g8rc:$dst), (ins crbitrc:$cond,
|
||||
g8rc_nox0:$T, g8rc_nox0:$F), "#SELECT_I8",
|
||||
[(set i64:$dst, (select i1:$cond, i64:$T, i64:$F))]>;
|
||||
let Predicates = [HasFPU] in {
|
||||
def SELECT_F4 : Pseudo<(outs f4rc:$dst), (ins crbitrc:$cond,
|
||||
f4rc:$T, f4rc:$F), "#SELECT_F4",
|
||||
[(set f32:$dst, (select i1:$cond, f32:$T, f32:$F))]>;
|
||||
@ -1243,6 +1258,7 @@ let usesCustomInserter = 1, // Expanded after instruction selection.
|
||||
def SELECT_F16 : Pseudo<(outs vrrc:$dst), (ins crbitrc:$cond,
|
||||
vrrc:$T, vrrc:$F), "#SELECT_F16",
|
||||
[(set f128:$dst, (select i1:$cond, f128:$T, f128:$F))]>;
|
||||
}
|
||||
def SELECT_VRRC: Pseudo<(outs vrrc:$dst), (ins crbitrc:$cond,
|
||||
vrrc:$T, vrrc:$F), "#SELECT_VRRC",
|
||||
[(set v4i32:$dst,
|
||||
@ -1836,12 +1852,14 @@ def LWZ : DForm_1<32, (outs gprc:$rD), (ins memri:$src),
|
||||
"lwz $rD, $src", IIC_LdStLoad,
|
||||
[(set i32:$rD, (load iaddr:$src))]>;
|
||||
|
||||
let Predicates = [HasFPU] in {
|
||||
def LFS : DForm_1<48, (outs f4rc:$rD), (ins memri:$src),
|
||||
"lfs $rD, $src", IIC_LdStLFD,
|
||||
[(set f32:$rD, (load iaddr:$src))]>;
|
||||
def LFD : DForm_1<50, (outs f8rc:$rD), (ins memri:$src),
|
||||
"lfd $rD, $src", IIC_LdStLFD,
|
||||
[(set f64:$rD, (load iaddr:$src))]>;
|
||||
}
|
||||
|
||||
|
||||
// Unindexed (r+i) Loads with Update (preinc).
|
||||
@ -1866,6 +1884,7 @@ def LWZU : DForm_1<33, (outs gprc:$rD, ptr_rc_nor0:$ea_result), (ins memri:$addr
|
||||
[]>, RegConstraint<"$addr.reg = $ea_result">,
|
||||
NoEncode<"$ea_result">;
|
||||
|
||||
let Predicates = [HasFPU] in {
|
||||
def LFSU : DForm_1<49, (outs f4rc:$rD, ptr_rc_nor0:$ea_result), (ins memri:$addr),
|
||||
"lfsu $rD, $addr", IIC_LdStLFDU,
|
||||
[]>, RegConstraint<"$addr.reg = $ea_result">,
|
||||
@ -1875,6 +1894,7 @@ def LFDU : DForm_1<51, (outs f8rc:$rD, ptr_rc_nor0:$ea_result), (ins memri:$addr
|
||||
"lfdu $rD, $addr", IIC_LdStLFDU,
|
||||
[]>, RegConstraint<"$addr.reg = $ea_result">,
|
||||
NoEncode<"$ea_result">;
|
||||
}
|
||||
|
||||
|
||||
// Indexed (r+r) Loads with Update (preinc).
|
||||
@ -1902,6 +1922,7 @@ def LWZUX : XForm_1_memOp<31, 55, (outs gprc:$rD, ptr_rc_nor0:$ea_result),
|
||||
[]>, RegConstraint<"$addr.ptrreg = $ea_result">,
|
||||
NoEncode<"$ea_result">;
|
||||
|
||||
let Predicates = [HasFPU] in {
|
||||
def LFSUX : XForm_1_memOp<31, 567, (outs f4rc:$rD, ptr_rc_nor0:$ea_result),
|
||||
(ins memrr:$addr),
|
||||
"lfsux $rD, $addr", IIC_LdStLFDUX,
|
||||
@ -1915,6 +1936,7 @@ def LFDUX : XForm_1_memOp<31, 631, (outs f8rc:$rD, ptr_rc_nor0:$ea_result),
|
||||
NoEncode<"$ea_result">;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Indexed (r+r) Loads.
|
||||
//
|
||||
@ -1939,6 +1961,7 @@ def LWBRX : XForm_1_memOp<31, 534, (outs gprc:$rD), (ins memrr:$src),
|
||||
"lwbrx $rD, $src", IIC_LdStLoad,
|
||||
[(set i32:$rD, (PPClbrx xoaddr:$src, i32))]>;
|
||||
|
||||
let Predicates = [HasFPU] in {
|
||||
def LFSX : XForm_25_memOp<31, 535, (outs f4rc:$frD), (ins memrr:$src),
|
||||
"lfsx $frD, $src", IIC_LdStLFD,
|
||||
[(set f32:$frD, (load xaddr:$src))]>;
|
||||
@ -1953,6 +1976,7 @@ def LFIWZX : XForm_25_memOp<31, 887, (outs f8rc:$frD), (ins memrr:$src),
|
||||
"lfiwzx $frD, $src", IIC_LdStLFD,
|
||||
[(set f64:$frD, (PPClfiwzx xoaddr:$src))]>;
|
||||
}
|
||||
}
|
||||
|
||||
// Load Multiple
|
||||
def LMW : DForm_1<46, (outs gprc:$rD), (ins memri:$src),
|
||||
@ -1973,6 +1997,7 @@ def STH : DForm_1<44, (outs), (ins gprc:$rS, memri:$src),
|
||||
def STW : DForm_1<36, (outs), (ins gprc:$rS, memri:$src),
|
||||
"stw $rS, $src", IIC_LdStStore,
|
||||
[(store i32:$rS, iaddr:$src)]>;
|
||||
let Predicates = [HasFPU] in {
|
||||
def STFS : DForm_1<52, (outs), (ins f4rc:$rS, memri:$dst),
|
||||
"stfs $rS, $dst", IIC_LdStSTFD,
|
||||
[(store f32:$rS, iaddr:$dst)]>;
|
||||
@ -1980,6 +2005,7 @@ def STFD : DForm_1<54, (outs), (ins f8rc:$rS, memri:$dst),
|
||||
"stfd $rS, $dst", IIC_LdStSTFD,
|
||||
[(store f64:$rS, iaddr:$dst)]>;
|
||||
}
|
||||
}
|
||||
|
||||
// Unindexed (r+i) Stores with Update (preinc).
|
||||
let PPC970_Unit = 2, mayStore = 1, mayLoad = 0 in {
|
||||
@ -1992,6 +2018,7 @@ def STHU : DForm_1<45, (outs ptr_rc_nor0:$ea_res), (ins gprc:$rS, memri:$dst),
|
||||
def STWU : DForm_1<37, (outs ptr_rc_nor0:$ea_res), (ins gprc:$rS, memri:$dst),
|
||||
"stwu $rS, $dst", IIC_LdStStoreUpd, []>,
|
||||
RegConstraint<"$dst.reg = $ea_res">, NoEncode<"$ea_res">;
|
||||
let Predicates = [HasFPU] in {
|
||||
def STFSU : DForm_1<53, (outs ptr_rc_nor0:$ea_res), (ins f4rc:$rS, memri:$dst),
|
||||
"stfsu $rS, $dst", IIC_LdStSTFDU, []>,
|
||||
RegConstraint<"$dst.reg = $ea_res">, NoEncode<"$ea_res">;
|
||||
@ -1999,6 +2026,7 @@ def STFDU : DForm_1<55, (outs ptr_rc_nor0:$ea_res), (ins f8rc:$rS, memri:$dst),
|
||||
"stfdu $rS, $dst", IIC_LdStSTFDU, []>,
|
||||
RegConstraint<"$dst.reg = $ea_res">, NoEncode<"$ea_res">;
|
||||
}
|
||||
}
|
||||
|
||||
// Patterns to match the pre-inc stores. We can't put the patterns on
|
||||
// the instruction definitions directly as ISel wants the address base
|
||||
@ -2038,6 +2066,7 @@ def STWBRX: XForm_8_memOp<31, 662, (outs), (ins gprc:$rS, memrr:$dst),
|
||||
[(PPCstbrx i32:$rS, xoaddr:$dst, i32)]>,
|
||||
PPC970_DGroup_Cracked;
|
||||
|
||||
let Predicates = [HasFPU] in {
|
||||
def STFIWX: XForm_28_memOp<31, 983, (outs), (ins f8rc:$frS, memrr:$dst),
|
||||
"stfiwx $frS, $dst", IIC_LdStSTFD,
|
||||
[(PPCstfiwx f64:$frS, xoaddr:$dst)]>;
|
||||
@ -2049,6 +2078,7 @@ def STFDX : XForm_28_memOp<31, 727, (outs), (ins f8rc:$frS, memrr:$dst),
|
||||
"stfdx $frS, $dst", IIC_LdStSTFD,
|
||||
[(store f64:$frS, xaddr:$dst)]>;
|
||||
}
|
||||
}
|
||||
|
||||
// Indexed (r+r) Stores with Update (preinc).
|
||||
let PPC970_Unit = 2, mayStore = 1, mayLoad = 0 in {
|
||||
@ -2070,6 +2100,7 @@ def STWUX : XForm_8_memOp<31, 183, (outs ptr_rc_nor0:$ea_res),
|
||||
RegConstraint<"$dst.ptrreg = $ea_res">,
|
||||
NoEncode<"$ea_res">,
|
||||
PPC970_DGroup_Cracked;
|
||||
let Predicates = [HasFPU] in {
|
||||
def STFSUX: XForm_8_memOp<31, 695, (outs ptr_rc_nor0:$ea_res),
|
||||
(ins f4rc:$rS, memrr:$dst),
|
||||
"stfsux $rS, $dst", IIC_LdStSTFDU, []>,
|
||||
@ -2083,6 +2114,7 @@ def STFDUX: XForm_8_memOp<31, 759, (outs ptr_rc_nor0:$ea_res),
|
||||
NoEncode<"$ea_res">,
|
||||
PPC970_DGroup_Cracked;
|
||||
}
|
||||
}
|
||||
|
||||
// Patterns to match the pre-inc stores. We can't put the patterns on
|
||||
// the instruction definitions directly as ISel wants the address base
|
||||
@ -2093,10 +2125,12 @@ def : Pat<(pre_truncsti16 i32:$rS, iPTR:$ptrreg, iPTR:$ptroff),
|
||||
(STHUX $rS, $ptrreg, $ptroff)>;
|
||||
def : Pat<(pre_store i32:$rS, iPTR:$ptrreg, iPTR:$ptroff),
|
||||
(STWUX $rS, $ptrreg, $ptroff)>;
|
||||
let Predicates = [HasFPU] in {
|
||||
def : Pat<(pre_store f32:$rS, iPTR:$ptrreg, iPTR:$ptroff),
|
||||
(STFSUX $rS, $ptrreg, $ptroff)>;
|
||||
def : Pat<(pre_store f64:$rS, iPTR:$ptrreg, iPTR:$ptroff),
|
||||
(STFDUX $rS, $ptrreg, $ptroff)>;
|
||||
}
|
||||
|
||||
// Store Multiple
|
||||
def STMW : DForm_1<47, (outs), (ins gprc:$rS, memri:$dst),
|
||||
@ -2280,7 +2314,7 @@ let isCompare = 1, hasSideEffects = 0 in {
|
||||
"cmplw $crD, $rA, $rB", IIC_IntCompare>;
|
||||
}
|
||||
}
|
||||
let PPC970_Unit = 3 in { // FPU Operations.
|
||||
let PPC970_Unit = 3, Predicates = [HasFPU] in { // FPU Operations.
|
||||
//def FCMPO : XForm_17<63, 32, (outs CRRC:$crD), (ins FPRC:$fA, FPRC:$fB),
|
||||
// "fcmpo $crD, $fA, $fB", IIC_FPCompare>;
|
||||
let isCompare = 1, hasSideEffects = 0 in {
|
||||
@ -2358,13 +2392,13 @@ let Uses = [RM] in {
|
||||
/// often coalesced away and we don't want the dispatch group builder to think
|
||||
/// that they will fill slots (which could cause the load of a LSU reject to
|
||||
/// sneak into a d-group with a store).
|
||||
let hasSideEffects = 0 in
|
||||
let hasSideEffects = 0, Predicates = [HasFPU] in
|
||||
defm FMR : XForm_26r<63, 72, (outs f4rc:$frD), (ins f4rc:$frB),
|
||||
"fmr", "$frD, $frB", IIC_FPGeneral,
|
||||
[]>, // (set f32:$frD, f32:$frB)
|
||||
PPC970_Unit_Pseudo;
|
||||
|
||||
let PPC970_Unit = 3, hasSideEffects = 0 in { // FPU Operations.
|
||||
let PPC970_Unit = 3, hasSideEffects = 0, Predicates = [HasFPU] in { // FPU Operations.
|
||||
// These are artificially split into two different forms, for 4/8 byte FP.
|
||||
defm FABSS : XForm_26r<63, 264, (outs f4rc:$frD), (ins f4rc:$frB),
|
||||
"fabs", "$frD, $frB", IIC_FPGeneral,
|
||||
@ -2613,6 +2647,7 @@ def MCRXRX : X_BF3<31, 576, (outs crrc:$BF), (ins),
|
||||
"mcrxrx $BF", IIC_BrMCRX>, Requires<[IsISA3_0]>;
|
||||
} // hasSideEffects = 0
|
||||
|
||||
let Predicates = [HasFPU] in {
|
||||
// Pseudo instruction to perform FADD in round-to-zero mode.
|
||||
let usesCustomInserter = 1, Uses = [RM] in {
|
||||
def FADDrtz: Pseudo<(outs f8rc:$FRT), (ins f8rc:$FRA, f8rc:$FRB), "",
|
||||
@ -2672,6 +2707,7 @@ let Uses = [RM] in {
|
||||
"mffsl $rT", IIC_IntMFFS, []>,
|
||||
PPC970_DGroup_Single, PPC970_Unit_FPU;
|
||||
}
|
||||
}
|
||||
|
||||
let Predicates = [IsISA3_0] in {
|
||||
def MODSW : XForm_8<31, 779, (outs gprc:$rT), (ins gprc:$rA, gprc:$rB),
|
||||
@ -2769,7 +2805,7 @@ defm SUBFZE : XOForm_3rc<31, 200, 0, (outs gprc:$rT), (ins gprc:$rA),
|
||||
// A-Form instructions. Most of the instructions executed in the FPU are of
|
||||
// this type.
|
||||
//
|
||||
let PPC970_Unit = 3, hasSideEffects = 0 in { // FPU Operations.
|
||||
let PPC970_Unit = 3, hasSideEffects = 0, Predicates = [HasFPU] in { // FPU Operations.
|
||||
let Uses = [RM] in {
|
||||
let isCommutable = 1 in {
|
||||
defm FMADD : AForm_1r<63, 29,
|
||||
@ -3095,6 +3131,7 @@ def : Pat<(extloadi16 iaddr:$src),
|
||||
(LHZ iaddr:$src)>;
|
||||
def : Pat<(extloadi16 xaddr:$src),
|
||||
(LHZX xaddr:$src)>;
|
||||
let Predicates = [HasFPU] in {
|
||||
def : Pat<(f64 (extloadf32 iaddr:$src)),
|
||||
(COPY_TO_REGCLASS (LFS iaddr:$src), F8RC)>;
|
||||
def : Pat<(f64 (extloadf32 xaddr:$src)),
|
||||
@ -3102,6 +3139,7 @@ def : Pat<(f64 (extloadf32 xaddr:$src)),
|
||||
|
||||
def : Pat<(f64 (fpextend f32:$src)),
|
||||
(COPY_TO_REGCLASS $src, F8RC)>;
|
||||
}
|
||||
|
||||
// Only seq_cst fences require the heavyweight sync (SYNC 0).
|
||||
// All others can use the lightweight sync (SYNC 1).
|
||||
@ -3113,6 +3151,7 @@ def : Pat<(atomic_fence (i32 7), (imm)), (SYNC 0)>, Requires<[HasSYNC]>;
|
||||
def : Pat<(atomic_fence (imm), (imm)), (SYNC 1)>, Requires<[HasSYNC]>;
|
||||
def : Pat<(atomic_fence (imm), (imm)), (MSYNC)>, Requires<[HasOnlyMSYNC]>;
|
||||
|
||||
let Predicates = [HasFPU] in {
|
||||
// Additional FNMSUB patterns: -a*c + b == -(a*c - b)
|
||||
def : Pat<(fma (fneg f64:$A), f64:$C, f64:$B),
|
||||
(FNMSUB $A, $C, $B)>;
|
||||
@ -3128,6 +3167,7 @@ def : Pat<(fcopysign f64:$frB, f32:$frA),
|
||||
(FCPSGND (COPY_TO_REGCLASS $frA, F8RC), $frB)>;
|
||||
def : Pat<(fcopysign f32:$frB, f64:$frA),
|
||||
(FCPSGNS (COPY_TO_REGCLASS $frA, F4RC), $frB)>;
|
||||
}
|
||||
|
||||
include "PPCInstrAltivec.td"
|
||||
include "PPCInstrSPE.td"
|
||||
@ -3570,6 +3610,7 @@ defm : CRNotPat<(i1 (setcc i64:$s1, i64:$s2, SETNE)),
|
||||
(EXTRACT_SUBREG (CMPD $s1, $s2), sub_eq)>;
|
||||
|
||||
// SETCC for f32.
|
||||
let Predicates = [HasFPU] in {
|
||||
def : Pat<(i1 (setcc f32:$s1, f32:$s2, SETOLT)),
|
||||
(EXTRACT_SUBREG (FCMPUS $s1, $s2), sub_lt)>;
|
||||
def : Pat<(i1 (setcc f32:$s1, f32:$s2, SETLT)),
|
||||
@ -3662,6 +3703,65 @@ defm : CRNotPat<(i1 (setcc f128:$s1, f128:$s2, SETNE)),
|
||||
defm : CRNotPat<(i1 (setcc f128:$s1, f128:$s2, SETO)),
|
||||
(EXTRACT_SUBREG (XSCMPUQP $s1, $s2), sub_un)>;
|
||||
|
||||
}
|
||||
|
||||
// This must be in this file because it relies on patterns defined in this file
|
||||
// after the inclusion of the instruction sets.
|
||||
let Predicates = [HasSPE] in {
|
||||
// SETCC for f32.
|
||||
def : Pat<(i1 (setcc f32:$s1, f32:$s2, SETOLT)),
|
||||
(EXTRACT_SUBREG (EFSCMPLT $s1, $s2), sub_gt)>;
|
||||
def : Pat<(i1 (setcc f32:$s1, f32:$s2, SETLT)),
|
||||
(EXTRACT_SUBREG (EFSCMPLT $s1, $s2), sub_gt)>;
|
||||
def : Pat<(i1 (setcc f32:$s1, f32:$s2, SETOGT)),
|
||||
(EXTRACT_SUBREG (EFSCMPGT $s1, $s2), sub_gt)>;
|
||||
def : Pat<(i1 (setcc f32:$s1, f32:$s2, SETGT)),
|
||||
(EXTRACT_SUBREG (EFSCMPGT $s1, $s2), sub_gt)>;
|
||||
def : Pat<(i1 (setcc f32:$s1, f32:$s2, SETOEQ)),
|
||||
(EXTRACT_SUBREG (EFSCMPEQ $s1, $s2), sub_gt)>;
|
||||
def : Pat<(i1 (setcc f32:$s1, f32:$s2, SETEQ)),
|
||||
(EXTRACT_SUBREG (EFSCMPEQ $s1, $s2), sub_gt)>;
|
||||
|
||||
defm : CRNotPat<(i1 (setcc f32:$s1, f32:$s2, SETUGE)),
|
||||
(EXTRACT_SUBREG (EFSCMPLT $s1, $s2), sub_gt)>;
|
||||
defm : CRNotPat<(i1 (setcc f32:$s1, f32:$s2, SETGE)),
|
||||
(EXTRACT_SUBREG (EFSCMPLT $s1, $s2), sub_gt)>;
|
||||
defm : CRNotPat<(i1 (setcc f32:$s1, f32:$s2, SETULE)),
|
||||
(EXTRACT_SUBREG (EFSCMPGT $s1, $s2), sub_gt)>;
|
||||
defm : CRNotPat<(i1 (setcc f32:$s1, f32:$s2, SETLE)),
|
||||
(EXTRACT_SUBREG (EFSCMPGT $s1, $s2), sub_gt)>;
|
||||
defm : CRNotPat<(i1 (setcc f32:$s1, f32:$s2, SETUNE)),
|
||||
(EXTRACT_SUBREG (EFSCMPEQ $s1, $s2), sub_gt)>;
|
||||
defm : CRNotPat<(i1 (setcc f32:$s1, f32:$s2, SETNE)),
|
||||
(EXTRACT_SUBREG (EFSCMPEQ $s1, $s2), sub_gt)>;
|
||||
|
||||
// SETCC for f64.
|
||||
def : Pat<(i1 (setcc f64:$s1, f64:$s2, SETOLT)),
|
||||
(EXTRACT_SUBREG (EFDCMPLT $s1, $s2), sub_gt)>;
|
||||
def : Pat<(i1 (setcc f64:$s1, f64:$s2, SETLT)),
|
||||
(EXTRACT_SUBREG (EFDCMPLT $s1, $s2), sub_gt)>;
|
||||
def : Pat<(i1 (setcc f64:$s1, f64:$s2, SETOGT)),
|
||||
(EXTRACT_SUBREG (EFDCMPGT $s1, $s2), sub_gt)>;
|
||||
def : Pat<(i1 (setcc f64:$s1, f64:$s2, SETGT)),
|
||||
(EXTRACT_SUBREG (EFDCMPGT $s1, $s2), sub_gt)>;
|
||||
def : Pat<(i1 (setcc f64:$s1, f64:$s2, SETOEQ)),
|
||||
(EXTRACT_SUBREG (EFDCMPEQ $s1, $s2), sub_gt)>;
|
||||
def : Pat<(i1 (setcc f64:$s1, f64:$s2, SETEQ)),
|
||||
(EXTRACT_SUBREG (EFDCMPEQ $s1, $s2), sub_gt)>;
|
||||
|
||||
defm : CRNotPat<(i1 (setcc f64:$s1, f64:$s2, SETUGE)),
|
||||
(EXTRACT_SUBREG (EFDCMPLT $s1, $s2), sub_gt)>;
|
||||
defm : CRNotPat<(i1 (setcc f64:$s1, f64:$s2, SETGE)),
|
||||
(EXTRACT_SUBREG (EFDCMPLT $s1, $s2), sub_gt)>;
|
||||
defm : CRNotPat<(i1 (setcc f64:$s1, f64:$s2, SETULE)),
|
||||
(EXTRACT_SUBREG (EFDCMPGT $s1, $s2), sub_gt)>;
|
||||
defm : CRNotPat<(i1 (setcc f64:$s1, f64:$s2, SETLE)),
|
||||
(EXTRACT_SUBREG (EFDCMPGT $s1, $s2), sub_gt)>;
|
||||
defm : CRNotPat<(i1 (setcc f64:$s1, f64:$s2, SETUNE)),
|
||||
(EXTRACT_SUBREG (EFDCMPEQ $s1, $s2), sub_gt)>;
|
||||
defm : CRNotPat<(i1 (setcc f64:$s1, f64:$s2, SETNE)),
|
||||
(EXTRACT_SUBREG (EFDCMPEQ $s1, $s2), sub_gt)>;
|
||||
}
|
||||
// match select on i1 variables:
|
||||
def : Pat<(i1 (select i1:$cond, i1:$tval, i1:$fval)),
|
||||
(CROR (CRAND $cond , $tval),
|
||||
@ -3744,6 +3844,7 @@ def : Pat<(i64 (selectcc i1:$lhs, i1:$rhs, i64:$tval, i64:$fval, SETUGT)),
|
||||
def : Pat<(i64 (selectcc i1:$lhs, i1:$rhs, i64:$tval, i64:$fval, SETNE)),
|
||||
(SELECT_I8 (CRXOR $lhs, $rhs), $tval, $fval)>;
|
||||
|
||||
let Predicates = [HasFPU] in {
|
||||
def : Pat<(f32 (selectcc i1:$lhs, i1:$rhs, f32:$tval, f32:$fval, SETLT)),
|
||||
(SELECT_F4 (CRANDC $lhs, $rhs), $tval, $fval)>;
|
||||
def : Pat<(f32 (selectcc i1:$lhs, i1:$rhs, f32:$tval, f32:$fval, SETULT)),
|
||||
@ -3785,6 +3886,7 @@ def : Pat<(f64 (selectcc i1:$lhs, i1:$rhs, f64:$tval, f64:$fval, SETUGT)),
|
||||
(SELECT_F8 (CRANDC $lhs, $rhs), $tval, $fval)>;
|
||||
def : Pat<(f64 (selectcc i1:$lhs, i1:$rhs, f64:$tval, f64:$fval, SETNE)),
|
||||
(SELECT_F8 (CRXOR $lhs, $rhs), $tval, $fval)>;
|
||||
}
|
||||
|
||||
def : Pat<(f128 (selectcc i1:$lhs, i1:$rhs, f128:$tval, f128:$fval, SETLT)),
|
||||
(SELECT_F16 (CRANDC $lhs, $rhs), $tval, $fval)>;
|
||||
@ -3937,6 +4039,7 @@ def MTFSFIo : XLForm_4<63, 134, (outs crrc:$BF), (ins i32imm:$U, i32imm:$W),
|
||||
def : InstAlias<"mtfsfi $BF, $U", (MTFSFI crrc:$BF, i32imm:$U, 0)>;
|
||||
def : InstAlias<"mtfsfi. $BF, $U", (MTFSFIo crrc:$BF, i32imm:$U, 0)>;
|
||||
|
||||
let Predicates = [HasFPU] in {
|
||||
def MTFSF : XFLForm_1<63, 711, (outs),
|
||||
(ins i32imm:$FLM, f8rc:$FRB, i32imm:$L, i32imm:$W),
|
||||
"mtfsf $FLM, $FRB, $L, $W", IIC_IntMFFS, []>;
|
||||
@ -3946,6 +4049,7 @@ def MTFSFo : XFLForm_1<63, 711, (outs),
|
||||
|
||||
def : InstAlias<"mtfsf $FLM, $FRB", (MTFSF i32imm:$FLM, f8rc:$FRB, 0, 0)>;
|
||||
def : InstAlias<"mtfsf. $FLM, $FRB", (MTFSFo i32imm:$FLM, f8rc:$FRB, 0, 0)>;
|
||||
}
|
||||
|
||||
def SLBIE : XForm_16b<31, 434, (outs), (ins gprc:$RB),
|
||||
"slbie $RB", IIC_SprSLBIE, []>;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -106,6 +106,12 @@ PPCRegisterInfo::PPCRegisterInfo(const PPCTargetMachine &TM)
|
||||
ImmToIdxMap[PPC::STXV] = PPC::STXVX;
|
||||
ImmToIdxMap[PPC::STXSD] = PPC::STXSDX;
|
||||
ImmToIdxMap[PPC::STXSSP] = PPC::STXSSPX;
|
||||
|
||||
// SPE
|
||||
ImmToIdxMap[PPC::EVLDD] = PPC::EVLDDX;
|
||||
ImmToIdxMap[PPC::EVSTDD] = PPC::EVSTDDX;
|
||||
ImmToIdxMap[PPC::SPESTW] = PPC::SPESTWX;
|
||||
ImmToIdxMap[PPC::SPELWZ] = PPC::SPELWZX;
|
||||
}
|
||||
|
||||
/// getPointerRegClass - Return the register class to use to hold pointers.
|
||||
@ -147,6 +153,9 @@ PPCRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
|
||||
if (TM.isPPC64() && MF->getInfo<PPCFunctionInfo>()->isSplitCSR())
|
||||
return CSR_SRV464_TLS_PE_SaveList;
|
||||
|
||||
if (Subtarget.hasSPE())
|
||||
return CSR_SVR432_SPE_SaveList;
|
||||
|
||||
// On PPC64, we might need to save r2 (but only if it is not reserved).
|
||||
bool SaveR2 = MF->getRegInfo().isAllocatable(PPC::X2);
|
||||
|
||||
@ -342,6 +351,8 @@ unsigned PPCRegisterInfo::getRegPressureLimit(const TargetRegisterClass *RC,
|
||||
return 0;
|
||||
case PPC::G8RC_NOX0RegClassID:
|
||||
case PPC::GPRC_NOR0RegClassID:
|
||||
case PPC::SPERCRegClassID:
|
||||
case PPC::SPE4RCRegClassID:
|
||||
case PPC::G8RCRegClassID:
|
||||
case PPC::GPRCRegClassID: {
|
||||
unsigned FP = TFI->hasFP(MF) ? 1 : 0;
|
||||
|
@ -38,6 +38,13 @@ class GP8<GPR SubReg, string n> : PPCReg<n> {
|
||||
let SubRegIndices = [sub_32];
|
||||
}
|
||||
|
||||
// SPE - One of the 32 64-bit general-purpose registers (SPE)
|
||||
class SPE<GPR SubReg, string n> : PPCReg<n> {
|
||||
let HWEncoding = SubReg.HWEncoding;
|
||||
let SubRegs = [SubReg];
|
||||
let SubRegIndices = [sub_32];
|
||||
}
|
||||
|
||||
// SPR - One of the 32-bit special-purpose registers
|
||||
class SPR<bits<10> num, string n> : PPCReg<n> {
|
||||
let HWEncoding{9-0} = num;
|
||||
@ -100,6 +107,12 @@ foreach Index = 0-31 in {
|
||||
DwarfRegNum<[Index, -2]>;
|
||||
}
|
||||
|
||||
// SPE registers
|
||||
foreach Index = 0-31 in {
|
||||
def S#Index : SPE<!cast<GPR>("R"#Index), "r"#Index>,
|
||||
DwarfRegNum<[!add(Index, 1200), !add(Index, 1200)]>;
|
||||
}
|
||||
|
||||
// Floating-point registers
|
||||
foreach Index = 0-31 in {
|
||||
def F#Index : FPR<Index, "f"#Index>,
|
||||
@ -208,6 +221,12 @@ def CTR8 : SPR<9, "ctr">, DwarfRegNum<[66, -2]>;
|
||||
// VRsave register
|
||||
def VRSAVE: SPR<256, "vrsave">, DwarfRegNum<[109]>;
|
||||
|
||||
// SPE extra registers
|
||||
// SPE Accumulator for multiply-accumulate SPE operations. Never directly
|
||||
// accessed, so there's no real encoding for it.
|
||||
def SPEACC: DwarfRegNum<[99, 111]>;
|
||||
def SPEFSCR: SPR<512, "spefscr">, DwarfRegNum<[612, 112]>;
|
||||
|
||||
def XER: SPR<1, "xer">, DwarfRegNum<[76]>;
|
||||
|
||||
// Carry bit. In the architecture this is really bit 0 of the XER register
|
||||
@ -276,6 +295,12 @@ def G8RC_NOX0 : RegisterClass<"PPC", [i64], 64, (add (sub G8RC, X0), ZERO8)> {
|
||||
}];
|
||||
}
|
||||
|
||||
def SPERC : RegisterClass<"PPC", [f64], 64, (add (sequence "S%u", 2, 12),
|
||||
(sequence "S%u", 30, 13),
|
||||
S31, S0, S1)>;
|
||||
|
||||
def SPE4RC : RegisterClass<"PPC", [f32], 32, (add GPRC)>;
|
||||
|
||||
// Allocate volatiles first, then non-volatiles in reverse order. With the SVR4
|
||||
// ABI the size of the Floating-point register save area is determined by the
|
||||
// allocated non-volatile register with the lowest register number, as FP
|
||||
|
@ -65,6 +65,7 @@ void PPCSubtarget::initializeEnvironment() {
|
||||
HasHardFloat = false;
|
||||
HasAltivec = false;
|
||||
HasSPE = false;
|
||||
HasFPU = false;
|
||||
HasQPX = false;
|
||||
HasVSX = false;
|
||||
HasP8Vector = false;
|
||||
@ -137,6 +138,16 @@ void PPCSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) {
|
||||
if (isDarwin())
|
||||
HasLazyResolverStubs = true;
|
||||
|
||||
if (HasSPE && IsPPC64)
|
||||
report_fatal_error( "SPE is only supported for 32-bit targets.\n", false);
|
||||
if (HasSPE && (HasAltivec || HasQPX || HasVSX || HasFPU))
|
||||
report_fatal_error(
|
||||
"SPE and traditional floating point cannot both be enabled.\n", false);
|
||||
|
||||
// If not SPE, set standard FPU
|
||||
if (!HasSPE)
|
||||
HasFPU = true;
|
||||
|
||||
// QPX requires a 32-byte aligned stack. Note that we need to do this if
|
||||
// we're compiling for a BG/Q system regardless of whether or not QPX
|
||||
// is enabled because external functions will assume this alignment.
|
||||
|
@ -95,6 +95,7 @@ protected:
|
||||
bool HasHardFloat;
|
||||
bool IsPPC64;
|
||||
bool HasAltivec;
|
||||
bool HasFPU;
|
||||
bool HasSPE;
|
||||
bool HasQPX;
|
||||
bool HasVSX;
|
||||
@ -240,6 +241,7 @@ public:
|
||||
bool hasFPCVT() const { return HasFPCVT; }
|
||||
bool hasAltivec() const { return HasAltivec; }
|
||||
bool hasSPE() const { return HasSPE; }
|
||||
bool hasFPU() const { return HasFPU; }
|
||||
bool hasQPX() const { return HasQPX; }
|
||||
bool hasVSX() const { return HasVSX; }
|
||||
bool hasP8Vector() const { return HasP8Vector; }
|
||||
|
@ -7,27 +7,27 @@ define i64 @__fixunstfdi(ppc_fp128 %a) nounwind readnone {
|
||||
; CHECK-NEXT: mflr 0
|
||||
; CHECK-NEXT: stw 0, 4(1)
|
||||
; CHECK-NEXT: stwu 1, -464(1)
|
||||
; CHECK-NEXT: lis 3, .LCPI0_0@ha
|
||||
; CHECK-NEXT: stfd 27, 424(1) # 8-byte Folded Spill
|
||||
; CHECK-NEXT: mfcr 12
|
||||
; CHECK-NEXT: lfs 27, .LCPI0_0@l(3)
|
||||
; CHECK-NEXT: lis 3, .LCPI0_0@ha
|
||||
; CHECK-NEXT: stw 29, 412(1) # 4-byte Folded Spill
|
||||
; CHECK-NEXT: stw 30, 416(1) # 4-byte Folded Spill
|
||||
; CHECK-NEXT: stw 12, 408(1)
|
||||
; CHECK-NEXT: stfd 27, 424(1) # 8-byte Folded Spill
|
||||
; CHECK-NEXT: stfd 28, 432(1) # 8-byte Folded Spill
|
||||
; CHECK-NEXT: stfd 29, 440(1) # 8-byte Folded Spill
|
||||
; CHECK-NEXT: stfd 30, 448(1) # 8-byte Folded Spill
|
||||
; CHECK-NEXT: stfd 31, 456(1) # 8-byte Folded Spill
|
||||
; CHECK-NEXT: fcmpu 0, 2, 27
|
||||
; CHECK-NEXT: stw 12, 408(1)
|
||||
; CHECK-NEXT: fcmpu 1, 1, 27
|
||||
; CHECK-NEXT: lfs 27, .LCPI0_0@l(3)
|
||||
; CHECK-NEXT: stfd 2, 376(1)
|
||||
; CHECK-NEXT: crand 20, 6, 0
|
||||
; CHECK-NEXT: stfd 1, 384(1)
|
||||
; CHECK-NEXT: cror 20, 4, 20
|
||||
; CHECK-NEXT: fcmpu 0, 2, 27
|
||||
; CHECK-NEXT: lwz 3, 380(1)
|
||||
; CHECK-NEXT: lwz 4, 376(1)
|
||||
; CHECK-NEXT: lwz 5, 388(1)
|
||||
; CHECK-NEXT: lwz 6, 384(1)
|
||||
; CHECK-NEXT: fcmpu 1, 1, 27
|
||||
; CHECK-NEXT: crand 20, 6, 0
|
||||
; CHECK-NEXT: cror 20, 4, 20
|
||||
; CHECK-NEXT: stw 3, 396(1)
|
||||
; CHECK-NEXT: stw 4, 392(1)
|
||||
; CHECK-NEXT: stw 5, 404(1)
|
||||
@ -293,14 +293,14 @@ define i64 @__fixunstfdi(ppc_fp128 %a) nounwind readnone {
|
||||
; CHECK-NEXT: .LBB0_15: # %bb3
|
||||
; CHECK-NEXT: mr 3, 30
|
||||
; CHECK-NEXT: .LBB0_16: # %bb5
|
||||
; CHECK-NEXT: lwz 12, 408(1)
|
||||
; CHECK-NEXT: lfd 31, 456(1) # 8-byte Folded Reload
|
||||
; CHECK-NEXT: lfd 30, 448(1) # 8-byte Folded Reload
|
||||
; CHECK-NEXT: mtcrf 32, 12 # cr2
|
||||
; CHECK-NEXT: lfd 29, 440(1) # 8-byte Folded Reload
|
||||
; CHECK-NEXT: lfd 28, 432(1) # 8-byte Folded Reload
|
||||
; CHECK-NEXT: lwz 12, 408(1)
|
||||
; CHECK-NEXT: lfd 27, 424(1) # 8-byte Folded Reload
|
||||
; CHECK-NEXT: lwz 30, 416(1) # 4-byte Folded Reload
|
||||
; CHECK-NEXT: mtcrf 32, 12 # cr2
|
||||
; CHECK-NEXT: lwz 29, 412(1) # 4-byte Folded Reload
|
||||
; CHECK-NEXT: lwz 0, 468(1)
|
||||
; CHECK-NEXT: addi 1, 1, 464
|
||||
|
@ -3,13 +3,16 @@
|
||||
; When fastisel better supports VSX fix up this test case.
|
||||
;
|
||||
; RUN: llc < %s -O0 -verify-machineinstrs -fast-isel-abort=1 -mtriple=powerpc64-unknown-linux-gnu -mcpu=pwr7 -mattr=-vsx | FileCheck %s --check-prefix=ELF64
|
||||
; RUN: llc < %s -O0 -verify-machineinstrs -fast-isel-abort=1 -mtriple=powerpc-unknown-linux-gnu -mcpu=e500 -mattr=spe | FileCheck %s --check-prefix=SPE
|
||||
define void @t1a(float %a) nounwind {
|
||||
entry:
|
||||
; ELF64: t1a
|
||||
; SPE: t1a
|
||||
%cmp = fcmp oeq float %a, 0.000000e+00
|
||||
; ELF64: addis
|
||||
; ELF64: lfs
|
||||
; ELF64: fcmpu
|
||||
; SPE: efscmpeq
|
||||
br i1 %cmp, label %if.then, label %if.end
|
||||
|
||||
if.then: ; preds = %entry
|
||||
@ -25,10 +28,12 @@ declare void @foo()
|
||||
define void @t1b(float %a) nounwind {
|
||||
entry:
|
||||
; ELF64: t1b
|
||||
; SPE: t1b
|
||||
%cmp = fcmp oeq float %a, -0.000000e+00
|
||||
; ELF64: addis
|
||||
; ELF64: lfs
|
||||
; ELF64: fcmpu
|
||||
; SPE: efscmpeq
|
||||
br i1 %cmp, label %if.then, label %if.end
|
||||
|
||||
if.then: ; preds = %entry
|
||||
@ -42,10 +47,12 @@ if.end: ; preds = %if.then, %entry
|
||||
define void @t2a(double %a) nounwind {
|
||||
entry:
|
||||
; ELF64: t2a
|
||||
; SPE: t2a
|
||||
%cmp = fcmp oeq double %a, 0.000000e+00
|
||||
; ELF64: addis
|
||||
; ELF64: lfd
|
||||
; ELF64: fcmpu
|
||||
; SPE: efdcmpeq
|
||||
br i1 %cmp, label %if.then, label %if.end
|
||||
|
||||
if.then: ; preds = %entry
|
||||
@ -59,10 +66,12 @@ if.end: ; preds = %if.then, %entry
|
||||
define void @t2b(double %a) nounwind {
|
||||
entry:
|
||||
; ELF64: t2b
|
||||
; SPE: t2b
|
||||
%cmp = fcmp oeq double %a, -0.000000e+00
|
||||
; ELF64: addis
|
||||
; ELF64: lfd
|
||||
; ELF64: fcmpu
|
||||
; SPE: efdcmpeq
|
||||
br i1 %cmp, label %if.then, label %if.end
|
||||
|
||||
if.then: ; preds = %entry
|
||||
|
@ -5,6 +5,7 @@
|
||||
; RUN: llc < %s -O0 -verify-machineinstrs -fast-isel-abort=1 -mtriple=powerpc64-unknown-linux-gnu -mcpu=pwr7 -mattr=-vsx | FileCheck %s
|
||||
; RUN: llc < %s -O0 -verify-machineinstrs -fast-isel-abort=1 -mtriple=powerpc64le-unknown-linux-gnu -mcpu=pwr8 -mattr=-vsx | FileCheck %s
|
||||
; RUN: llc < %s -O0 -verify-machineinstrs -mtriple=powerpc64-unknown-linux-gnu -mcpu=970 -mattr=-vsx | FileCheck %s --check-prefix=PPC970
|
||||
; RUN: llc < %s -O0 -verify-machineinstrs -mtriple=powerpc-unknown-linux-gnu -mcpu=e500 -mattr=spe | FileCheck %s --check-prefix=SPE
|
||||
|
||||
;; Tests for 970 don't use -fast-isel-abort=1 because we intentionally punt
|
||||
;; to SelectionDAG in some cases.
|
||||
@ -42,6 +43,7 @@ entry:
|
||||
; PPC970: lfd
|
||||
; PPC970: fcfid
|
||||
; PPC970: frsp
|
||||
; SPE: efscfsi
|
||||
store float %conv, float* %b.addr, align 4
|
||||
ret void
|
||||
}
|
||||
@ -61,6 +63,8 @@ entry:
|
||||
; PPC970: lfd
|
||||
; PPC970: fcfid
|
||||
; PPC970: frsp
|
||||
; SPE: extsh
|
||||
; SPE: efscfsi
|
||||
store float %conv, float* %b.addr, align 4
|
||||
ret void
|
||||
}
|
||||
@ -80,6 +84,8 @@ entry:
|
||||
; PPC970: lfd
|
||||
; PPC970: fcfid
|
||||
; PPC970: frsp
|
||||
; SPE: extsb
|
||||
; SPE: efscfsi
|
||||
store float %conv, float* %b.addr, align 4
|
||||
ret void
|
||||
}
|
||||
@ -99,6 +105,7 @@ entry:
|
||||
; PPC970: std
|
||||
; PPC970: lfd
|
||||
; PPC970: fcfid
|
||||
; SPE: efdcfsi
|
||||
store double %conv, double* %b.addr, align 8
|
||||
ret void
|
||||
}
|
||||
@ -133,6 +140,8 @@ entry:
|
||||
; PPC970: std
|
||||
; PPC970: lfd
|
||||
; PPC970: fcfid
|
||||
; SPE: extsh
|
||||
; SPE: efdcfsi
|
||||
store double %conv, double* %b.addr, align 8
|
||||
ret void
|
||||
}
|
||||
@ -151,6 +160,8 @@ entry:
|
||||
; PPC970: std
|
||||
; PPC970: lfd
|
||||
; PPC970: fcfid
|
||||
; SPE: extsb
|
||||
; SPE: efdcfsi
|
||||
store double %conv, double* %b.addr, align 8
|
||||
ret void
|
||||
}
|
||||
@ -185,6 +196,7 @@ entry:
|
||||
; CHECK: fcfidus
|
||||
; PPC970-NOT: lfiwzx
|
||||
; PPC970-NOT: fcfidus
|
||||
; SPE: efscfui
|
||||
store float %conv, float* %b.addr, align 4
|
||||
ret void
|
||||
}
|
||||
@ -204,6 +216,8 @@ entry:
|
||||
; PPC970: lfd
|
||||
; PPC970: fcfid
|
||||
; PPC970: frsp
|
||||
; SPE: clrlwi {{[0-9]+}}, {{[0-9]+}}, 16
|
||||
; SPE: efscfui
|
||||
store float %conv, float* %b.addr, align 4
|
||||
ret void
|
||||
}
|
||||
@ -223,6 +237,8 @@ entry:
|
||||
; PPC970: lfd
|
||||
; PPC970: fcfid
|
||||
; PPC970: frsp
|
||||
; SPE: clrlwi {{[0-9]+}}, {{[0-9]+}}, 24
|
||||
; SPE: efscfui
|
||||
store float %conv, float* %b.addr, align 4
|
||||
ret void
|
||||
}
|
||||
@ -254,6 +270,7 @@ entry:
|
||||
; CHECKLE: fcfidu
|
||||
; PPC970-NOT: lfiwzx
|
||||
; PPC970-NOT: fcfidu
|
||||
; SPE: efdcfui
|
||||
store double %conv, double* %b.addr, align 8
|
||||
ret void
|
||||
}
|
||||
@ -272,6 +289,8 @@ entry:
|
||||
; PPC970: std
|
||||
; PPC970: lfd
|
||||
; PPC970: fcfid
|
||||
; SPE: clrlwi {{[0-9]+}}, {{[0-9]+}}, 16
|
||||
; SPE: efdcfui
|
||||
store double %conv, double* %b.addr, align 8
|
||||
ret void
|
||||
}
|
||||
@ -290,6 +309,8 @@ entry:
|
||||
; PPC970: std
|
||||
; PPC970: lfd
|
||||
; PPC970: fcfid
|
||||
; SPE: clrlwi {{[0-9]+}}, {{[0-9]+}}, 24
|
||||
; SPE: efdcfui
|
||||
store double %conv, double* %b.addr, align 8
|
||||
ret void
|
||||
}
|
||||
@ -308,6 +329,7 @@ entry:
|
||||
; PPC970: fctiwz
|
||||
; PPC970: stfd
|
||||
; PPC970: lwa
|
||||
; SPE: efsctsi
|
||||
store i32 %conv, i32* %b.addr, align 4
|
||||
ret void
|
||||
}
|
||||
@ -340,6 +362,7 @@ entry:
|
||||
; PPC970: fctiwz
|
||||
; PPC970: stfd
|
||||
; PPC970: lwa
|
||||
; SPE: efdctsi
|
||||
store i32 %conv, i32* %b.addr, align 8
|
||||
ret void
|
||||
}
|
||||
@ -374,6 +397,7 @@ entry:
|
||||
; PPC970: fctidz
|
||||
; PPC970: stfd
|
||||
; PPC970: lwz
|
||||
; SPE: efsctui
|
||||
store i32 %conv, i32* %b.addr, align 4
|
||||
ret void
|
||||
}
|
||||
@ -404,6 +428,7 @@ entry:
|
||||
; PPC970: fctidz
|
||||
; PPC970: stfd
|
||||
; PPC970: lwz
|
||||
; SPE: efdctui
|
||||
store i32 %conv, i32* %b.addr, align 8
|
||||
ret void
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
; When fastisel better supports VSX fix up this test case.
|
||||
;
|
||||
; RUN: llc -relocation-model=static < %s -O0 -verify-machineinstrs -fast-isel -fast-isel-abort=1 -mattr=-vsx -mtriple=powerpc64-unknown-linux-gnu -mcpu=pwr7 | FileCheck %s --check-prefix=ELF64
|
||||
; RUN: llc -relocation-model=static < %s -O0 -verify-machineinstrs -fast-isel -fast-isel-abort=1 -mattr=spe -mtriple=powerpc-unknown-linux-gnu -mcpu=e500 | FileCheck %s --check-prefix=SPE
|
||||
|
||||
; This test verifies that load/store instructions are properly generated,
|
||||
; and that they pass MI verification.
|
||||
@ -62,19 +63,25 @@ define i64 @t4() nounwind {
|
||||
|
||||
define float @t5() nounwind {
|
||||
; ELF64: t5
|
||||
; SPE: t5
|
||||
%1 = load float, float* @e, align 4
|
||||
; ELF64: lfs
|
||||
; SPE: lwz
|
||||
%2 = fadd float %1, 1.0
|
||||
; ELF64: fadds
|
||||
; SPE: efsadd
|
||||
ret float %2
|
||||
}
|
||||
|
||||
define double @t6() nounwind {
|
||||
; ELF64: t6
|
||||
; SPE: t6
|
||||
%1 = load double, double* @f, align 8
|
||||
; ELF64: lfd
|
||||
; SPE: evldd
|
||||
%2 = fadd double %1, 1.0
|
||||
; ELF64: fadd
|
||||
; SPE: efdadd
|
||||
ret double %2
|
||||
}
|
||||
|
||||
@ -126,19 +133,25 @@ define void @t10(i64 %v) nounwind {
|
||||
|
||||
define void @t11(float %v) nounwind {
|
||||
; ELF64: t11
|
||||
; SPE: t11
|
||||
%1 = fadd float %v, 1.0
|
||||
store float %1, float* @e, align 4
|
||||
; ELF64: fadds
|
||||
; ELF64: stfs
|
||||
; SPE: efsadd
|
||||
; SPE: stw
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @t12(double %v) nounwind {
|
||||
; ELF64: t12
|
||||
; SPE: t12
|
||||
%1 = fadd double %v, 1.0
|
||||
store double %1, double* @f, align 8
|
||||
; ELF64: fadd
|
||||
; ELF64: stfd
|
||||
; SPE: efdadd
|
||||
; SPE: evstdd
|
||||
ret void
|
||||
}
|
||||
|
||||
|
542
test/CodeGen/PowerPC/spe.ll
Normal file
542
test/CodeGen/PowerPC/spe.ll
Normal file
@ -0,0 +1,542 @@
|
||||
; RUN: llc -verify-machineinstrs < %s -mtriple=powerpc-unknown-linux-gnu \
|
||||
; RUN: -mattr=+spe | FileCheck %s
|
||||
|
||||
declare float @llvm.fabs.float(float)
|
||||
define float @test_float_abs(float %a) #0 {
|
||||
entry:
|
||||
%0 = tail call float @llvm.fabs.float(float %a)
|
||||
ret float %0
|
||||
; CHECK-LABEL: test_float_abs
|
||||
; CHECK: efsabs 3, 3
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define float @test_fnabs(float %a) #0 {
|
||||
entry:
|
||||
%0 = tail call float @llvm.fabs.float(float %a)
|
||||
%sub = fsub float -0.000000e+00, %0
|
||||
ret float %sub
|
||||
; CHECK-LABEL: @test_fnabs
|
||||
; CHECK: efsnabs
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define float @test_fdiv(float %a, float %b) {
|
||||
entry:
|
||||
%v = fdiv float %a, %b
|
||||
ret float %v
|
||||
|
||||
; CHECK-LABEL: test_fdiv
|
||||
; CHECK: efsdiv
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define float @test_fmul(float %a, float %b) {
|
||||
entry:
|
||||
%v = fmul float %a, %b
|
||||
ret float %v
|
||||
; CHECK-LABEL @test_fmul
|
||||
; CHECK: efsmul
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define float @test_fadd(float %a, float %b) {
|
||||
entry:
|
||||
%v = fadd float %a, %b
|
||||
ret float %v
|
||||
; CHECK-LABEL @test_fadd
|
||||
; CHECK: efsadd
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define float @test_fsub(float %a, float %b) {
|
||||
entry:
|
||||
%v = fsub float %a, %b
|
||||
ret float %v
|
||||
; CHECK-LABEL @test_fsub
|
||||
; CHECK: efssub
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define float @test_fneg(float %a) {
|
||||
entry:
|
||||
%v = fsub float -0.0, %a
|
||||
ret float %v
|
||||
|
||||
; CHECK-LABEL @test_fneg
|
||||
; CHECK: efsneg
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define float @test_dtos(double %a) {
|
||||
entry:
|
||||
%v = fptrunc double %a to float
|
||||
ret float %v
|
||||
; CHECK-LABEL: test_dtos
|
||||
; CHECK: efscfd
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define i1 @test_fcmpgt(float %a, float %b) {
|
||||
entry:
|
||||
%r = fcmp ogt float %a, %b
|
||||
ret i1 %r
|
||||
; CHECK-LABEL: test_fcmpgt
|
||||
; CHECK: efscmpgt
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define i1 @test_fcmpugt(float %a, float %b) {
|
||||
entry:
|
||||
%r = fcmp ugt float %a, %b
|
||||
ret i1 %r
|
||||
; CHECK-LABEL: test_fcmpugt
|
||||
; CHECK: efscmpgt
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define i1 @test_fcmple(float %a, float %b) {
|
||||
entry:
|
||||
%r = fcmp ole float %a, %b
|
||||
ret i1 %r
|
||||
; CHECK-LABEL: test_fcmple
|
||||
; CHECK: efscmpgt
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define i1 @test_fcmpule(float %a, float %b) {
|
||||
entry:
|
||||
%r = fcmp ule float %a, %b
|
||||
ret i1 %r
|
||||
; CHECK-LABEL: test_fcmpule
|
||||
; CHECK: efscmpgt
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define i1 @test_fcmpeq(float %a, float %b) {
|
||||
entry:
|
||||
%r = fcmp oeq float %a, %b
|
||||
ret i1 %r
|
||||
; CHECK-LABEL: test_fcmpeq
|
||||
; CHECK: efscmpeq
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
; (un)ordered tests are expanded to une and oeq so verify
|
||||
define i1 @test_fcmpuno(float %a, float %b) {
|
||||
entry:
|
||||
%r = fcmp uno float %a, %b
|
||||
ret i1 %r
|
||||
; CHECK-LABEL: test_fcmpuno
|
||||
; CHECK: efscmpeq
|
||||
; CHECK: efscmpeq
|
||||
; CHECK: crand
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define i1 @test_fcmpord(float %a, float %b) {
|
||||
entry:
|
||||
%r = fcmp ord float %a, %b
|
||||
ret i1 %r
|
||||
; CHECK-LABEL: test_fcmpord
|
||||
; CHECK: efscmpeq
|
||||
; CHECK: efscmpeq
|
||||
; CHECK: crnand
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define i1 @test_fcmpueq(float %a, float %b) {
|
||||
entry:
|
||||
%r = fcmp ueq float %a, %b
|
||||
ret i1 %r
|
||||
; CHECK-LABEL: test_fcmpueq
|
||||
; CHECK: efscmpeq
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define i1 @test_fcmpne(float %a, float %b) {
|
||||
entry:
|
||||
%r = fcmp one float %a, %b
|
||||
ret i1 %r
|
||||
; CHECK-LABEL: test_fcmpne
|
||||
; CHECK: efscmpeq
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define i1 @test_fcmpune(float %a, float %b) {
|
||||
entry:
|
||||
%r = fcmp une float %a, %b
|
||||
ret i1 %r
|
||||
; CHECK-LABEL: test_fcmpune
|
||||
; CHECK: efscmpeq
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define i1 @test_fcmplt(float %a, float %b) {
|
||||
entry:
|
||||
%r = fcmp olt float %a, %b
|
||||
ret i1 %r
|
||||
; CHECK-LABEL: test_fcmplt
|
||||
; CHECK: efscmplt
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define i1 @test_fcmpult(float %a, float %b) {
|
||||
entry:
|
||||
%r = fcmp ult float %a, %b
|
||||
ret i1 %r
|
||||
; CHECK-LABEL: test_fcmpult
|
||||
; CHECK: efscmplt
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define i1 @test_fcmpge(float %a, float %b) {
|
||||
entry:
|
||||
%r = fcmp oge float %a, %b
|
||||
ret i1 %r
|
||||
; CHECK-LABEL: test_fcmpge
|
||||
; CHECK: efscmplt
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define i1 @test_fcmpuge(float %a, float %b) {
|
||||
entry:
|
||||
%r = fcmp uge float %a, %b
|
||||
ret i1 %r
|
||||
; CHECK-LABEL: test_fcmpuge
|
||||
; CHECK: efscmplt
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define i32 @test_ftoui(float %a) {
|
||||
%v = fptoui float %a to i32
|
||||
ret i32 %v
|
||||
; CHECK-LABEL: test_ftoui
|
||||
; CHECK: efsctuiz
|
||||
}
|
||||
|
||||
define i32 @test_ftosi(float %a) {
|
||||
%v = fptosi float %a to i32
|
||||
ret i32 %v
|
||||
; CHECK-LABEL: test_ftosi
|
||||
; CHECK: efsctsiz
|
||||
}
|
||||
|
||||
define float @test_ffromui(i32 %a) {
|
||||
%v = uitofp i32 %a to float
|
||||
ret float %v
|
||||
; CHECK-LABEL: test_ffromui
|
||||
; CHECK: efscfui
|
||||
}
|
||||
|
||||
define float @test_ffromsi(i32 %a) {
|
||||
%v = sitofp i32 %a to float
|
||||
ret float %v
|
||||
; CHECK-LABEL: test_ffromsi
|
||||
; CHECK: efscfsi
|
||||
}
|
||||
|
||||
define i32 @test_fasmconst(float %x) {
|
||||
entry:
|
||||
%x.addr = alloca float, align 8
|
||||
store float %x, float* %x.addr, align 8
|
||||
%0 = load float, float* %x.addr, align 8
|
||||
%1 = call i32 asm sideeffect "efsctsi $0, $1", "=f,f"(float %0)
|
||||
ret i32 %1
|
||||
; CHECK-LABEL: test_fasmconst
|
||||
; Check that it's not loading a double
|
||||
; CHECK-NOT: evldd
|
||||
; CHECK: #APP
|
||||
; CHECK: efsctsi
|
||||
; CHECK: #NO_APP
|
||||
}
|
||||
|
||||
; Double tests
|
||||
|
||||
define void @test_double_abs(double * %aa) #0 {
|
||||
entry:
|
||||
%0 = load double, double * %aa
|
||||
%1 = tail call double @llvm.fabs.f64(double %0) #2
|
||||
store double %1, double * %aa
|
||||
ret void
|
||||
; CHECK-LABEL: test_double_abs
|
||||
; CHECK: efdabs
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
; Function Attrs: nounwind readnone
|
||||
declare double @llvm.fabs.f64(double) #1
|
||||
|
||||
define void @test_dnabs(double * %aa) #0 {
|
||||
entry:
|
||||
%0 = load double, double * %aa
|
||||
%1 = tail call double @llvm.fabs.f64(double %0) #2
|
||||
%sub = fsub double -0.000000e+00, %1
|
||||
store double %sub, double * %aa
|
||||
ret void
|
||||
}
|
||||
; CHECK-LABEL: @test_dnabs
|
||||
; CHECK: efdnabs
|
||||
; CHECK: blr
|
||||
|
||||
define double @test_ddiv(double %a, double %b) {
|
||||
entry:
|
||||
%v = fdiv double %a, %b
|
||||
ret double %v
|
||||
|
||||
; CHECK-LABEL: test_ddiv
|
||||
; CHECK: efddiv
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define double @test_dmul(double %a, double %b) {
|
||||
entry:
|
||||
%v = fmul double %a, %b
|
||||
ret double %v
|
||||
; CHECK-LABEL @test_dmul
|
||||
; CHECK: efdmul
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define double @test_dadd(double %a, double %b) {
|
||||
entry:
|
||||
%v = fadd double %a, %b
|
||||
ret double %v
|
||||
; CHECK-LABEL @test_dadd
|
||||
; CHECK: efdadd
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define double @test_dsub(double %a, double %b) {
|
||||
entry:
|
||||
%v = fsub double %a, %b
|
||||
ret double %v
|
||||
; CHECK-LABEL @test_dsub
|
||||
; CHECK: efdsub
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define double @test_dneg(double %a) {
|
||||
entry:
|
||||
%v = fsub double -0.0, %a
|
||||
ret double %v
|
||||
|
||||
; CHECK-LABEL @test_dneg
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define double @test_stod(float %a) {
|
||||
entry:
|
||||
%v = fpext float %a to double
|
||||
ret double %v
|
||||
; CHECK-LABEL: test_stod
|
||||
; CHECK: efdcfs
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
; (un)ordered tests are expanded to une and oeq so verify
|
||||
define i1 @test_dcmpuno(double %a, double %b) {
|
||||
entry:
|
||||
%r = fcmp uno double %a, %b
|
||||
ret i1 %r
|
||||
; CHECK-LABEL: test_dcmpuno
|
||||
; CHECK: efdcmpeq
|
||||
; CHECK: efdcmpeq
|
||||
; CHECK: crand
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define i1 @test_dcmpord(double %a, double %b) {
|
||||
entry:
|
||||
%r = fcmp ord double %a, %b
|
||||
ret i1 %r
|
||||
; CHECK-LABEL: test_dcmpord
|
||||
; CHECK: efdcmpeq
|
||||
; CHECK: efdcmpeq
|
||||
; CHECK: crnand
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define i1 @test_dcmpgt(double %a, double %b) {
|
||||
entry:
|
||||
%r = fcmp ogt double %a, %b
|
||||
ret i1 %r
|
||||
; CHECK-LABEL: test_dcmpgt
|
||||
; CHECK: efdcmpgt
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define i1 @test_dcmpugt(double %a, double %b) {
|
||||
entry:
|
||||
%r = fcmp ugt double %a, %b
|
||||
ret i1 %r
|
||||
; CHECK-LABEL: test_dcmpugt
|
||||
; CHECK: efdcmpgt
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define i1 @test_dcmple(double %a, double %b) {
|
||||
entry:
|
||||
%r = fcmp ole double %a, %b
|
||||
ret i1 %r
|
||||
; CHECK-LABEL: test_dcmple
|
||||
; CHECK: efdcmpgt
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define i1 @test_dcmpule(double %a, double %b) {
|
||||
entry:
|
||||
%r = fcmp ule double %a, %b
|
||||
ret i1 %r
|
||||
; CHECK-LABEL: test_dcmpule
|
||||
; CHECK: efdcmpgt
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define i1 @test_dcmpeq(double %a, double %b) {
|
||||
entry:
|
||||
%r = fcmp oeq double %a, %b
|
||||
ret i1 %r
|
||||
; CHECK-LABEL: test_dcmpeq
|
||||
; CHECK: efdcmpeq
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define i1 @test_dcmpueq(double %a, double %b) {
|
||||
entry:
|
||||
%r = fcmp ueq double %a, %b
|
||||
ret i1 %r
|
||||
; CHECK-LABEL: test_dcmpueq
|
||||
; CHECK: efdcmpeq
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define i1 @test_dcmpne(double %a, double %b) {
|
||||
entry:
|
||||
%r = fcmp one double %a, %b
|
||||
ret i1 %r
|
||||
; CHECK-LABEL: test_dcmpne
|
||||
; CHECK: efdcmpeq
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define i1 @test_dcmpune(double %a, double %b) {
|
||||
entry:
|
||||
%r = fcmp une double %a, %b
|
||||
ret i1 %r
|
||||
; CHECK-LABEL: test_dcmpune
|
||||
; CHECK: efdcmpeq
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define i1 @test_dcmplt(double %a, double %b) {
|
||||
entry:
|
||||
%r = fcmp olt double %a, %b
|
||||
ret i1 %r
|
||||
; CHECK-LABEL: test_dcmplt
|
||||
; CHECK: efdcmplt
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define i1 @test_dcmpult(double %a, double %b) {
|
||||
entry:
|
||||
%r = fcmp ult double %a, %b
|
||||
ret i1 %r
|
||||
; CHECK-LABEL: test_dcmpult
|
||||
; CHECK: efdcmplt
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define i1 @test_dcmpge(double %a, double %b) {
|
||||
entry:
|
||||
%r = fcmp oge double %a, %b
|
||||
ret i1 %r
|
||||
; CHECK-LABEL: test_dcmpge
|
||||
; CHECK: efdcmplt
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define i1 @test_dcmpuge(double %a, double %b) {
|
||||
entry:
|
||||
%r = fcmp uge double %a, %b
|
||||
ret i1 %r
|
||||
; CHECK-LABEL: test_dcmpuge
|
||||
; CHECK: efdcmplt
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define double @test_dselect(double %a, double %b, i1 %c) {
|
||||
entry:
|
||||
%r = select i1 %c, double %a, double %b
|
||||
ret double %r
|
||||
; CHECK-LABEL: test_dselect
|
||||
; CHECK: andi.
|
||||
; CHECK: bc
|
||||
; CHECK: evldd
|
||||
; CHECK: b
|
||||
; CHECK: evldd
|
||||
; CHECK: evstdd
|
||||
; CHECK: blr
|
||||
}
|
||||
|
||||
define i32 @test_dtoui(double %a) {
|
||||
entry:
|
||||
%v = fptoui double %a to i32
|
||||
ret i32 %v
|
||||
; CHECK-LABEL: test_dtoui
|
||||
; CHECK: efdctuiz
|
||||
}
|
||||
|
||||
define i32 @test_dtosi(double %a) {
|
||||
entry:
|
||||
%v = fptosi double %a to i32
|
||||
ret i32 %v
|
||||
; CHECK-LABEL: test_dtosi
|
||||
; CHECK: efdctsiz
|
||||
}
|
||||
|
||||
define double @test_dfromui(i32 %a) {
|
||||
entry:
|
||||
%v = uitofp i32 %a to double
|
||||
ret double %v
|
||||
; CHECK-LABEL: test_dfromui
|
||||
; CHECK: efdcfui
|
||||
}
|
||||
|
||||
define double @test_dfromsi(i32 %a) {
|
||||
entry:
|
||||
%v = sitofp i32 %a to double
|
||||
ret double %v
|
||||
; CHECK-LABEL: test_dfromsi
|
||||
; CHECK: efdcfsi
|
||||
}
|
||||
|
||||
define i32 @test_dasmconst(double %x) {
|
||||
entry:
|
||||
%x.addr = alloca double, align 8
|
||||
store double %x, double* %x.addr, align 8
|
||||
%0 = load double, double* %x.addr, align 8
|
||||
%1 = call i32 asm sideeffect "efdctsi $0, $1", "=d,d"(double %0)
|
||||
ret i32 %1
|
||||
; CHECK-LABEL: test_dasmconst
|
||||
; CHECK: evldd
|
||||
; CHECK: #APP
|
||||
; CHECK: efdctsi
|
||||
; CHECK: #NO_APP
|
||||
}
|
||||
|
||||
define double @test_spill(double %a) nounwind {
|
||||
entry:
|
||||
%0 = fadd double %a, %a
|
||||
call void asm sideeffect "","~{r0},~{r3},~{s4},~{r5},~{r6},~{r7},~{r8},~{r9},~{r10},~{r11},~{r12},~{r13},~{r14},~{r15},~{r16},~{r17},~{r18},~{r19},~{r20},~{r21},~{r22},~{r23},~{r24},~{r25},~{r26},~{r27},~{r28},~{r29},~{r30},~{r31}"() nounwind
|
||||
%1 = fadd double %0, 3.14159
|
||||
br label %return
|
||||
|
||||
return:
|
||||
ret double %1
|
||||
|
||||
; CHECK-LABEL: test_spill
|
||||
; CHECK: efdadd
|
||||
; CHECK: evstdd
|
||||
; CHECK: evldd
|
||||
}
|
Loading…
Reference in New Issue
Block a user