diff --git a/llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp b/llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp --- a/llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp +++ b/llvm/lib/Target/PowerPC/GISel/PPCInstructionSelector.cpp @@ -99,7 +99,7 @@ if (RB->getID() == PPC::GPRRegBankID) { if (Ty.getSizeInBits() == 64) return &PPC::G8RCRegClass; - if (Ty.getSizeInBits() == 32) + if (Ty.getSizeInBits() <= 32) return &PPC::GPRCRegClass; } if (RB->getID() == PPC::FPRRegBankID) { @@ -108,6 +108,12 @@ if (Ty.getSizeInBits() == 64) return &PPC::F8RCRegClass; } + if (RB->getID() == PPC::CRRegBankID) { + if (Ty.getSizeInBits() == 1) + return &PPC::CRBITRCRegClass; + if (Ty.getSizeInBits() == 4) + return &PPC::CRRCRegClass; + } llvm_unreachable("Unknown RegBank!"); } diff --git a/llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp b/llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp --- a/llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp +++ b/llvm/lib/Target/PowerPC/GISel/PPCLegalizerInfo.cpp @@ -20,6 +20,7 @@ PPCLegalizerInfo::PPCLegalizerInfo(const PPCSubtarget &ST) { using namespace TargetOpcode; const LLT P0 = LLT::pointer(0, 64); + const LLT S1 = LLT::scalar(1); const LLT S8 = LLT::scalar(8); const LLT S16 = LLT::scalar(16); const LLT S32 = LLT::scalar(32); @@ -28,8 +29,8 @@ getActionDefinitionsBuilder(G_CONSTANT) .legalFor({S32, S64}) .clampScalar(0, S64, S64); - getActionDefinitionsBuilder({G_ZEXT, G_SEXT}) - .legalForCartesianProduct({S64}, {S8, S16, S32}) + getActionDefinitionsBuilder({G_ZEXT, G_SEXT, G_ANYEXT}) + .legalForCartesianProduct({S64}, {S1, S8, S16, S32}) .clampScalar(0, S64, S64); getActionDefinitionsBuilder({G_AND, G_OR, G_XOR}) .legalFor({S64}) @@ -41,6 +42,9 @@ getActionDefinitionsBuilder({G_FADD, G_FSUB, G_FMUL, G_FDIV}) .legalFor({S32, S64}); + getActionDefinitionsBuilder(G_FCMP).legalForCartesianProduct({S1}, + {S32, S64}); + getActionDefinitionsBuilder({G_FPTOSI, G_FPTOUI}) .legalForCartesianProduct({S64}, {S32, S64}); diff --git a/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.h b/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.h --- a/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.h +++ b/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.h @@ -32,6 +32,7 @@ PMI_GPR64 = 2, PMI_FPR32 = 3, PMI_FPR64 = 4, + PMI_CR = 5, PMI_Min = PMI_GPR32, }; diff --git a/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.cpp b/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.cpp --- a/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.cpp +++ b/llvm/lib/Target/PowerPC/GISel/PPCRegisterBankInfo.cpp @@ -48,6 +48,9 @@ case PPC::VSSRCRegClassID: case PPC::F4RCRegClassID: return getRegBank(PPC::FPRRegBankID); + case PPC::CRRCRegClassID: + case PPC::CRBITRCRegClassID: + return getRegBank(PPC::CRRegBankID); default: llvm_unreachable("Unexpected register class"); } @@ -87,6 +90,7 @@ // Extension ops. case TargetOpcode::G_SEXT: case TargetOpcode::G_ZEXT: + case TargetOpcode::G_ANYEXT: assert(NumOperands <= 3 && "This code is for instructions with 3 or less operands"); OperandsMapping = getValueMapping(PMI_GPR64); @@ -102,6 +106,15 @@ OperandsMapping = getValueMapping(Size == 32 ? PMI_FPR32 : PMI_FPR64); break; } + case TargetOpcode::G_FCMP: { + unsigned CmpSize = MRI.getType(MI.getOperand(2).getReg()).getSizeInBits(); + + OperandsMapping = getOperandsMapping( + {getValueMapping(PMI_CR), nullptr, + getValueMapping(CmpSize == 32 ? PMI_FPR32 : PMI_FPR64), + getValueMapping(CmpSize == 32 ? PMI_FPR32 : PMI_FPR64)}); + break; + } case TargetOpcode::G_CONSTANT: OperandsMapping = getOperandsMapping({getValueMapping(PMI_GPR64), nullptr}); break; diff --git a/llvm/lib/Target/PowerPC/GISel/PPCRegisterBanks.td b/llvm/lib/Target/PowerPC/GISel/PPCRegisterBanks.td --- a/llvm/lib/Target/PowerPC/GISel/PPCRegisterBanks.td +++ b/llvm/lib/Target/PowerPC/GISel/PPCRegisterBanks.td @@ -15,3 +15,5 @@ def GPRRegBank : RegisterBank<"GPR", [G8RC, G8RC_NOX0]>; /// Floating point Registers def FPRRegBank : RegisterBank<"FPR", [VSSRC]>; +/// Condition Registers +def CRRegBank : RegisterBank<"CR", [CRRC]>; diff --git a/llvm/lib/Target/PowerPC/PPCGenRegisterBankInfo.def b/llvm/lib/Target/PowerPC/PPCGenRegisterBankInfo.def --- a/llvm/lib/Target/PowerPC/PPCGenRegisterBankInfo.def +++ b/llvm/lib/Target/PowerPC/PPCGenRegisterBankInfo.def @@ -22,6 +22,8 @@ {0, 32, PPC::FPRRegBank}, // 3: FPR 64-bit value {0, 64, PPC::FPRRegBank}, + // 4: CR 4-bit value + {0, 4, PPC::CRRegBank}, }; // ValueMappings. @@ -55,6 +57,8 @@ {&PPCGenRegisterBankInfo::PartMappings[PMI_FPR64 - PMI_Min], 1}, {&PPCGenRegisterBankInfo::PartMappings[PMI_FPR64 - PMI_Min], 1}, {&PPCGenRegisterBankInfo::PartMappings[PMI_FPR64 - PMI_Min], 1}, + // 13: CR 4-bit value. + {&PPCGenRegisterBankInfo::PartMappings[PMI_CR - PMI_Min], 1}, }; // TODO Too simple! diff --git a/llvm/lib/Target/PowerPC/PPCInstrInfo.td b/llvm/lib/Target/PowerPC/PPCInstrInfo.td --- a/llvm/lib/Target/PowerPC/PPCInstrInfo.td +++ b/llvm/lib/Target/PowerPC/PPCInstrInfo.td @@ -3327,9 +3327,9 @@ // FIXME: We should choose either a zext or a sext based on other constants // already around. def : Pat<(i32 (anyext i1:$in)), - (SELECT_I4 $in, (LI 1), (LI 0))>; + (SELECT_I4 i1:$in, (LI 1), (LI 0))>; def : Pat<(i64 (anyext i1:$in)), - (SELECT_I8 $in, (LI8 1), (LI8 0))>; + (SELECT_I8 i1:$in, (LI8 1), (LI8 0))>; // match setcc on i1 variables. // CRANDC is: @@ -3735,34 +3735,34 @@ multiclass FSetCCPat { defm : CRNotPat<(i1 (SetCC Ty:$s1, Ty:$s2, SETUGE)), - (EXTRACT_SUBREG (FCmp $s1, $s2), sub_lt)>; + (EXTRACT_SUBREG (FCmp Ty:$s1, Ty:$s2), sub_lt)>; defm : CRNotPat<(i1 (SetCC Ty:$s1, Ty:$s2, SETGE)), - (EXTRACT_SUBREG (FCmp $s1, $s2), sub_lt)>; + (EXTRACT_SUBREG (FCmp Ty:$s1, Ty:$s2), sub_lt)>; defm : CRNotPat<(i1 (SetCC Ty:$s1, Ty:$s2, SETULE)), - (EXTRACT_SUBREG (FCmp $s1, $s2), sub_gt)>; + (EXTRACT_SUBREG (FCmp Ty:$s1, Ty:$s2), sub_gt)>; defm : CRNotPat<(i1 (SetCC Ty:$s1, Ty:$s2, SETLE)), - (EXTRACT_SUBREG (FCmp $s1, $s2), sub_gt)>; + (EXTRACT_SUBREG (FCmp Ty:$s1, Ty:$s2), sub_gt)>; defm : CRNotPat<(i1 (SetCC Ty:$s1, Ty:$s2, SETUNE)), - (EXTRACT_SUBREG (FCmp $s1, $s2), sub_eq)>; + (EXTRACT_SUBREG (FCmp Ty:$s1, Ty:$s2), sub_eq)>; defm : CRNotPat<(i1 (SetCC Ty:$s1, Ty:$s2, SETNE)), - (EXTRACT_SUBREG (FCmp $s1, $s2), sub_eq)>; + (EXTRACT_SUBREG (FCmp Ty:$s1, Ty:$s2), sub_eq)>; defm : CRNotPat<(i1 (SetCC Ty:$s1, Ty:$s2, SETO)), - (EXTRACT_SUBREG (FCmp $s1, $s2), sub_un)>; + (EXTRACT_SUBREG (FCmp Ty:$s1, Ty:$s2), sub_un)>; def : Pat<(i1 (SetCC Ty:$s1, Ty:$s2, SETOLT)), - (EXTRACT_SUBREG (FCmp $s1, $s2), sub_lt)>; + (EXTRACT_SUBREG (FCmp Ty:$s1, Ty:$s2), sub_lt)>; def : Pat<(i1 (SetCC Ty:$s1, Ty:$s2, SETLT)), - (EXTRACT_SUBREG (FCmp $s1, $s2), sub_lt)>; + (EXTRACT_SUBREG (FCmp Ty:$s1, Ty:$s2), sub_lt)>; def : Pat<(i1 (SetCC Ty:$s1, Ty:$s2, SETOGT)), - (EXTRACT_SUBREG (FCmp $s1, $s2), sub_gt)>; + (EXTRACT_SUBREG (FCmp Ty:$s1, Ty:$s2), sub_gt)>; def : Pat<(i1 (SetCC Ty:$s1, Ty:$s2, SETGT)), - (EXTRACT_SUBREG (FCmp $s1, $s2), sub_gt)>; + (EXTRACT_SUBREG (FCmp Ty:$s1, Ty:$s2), sub_gt)>; def : Pat<(i1 (SetCC Ty:$s1, Ty:$s2, SETOEQ)), - (EXTRACT_SUBREG (FCmp $s1, $s2), sub_eq)>; + (EXTRACT_SUBREG (FCmp Ty:$s1, Ty:$s2), sub_eq)>; def : Pat<(i1 (SetCC Ty:$s1, Ty:$s2, SETEQ)), - (EXTRACT_SUBREG (FCmp $s1, $s2), sub_eq)>; + (EXTRACT_SUBREG (FCmp Ty:$s1, Ty:$s2), sub_eq)>; def : Pat<(i1 (SetCC Ty:$s1, Ty:$s2, SETUO)), - (EXTRACT_SUBREG (FCmp $s1, $s2), sub_un)>; + (EXTRACT_SUBREG (FCmp Ty:$s1, Ty:$s2), sub_un)>; } let Predicates = [HasFPU] in { diff --git a/llvm/test/CodeGen/PowerPC/GlobalISel/fcmp.ll b/llvm/test/CodeGen/PowerPC/GlobalISel/fcmp.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/GlobalISel/fcmp.ll @@ -0,0 +1,243 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=powerpc64le-unknown-linux-gnu -global-isel -o - \ +; RUN: -ppc-vsr-nums-as-vr -ppc-asm-full-reg-names < %s | FileCheck %s + +;; Note that SETUEQ, SETOGE, SETOLE, SETONE, SETULT and SETUGT should be +;; expanded by legalize for floating-point types f32 and f64, so there are no. +;; patterns defined in PPCInstrInfo.td file for these setcc patterns. + +define i1 @fcmp_false(float %a, float %b) { +; CHECK-LABEL: fcmp_false: +; CHECK: # %bb.0: +; CHECK-NEXT: li r3, 0 +; CHECK-NEXT: blr + %cmp = fcmp false float %a, %b + ret i1 %cmp +} + +define i1 @fcmp_oeq(float %a, float %b) { +; CHECK-LABEL: fcmp_oeq: +; CHECK: # %bb.0: +; CHECK-NEXT: fcmpu cr0, f1, f2 +; CHECK-NEXT: li r3, 0 +; CHECK-NEXT: li r4, 1 +; CHECK-NEXT: iseleq r3, r4, r3 +; CHECK-NEXT: blr + %cmp = fcmp oeq float %a, %b + ret i1 %cmp +} + +define i1 @fcmp_ogt(float %a, float %b) { +; CHECK-LABEL: fcmp_ogt: +; CHECK: # %bb.0: +; CHECK-NEXT: fcmpu cr0, f1, f2 +; CHECK-NEXT: li r3, 0 +; CHECK-NEXT: li r4, 1 +; CHECK-NEXT: iselgt r3, r4, r3 +; CHECK-NEXT: blr + %cmp = fcmp ogt float %a, %b + ret i1 %cmp +} + +define i1 @fcmp_olt(float %a, float %b) { +; CHECK-LABEL: fcmp_olt: +; CHECK: # %bb.0: +; CHECK-NEXT: fcmpu cr0, f1, f2 +; CHECK-NEXT: li r3, 0 +; CHECK-NEXT: li r4, 1 +; CHECK-NEXT: isellt r3, r4, r3 +; CHECK-NEXT: blr + %cmp = fcmp olt float %a, %b + ret i1 %cmp +} + +define i1 @fcmp_ord(float %a, float %b) { +; CHECK-LABEL: fcmp_ord: +; CHECK: # %bb.0: +; CHECK-NEXT: fcmpu cr0, f1, f2 +; CHECK-NEXT: li r3, 0 +; CHECK-NEXT: li r4, 1 +; CHECK-NEXT: crnot 4*cr5+lt, un +; CHECK-NEXT: isel r3, r4, r3, 4*cr5+lt +; CHECK-NEXT: blr + %cmp = fcmp ord float %a, %b + ret i1 %cmp +} + +define i1 @fcmp_uge(float %a, float %b) { +; CHECK-LABEL: fcmp_uge: +; CHECK: # %bb.0: +; CHECK-NEXT: fcmpu cr0, f1, f2 +; CHECK-NEXT: li r3, 0 +; CHECK-NEXT: li r4, 1 +; CHECK-NEXT: crnot 4*cr5+lt, lt +; CHECK-NEXT: isel r3, r4, r3, 4*cr5+lt +; CHECK-NEXT: blr + %cmp = fcmp uge float %a, %b + ret i1 %cmp +} + +define i1 @fcmp_ule(float %a, float %b) { +; CHECK-LABEL: fcmp_ule: +; CHECK: # %bb.0: +; CHECK-NEXT: fcmpu cr0, f1, f2 +; CHECK-NEXT: li r3, 0 +; CHECK-NEXT: li r4, 1 +; CHECK-NEXT: crnot 4*cr5+lt, gt +; CHECK-NEXT: isel r3, r4, r3, 4*cr5+lt +; CHECK-NEXT: blr + %cmp = fcmp ule float %a, %b + ret i1 %cmp +} + +define i1 @fcmp_une(float %a, float %b) { +; CHECK-LABEL: fcmp_une: +; CHECK: # %bb.0: +; CHECK-NEXT: fcmpu cr0, f1, f2 +; CHECK-NEXT: li r3, 0 +; CHECK-NEXT: li r4, 1 +; CHECK-NEXT: crnot 4*cr5+lt, eq +; CHECK-NEXT: isel r3, r4, r3, 4*cr5+lt +; CHECK-NEXT: blr + %cmp = fcmp une float %a, %b + ret i1 %cmp +} + +define i1 @fcmp_uno(float %a, float %b) { +; CHECK-LABEL: fcmp_uno: +; CHECK: # %bb.0: +; CHECK-NEXT: fcmpu cr0, f1, f2 +; CHECK-NEXT: li r3, 0 +; CHECK-NEXT: li r4, 1 +; CHECK-NEXT: isel r3, r4, r3, un +; CHECK-NEXT: blr + %cmp = fcmp uno float %a, %b + ret i1 %cmp +} + +define i1 @fcmp_true(float %a, float %b) { +; CHECK-LABEL: fcmp_true: +; CHECK: # %bb.0: +; CHECK-NEXT: li r3, 1 +; CHECK-NEXT: blr + %cmp = fcmp true float %a, %b + ret i1 %cmp +} + +define i1 @fcmp_false_double(double %a, double %b) { +; CHECK-LABEL: fcmp_false_double: +; CHECK: # %bb.0: +; CHECK-NEXT: li r3, 0 +; CHECK-NEXT: blr + %cmp = fcmp false double %a, %b + ret i1 %cmp +} + +define i1 @fcmp_oeq_double(double %a, double %b) { +; CHECK-LABEL: fcmp_oeq_double: +; CHECK: # %bb.0: +; CHECK-NEXT: fcmpu cr0, f1, f2 +; CHECK-NEXT: li r3, 0 +; CHECK-NEXT: li r4, 1 +; CHECK-NEXT: iseleq r3, r4, r3 +; CHECK-NEXT: blr + %cmp = fcmp oeq double %a, %b + ret i1 %cmp +} + +define i1 @fcmp_ogt_double(double %a, double %b) { +; CHECK-LABEL: fcmp_ogt_double: +; CHECK: # %bb.0: +; CHECK-NEXT: fcmpu cr0, f1, f2 +; CHECK-NEXT: li r3, 0 +; CHECK-NEXT: li r4, 1 +; CHECK-NEXT: iselgt r3, r4, r3 +; CHECK-NEXT: blr + %cmp = fcmp ogt double %a, %b + ret i1 %cmp +} + +define i1 @fcmp_olt_double(double %a, double %b) { +; CHECK-LABEL: fcmp_olt_double: +; CHECK: # %bb.0: +; CHECK-NEXT: fcmpu cr0, f1, f2 +; CHECK-NEXT: li r3, 0 +; CHECK-NEXT: li r4, 1 +; CHECK-NEXT: isellt r3, r4, r3 +; CHECK-NEXT: blr + %cmp = fcmp olt double %a, %b + ret i1 %cmp +} + +define i1 @fcmp_ord_double(double %a, double %b) { +; CHECK-LABEL: fcmp_ord_double: +; CHECK: # %bb.0: +; CHECK-NEXT: fcmpu cr0, f1, f2 +; CHECK-NEXT: li r3, 0 +; CHECK-NEXT: li r4, 1 +; CHECK-NEXT: crnot 4*cr5+lt, un +; CHECK-NEXT: isel r3, r4, r3, 4*cr5+lt +; CHECK-NEXT: blr + %cmp = fcmp ord double %a, %b + ret i1 %cmp +} + +define i1 @fcmp_uge_double(double %a, double %b) { +; CHECK-LABEL: fcmp_uge_double: +; CHECK: # %bb.0: +; CHECK-NEXT: fcmpu cr0, f1, f2 +; CHECK-NEXT: li r3, 0 +; CHECK-NEXT: li r4, 1 +; CHECK-NEXT: crnot 4*cr5+lt, lt +; CHECK-NEXT: isel r3, r4, r3, 4*cr5+lt +; CHECK-NEXT: blr + %cmp = fcmp uge double %a, %b + ret i1 %cmp +} + +define i1 @fcmp_ule_double(double %a, double %b) { +; CHECK-LABEL: fcmp_ule_double: +; CHECK: # %bb.0: +; CHECK-NEXT: fcmpu cr0, f1, f2 +; CHECK-NEXT: li r3, 0 +; CHECK-NEXT: li r4, 1 +; CHECK-NEXT: crnot 4*cr5+lt, gt +; CHECK-NEXT: isel r3, r4, r3, 4*cr5+lt +; CHECK-NEXT: blr + %cmp = fcmp ule double %a, %b + ret i1 %cmp +} + +define i1 @fcmp_une_double(double %a, double %b) { +; CHECK-LABEL: fcmp_une_double: +; CHECK: # %bb.0: +; CHECK-NEXT: fcmpu cr0, f1, f2 +; CHECK-NEXT: li r3, 0 +; CHECK-NEXT: li r4, 1 +; CHECK-NEXT: crnot 4*cr5+lt, eq +; CHECK-NEXT: isel r3, r4, r3, 4*cr5+lt +; CHECK-NEXT: blr + %cmp = fcmp une double %a, %b + ret i1 %cmp +} + +define i1 @fcmp_uno_double(double %a, double %b) { +; CHECK-LABEL: fcmp_uno_double: +; CHECK: # %bb.0: +; CHECK-NEXT: fcmpu cr0, f1, f2 +; CHECK-NEXT: li r3, 0 +; CHECK-NEXT: li r4, 1 +; CHECK-NEXT: isel r3, r4, r3, un +; CHECK-NEXT: blr + %cmp = fcmp uno double %a, %b + ret i1 %cmp +} + +define i1 @fcmp_true_double(double %a, double %b) { +; CHECK-LABEL: fcmp_true_double: +; CHECK: # %bb.0: +; CHECK-NEXT: li r3, 1 +; CHECK-NEXT: blr + %cmp = fcmp true double %a, %b + ret i1 %cmp +}