From b80d6be6d7b04ee033bd6ff9e0fe6d5e30c8a885 Mon Sep 17 00:00:00 2001 From: Juergen Ributzka Date: Thu, 13 Nov 2014 00:36:43 +0000 Subject: [PATCH] [FastISel][AArch64] Fold the cmp into the select when possible. This folds the compare emission into the select emission when possible, so we can directly use the flags and don't have to emit a separate compare. Related to rdar://problem/18960150. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@221847 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/AArch64/AArch64FastISel.cpp | 54 ++++++ test/CodeGen/AArch64/fast-isel-select.ll | 227 +++++++++++++++++++++++ 2 files changed, 281 insertions(+) diff --git a/lib/Target/AArch64/AArch64FastISel.cpp b/lib/Target/AArch64/AArch64FastISel.cpp index 82080c7e4b1..28e4b0a4599 100644 --- a/lib/Target/AArch64/AArch64FastISel.cpp +++ b/lib/Target/AArch64/AArch64FastISel.cpp @@ -2531,6 +2531,7 @@ bool AArch64FastISel::selectSelect(const Instruction *I) { const SelectInst *SI = cast(I); const Value *Cond = SI->getCondition(); AArch64CC::CondCode CC = AArch64CC::NE; + AArch64CC::CondCode ExtraCC = AArch64CC::AL; // Try to pickup the flags, so we don't have to emit another compare. if (foldXALUIntrinsic(CC, I, Cond)) { @@ -2538,6 +2539,54 @@ bool AArch64FastISel::selectSelect(const Instruction *I) { unsigned CondReg = getRegForValue(Cond); if (!CondReg) return false; + } else if (isa(Cond) && cast(Cond)->hasOneUse() && + isValueAvailable(Cond)) { + const auto *Cmp = cast(Cond); + // Try to optimize or fold the cmp. + CmpInst::Predicate Predicate = optimizeCmpPredicate(Cmp); + const Value *FoldSelect = nullptr; + switch (Predicate) { + default: + break; + case CmpInst::FCMP_FALSE: + FoldSelect = SI->getFalseValue(); + break; + case CmpInst::FCMP_TRUE: + FoldSelect = SI->getTrueValue(); + break; + } + + if (FoldSelect) { + unsigned SrcReg = getRegForValue(FoldSelect); + if (!SrcReg) + return false; + unsigned UseReg = lookUpRegForValue(SI); + if (UseReg) + MRI.clearKillFlags(UseReg); + + updateValueMap(I, SrcReg); + return true; + } + + // Emit the cmp. + if (!emitCmp(Cmp->getOperand(0), Cmp->getOperand(1), Cmp->isUnsigned())) + return false; + + // FCMP_UEQ and FCMP_ONE cannot be checked with a single select instruction. + CC = getCompareCC(Predicate); + switch (Predicate) { + default: + break; + case CmpInst::FCMP_UEQ: + ExtraCC = AArch64CC::EQ; + CC = AArch64CC::VS; + break; + case CmpInst::FCMP_ONE: + ExtraCC = AArch64CC::MI; + CC = AArch64CC::GT; + break; + } + assert((CC != AArch64CC::AL) && "Unexpected condition code."); } else { unsigned CondReg = getRegForValue(Cond); if (!CondReg) @@ -2560,6 +2609,11 @@ bool AArch64FastISel::selectSelect(const Instruction *I) { if (!Src1Reg || !Src2Reg) return false; + if (ExtraCC != AArch64CC::AL) { + Src2Reg = fastEmitInst_rri(Opc, RC, Src1Reg, Src1IsKill, Src2Reg, + Src2IsKill, ExtraCC); + Src2IsKill = true; + } unsigned ResultReg = fastEmitInst_rri(Opc, RC, Src1Reg, Src1IsKill, Src2Reg, Src2IsKill, CC); updateValueMap(I, ResultReg); diff --git a/test/CodeGen/AArch64/fast-isel-select.ll b/test/CodeGen/AArch64/fast-isel-select.ll index a219b5fad21..a4fc1b54a53 100644 --- a/test/CodeGen/AArch64/fast-isel-select.ll +++ b/test/CodeGen/AArch64/fast-isel-select.ll @@ -57,3 +57,230 @@ define double @select_f64(i1 zeroext %c, double %a, double %b) { %1 = select i1 %c, double %a, double %b ret double %1 } + +; Now test the folding of all compares. +define float @select_fcmp_false(float %x, float %a, float %b) { +; CHECK-LABEL: select_fcmp_false +; CHECK: mov.16b {{v[0-9]+}}, v2 + %1 = fcmp ogt float %x, %x + %2 = select i1 %1, float %a, float %b + ret float %2 +} + +define float @select_fcmp_ogt(float %x, float %y, float %a, float %b) { +; CHECK-LABEL: select_fcmp_ogt +; CHECK: fcmp s0, s1 +; CHECK-NEXT: fcsel {{s[0-9]+}}, s2, s3, gt + %1 = fcmp ogt float %x, %y + %2 = select i1 %1, float %a, float %b + ret float %2 +} + +define float @select_fcmp_oge(float %x, float %y, float %a, float %b) { +; CHECK-LABEL: select_fcmp_oge +; CHECK: fcmp s0, s1 +; CHECK-NEXT: fcsel {{s[0-9]+}}, s2, s3, ge + %1 = fcmp oge float %x, %y + %2 = select i1 %1, float %a, float %b + ret float %2 +} + +define float @select_fcmp_olt(float %x, float %y, float %a, float %b) { +; CHECK-LABEL: select_fcmp_olt +; CHECK: fcmp s0, s1 +; CHECK-NEXT: fcsel {{s[0-9]+}}, s2, s3, mi + %1 = fcmp olt float %x, %y + %2 = select i1 %1, float %a, float %b + ret float %2 +} + +define float @select_fcmp_ole(float %x, float %y, float %a, float %b) { +; CHECK-LABEL: select_fcmp_ole +; CHECK: fcmp s0, s1 +; CHECK-NEXT: fcsel {{s[0-9]+}}, s2, s3, ls + %1 = fcmp ole float %x, %y + %2 = select i1 %1, float %a, float %b + ret float %2 +} + +define float @select_fcmp_one(float %x, float %y, float %a, float %b) { +; CHECK-LABEL: select_fcmp_one +; CHECK: fcmp s0, s1 +; CHECK-NEXT: fcsel [[REG:s[0-9]+]], s2, s3, mi +; CHECK-NEXT: fcsel {{s[0-9]+}}, s2, [[REG]], gt + %1 = fcmp one float %x, %y + %2 = select i1 %1, float %a, float %b + ret float %2 +} + +define float @select_fcmp_ord(float %x, float %y, float %a, float %b) { +; CHECK-LABEL: select_fcmp_ord +; CHECK: fcmp s0, s1 +; CHECK-NEXT: fcsel {{s[0-9]+}}, s2, s3, vc + %1 = fcmp ord float %x, %y + %2 = select i1 %1, float %a, float %b + ret float %2 +} + +define float @select_fcmp_uno(float %x, float %y, float %a, float %b) { +; CHECK-LABEL: select_fcmp_uno +; CHECK: fcmp s0, s1 +; CHECK-NEXT: fcsel {{s[0-9]+}}, s2, s3, vs + %1 = fcmp uno float %x, %y + %2 = select i1 %1, float %a, float %b + ret float %2 +} + +define float @select_fcmp_ueq(float %x, float %y, float %a, float %b) { +; CHECK-LABEL: select_fcmp_ueq +; CHECK: fcmp s0, s1 +; CHECK-NEXT: fcsel [[REG:s[0-9]+]], s2, s3, eq +; CHECK-NEXT: fcsel {{s[0-9]+}}, s2, [[REG]], vs + %1 = fcmp ueq float %x, %y + %2 = select i1 %1, float %a, float %b + ret float %2 +} + +define float @select_fcmp_ugt(float %x, float %y, float %a, float %b) { +; CHECK-LABEL: select_fcmp_ugt +; CHECK: fcmp s0, s1 +; CHECK-NEXT: fcsel {{s[0-9]+}}, s2, s3, hi + %1 = fcmp ugt float %x, %y + %2 = select i1 %1, float %a, float %b + ret float %2 +} + +define float @select_fcmp_uge(float %x, float %y, float %a, float %b) { +; CHECK-LABEL: select_fcmp_uge +; CHECK: fcmp s0, s1 +; CHECK-NEXT: fcsel {{s[0-9]+}}, s2, s3, pl + %1 = fcmp uge float %x, %y + %2 = select i1 %1, float %a, float %b + ret float %2 +} + +define float @select_fcmp_ult(float %x, float %y, float %a, float %b) { +; CHECK-LABEL: select_fcmp_ult +; CHECK: fcmp s0, s1 +; CHECK-NEXT: fcsel {{s[0-9]+}}, s2, s3, lt + %1 = fcmp ult float %x, %y + %2 = select i1 %1, float %a, float %b + ret float %2 +} + + +define float @select_fcmp_ule(float %x, float %y, float %a, float %b) { +; CHECK-LABEL: select_fcmp_ule +; CHECK: fcmp s0, s1 +; CHECK-NEXT: fcsel {{s[0-9]+}}, s2, s3, le + %1 = fcmp ule float %x, %y + %2 = select i1 %1, float %a, float %b + ret float %2 +} + +define float @select_fcmp_une(float %x, float %y, float %a, float %b) { +; CHECK-LABEL: select_fcmp_une +; CHECK: fcmp s0, s1 +; CHECK-NEXT: fcsel {{s[0-9]+}}, s2, s3, ne + %1 = fcmp une float %x, %y + %2 = select i1 %1, float %a, float %b + ret float %2 +} + +define float @select_fcmp_true(float %x, float %a, float %b) { +; CHECK-LABEL: select_fcmp_true +; CHECK: mov.16b {{v[0-9]+}}, v1 + %1 = fcmp ueq float %x, %x + %2 = select i1 %1, float %a, float %b + ret float %2 +} + +define float @select_icmp_eq(i32 %x, i32 %y, float %a, float %b) { +; CHECK-LABEL: select_icmp_eq +; CHECK: cmp w0, w1 +; CHECK-NEXT: fcsel {{s[0-9]+}}, s0, s1, eq + %1 = icmp eq i32 %x, %y + %2 = select i1 %1, float %a, float %b + ret float %2 +} + +define float @select_icmp_ne(i32 %x, i32 %y, float %a, float %b) { +; CHECK-LABEL: select_icmp_ne +; CHECK: cmp w0, w1 +; CHECK-NEXT: fcsel {{s[0-9]+}}, s0, s1, ne + %1 = icmp ne i32 %x, %y + %2 = select i1 %1, float %a, float %b + ret float %2 +} + +define float @select_icmp_ugt(i32 %x, i32 %y, float %a, float %b) { +; CHECK-LABEL: select_icmp_ugt +; CHECK: cmp w0, w1 +; CHECK-NEXT: fcsel {{s[0-9]+}}, s0, s1, hi + %1 = icmp ugt i32 %x, %y + %2 = select i1 %1, float %a, float %b + ret float %2 +} + +define float @select_icmp_uge(i32 %x, i32 %y, float %a, float %b) { +; CHECK-LABEL: select_icmp_uge +; CHECK: cmp w0, w1 +; CHECK-NEXT: fcsel {{s[0-9]+}}, s0, s1, hs + %1 = icmp uge i32 %x, %y + %2 = select i1 %1, float %a, float %b + ret float %2 +} + +define float @select_icmp_ult(i32 %x, i32 %y, float %a, float %b) { +; CHECK-LABEL: select_icmp_ult +; CHECK: cmp w0, w1 +; CHECK-NEXT: fcsel {{s[0-9]+}}, s0, s1, lo + %1 = icmp ult i32 %x, %y + %2 = select i1 %1, float %a, float %b + ret float %2 +} + +define float @select_icmp_ule(i32 %x, i32 %y, float %a, float %b) { +; CHECK-LABEL: select_icmp_ule +; CHECK: cmp w0, w1 +; CHECK-NEXT: fcsel {{s[0-9]+}}, s0, s1, ls + %1 = icmp ule i32 %x, %y + %2 = select i1 %1, float %a, float %b + ret float %2 +} + +define float @select_icmp_sgt(i32 %x, i32 %y, float %a, float %b) { +; CHECK-LABEL: select_icmp_sgt +; CHECK: cmp w0, w1 +; CHECK-NEXT: fcsel {{s[0-9]+}}, s0, s1, gt + %1 = icmp sgt i32 %x, %y + %2 = select i1 %1, float %a, float %b + ret float %2 +} + +define float @select_icmp_sge(i32 %x, i32 %y, float %a, float %b) { +; CHECK-LABEL: select_icmp_sge +; CHECK: cmp w0, w1 +; CHECK-NEXT: fcsel {{s[0-9]+}}, s0, s1, ge + %1 = icmp sge i32 %x, %y + %2 = select i1 %1, float %a, float %b + ret float %2 +} + +define float @select_icmp_slt(i32 %x, i32 %y, float %a, float %b) { +; CHECK-LABEL: select_icmp_slt +; CHECK: cmp w0, w1 +; CHECK-NEXT: fcsel {{s[0-9]+}}, s0, s1, lt + %1 = icmp slt i32 %x, %y + %2 = select i1 %1, float %a, float %b + ret float %2 +} + +define float @select_icmp_sle(i32 %x, i32 %y, float %a, float %b) { +; CHECK-LABEL: select_icmp_sle +; CHECK: cmp w0, w1 +; CHECK-NEXT: fcsel {{s[0-9]+}}, s0, s1, le + %1 = icmp sle i32 %x, %y + %2 = select i1 %1, float %a, float %b + ret float %2 +} -- 2.34.1