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:
Justin Hibbits 2018-07-18 04:25:10 +00:00
parent 4fa4fa6a73
commit d52990c71b
23 changed files with 1929 additions and 631 deletions

View File

@ -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()]));

View File

@ -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

View File

@ -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,

View File

@ -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,

View File

@ -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;

View File

@ -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,

View File

@ -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();

View File

@ -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

View File

@ -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:

View File

@ -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())

View File

@ -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;

View File

@ -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,

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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.

View File

@ -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; }

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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
}

View 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
}