diff --git a/lib/Target/SystemZ/SystemZElimCompare.cpp b/lib/Target/SystemZ/SystemZElimCompare.cpp index 07afc86acba..b8a77db0f84 100644 --- a/lib/Target/SystemZ/SystemZElimCompare.cpp +++ b/lib/Target/SystemZ/SystemZElimCompare.cpp @@ -122,6 +122,12 @@ static bool resultTests(MachineInstr *MI, unsigned Reg, unsigned SubReg) { case SystemZ::LTR: case SystemZ::LTGR: case SystemZ::LTGFR: + case SystemZ::LER: + case SystemZ::LDR: + case SystemZ::LXR: + case SystemZ::LTEBR: + case SystemZ::LTDBR: + case SystemZ::LTXBR: if (MI->getOperand(1).getReg() == Reg && MI->getOperand(1).getSubReg() == SubReg) return true; @@ -230,15 +236,12 @@ adjustCCMasksForInstr(MachineInstr *MI, MachineInstr *Compare, unsigned MIFlags = Desc.TSFlags; // See which compare-style condition codes are available. - unsigned ReusableCCMask = 0; - if (MIFlags & SystemZII::CCHasZero) - ReusableCCMask |= SystemZ::CCMASK_CMP_EQ; + unsigned ReusableCCMask = SystemZII::getCompareZeroCCMask(MIFlags); // For unsigned comparisons with zero, only equality makes sense. unsigned CompareFlags = Compare->getDesc().TSFlags; - if (!(CompareFlags & SystemZII::IsLogical) && - (MIFlags & SystemZII::CCHasOrder)) - ReusableCCMask |= SystemZ::CCMASK_CMP_LT | SystemZ::CCMASK_CMP_GT; + if (CompareFlags & SystemZII::IsLogical) + ReusableCCMask &= SystemZ::CCMASK_CMP_EQ; if (ReusableCCMask == 0) return false; @@ -297,6 +300,21 @@ adjustCCMasksForInstr(MachineInstr *MI, MachineInstr *Compare, return true; } +// Return true if Compare is a comparison against zero. +static bool isCompareZero(MachineInstr *Compare) { + switch (Compare->getOpcode()) { + case SystemZ::LTEBRCompare: + case SystemZ::LTDBRCompare: + case SystemZ::LTXBRCompare: + return true; + + default: + return (Compare->getNumExplicitOperands() == 2 && + Compare->getOperand(1).isImm() && + Compare->getOperand(1).getImm() == 0); + } +} + // Try to optimize cases where comparison instruction Compare is testing // a value against zero. Return true on success and if Compare should be // deleted as dead. CCUsers is the list of instructions that use the CC @@ -304,10 +322,7 @@ adjustCCMasksForInstr(MachineInstr *MI, MachineInstr *Compare, bool SystemZElimCompare:: optimizeCompareZero(MachineInstr *Compare, SmallVectorImpl &CCUsers) { - // Check whether this is a comparison against zero. - if (Compare->getNumExplicitOperands() != 2 || - !Compare->getOperand(1).isImm() || - Compare->getOperand(1).getImm() != 0) + if (!isCompareZero(Compare)) return false; // Search back for CC results that are based on the first operand. diff --git a/lib/Target/SystemZ/SystemZInstrFP.td b/lib/Target/SystemZ/SystemZInstrFP.td index 47d864b7977..b903b519758 100644 --- a/lib/Target/SystemZ/SystemZInstrFP.td +++ b/lib/Target/SystemZ/SystemZInstrFP.td @@ -41,7 +41,7 @@ let neverHasSideEffects = 1 in { // Moves between two floating-point registers that also set the condition // codes. -let Defs = [CC] in { +let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0xF in { defm LTEBR : LoadAndTestRRE<"lteb", 0xB302, FP32>; defm LTDBR : LoadAndTestRRE<"ltdb", 0xB312, FP64>; defm LTXBR : LoadAndTestRRE<"ltxb", 0xB342, FP128>; @@ -149,15 +149,13 @@ def LXEB : UnaryRXE<"lxeb", 0xED06, extloadf32, FP128, 4>; def LXDB : UnaryRXE<"lxdb", 0xED05, extloadf64, FP128, 8>; // Convert a signed integer register value to a floating-point one. -let Defs = [CC] in { - def CEFBR : UnaryRRE<"cefb", 0xB394, sint_to_fp, FP32, GR32>; - def CDFBR : UnaryRRE<"cdfb", 0xB395, sint_to_fp, FP64, GR32>; - def CXFBR : UnaryRRE<"cxfb", 0xB396, sint_to_fp, FP128, GR32>; +def CEFBR : UnaryRRE<"cefb", 0xB394, sint_to_fp, FP32, GR32>; +def CDFBR : UnaryRRE<"cdfb", 0xB395, sint_to_fp, FP64, GR32>; +def CXFBR : UnaryRRE<"cxfb", 0xB396, sint_to_fp, FP128, GR32>; - def CEGBR : UnaryRRE<"cegb", 0xB3A4, sint_to_fp, FP32, GR64>; - def CDGBR : UnaryRRE<"cdgb", 0xB3A5, sint_to_fp, FP64, GR64>; - def CXGBR : UnaryRRE<"cxgb", 0xB3A6, sint_to_fp, FP128, GR64>; -} +def CEGBR : UnaryRRE<"cegb", 0xB3A4, sint_to_fp, FP32, GR64>; +def CDGBR : UnaryRRE<"cdgb", 0xB3A5, sint_to_fp, FP64, GR64>; +def CXGBR : UnaryRRE<"cxgb", 0xB3A6, sint_to_fp, FP128, GR64>; // Convert a floating-point register value to a signed integer value, // with the second operand (modifier M3) specifying the rounding mode. @@ -185,21 +183,21 @@ def : Pat<(i64 (fp_to_sint FP128:$src)), (CGXBR 5, FP128:$src)>; //===----------------------------------------------------------------------===// // Negation (Load Complement). -let Defs = [CC] in { +let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0xF in { def LCEBR : UnaryRRE<"lceb", 0xB303, fneg, FP32, FP32>; def LCDBR : UnaryRRE<"lcdb", 0xB313, fneg, FP64, FP64>; def LCXBR : UnaryRRE<"lcxb", 0xB343, fneg, FP128, FP128>; } // Absolute value (Load Positive). -let Defs = [CC] in { +let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0xF in { def LPEBR : UnaryRRE<"lpeb", 0xB300, fabs, FP32, FP32>; def LPDBR : UnaryRRE<"lpdb", 0xB310, fabs, FP64, FP64>; def LPXBR : UnaryRRE<"lpxb", 0xB340, fabs, FP128, FP128>; } // Negative absolute value (Load Negative). -let Defs = [CC] in { +let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0xF in { def LNEBR : UnaryRRE<"lneb", 0xB301, fnabs, FP32, FP32>; def LNDBR : UnaryRRE<"lndb", 0xB311, fnabs, FP64, FP64>; def LNXBR : UnaryRRE<"lnxb", 0xB341, fnabs, FP128, FP128>; @@ -219,11 +217,9 @@ def SQDB : UnaryRXE<"sqdb", 0xED15, loadu, FP64, 8>; // These forms always check for inexact conditions. z196 added versions // that allow this to suppressed (as for fnearbyint), but we don't yet // support -march=z196. -let Defs = [CC] in { - def FIEBR : UnaryRRF<"fieb", 0xB357, FP32, FP32>; - def FIDBR : UnaryRRF<"fidb", 0xB35F, FP64, FP64>; - def FIXBR : UnaryRRF<"fixb", 0xB347, FP128, FP128>; -} +def FIEBR : UnaryRRF<"fieb", 0xB357, FP32, FP32>; +def FIDBR : UnaryRRF<"fidb", 0xB35F, FP64, FP64>; +def FIXBR : UnaryRRF<"fixb", 0xB347, FP128, FP128>; // frint rounds according to the current mode (modifier 0) and detects // inexact conditions. @@ -236,7 +232,7 @@ def : Pat<(frint FP128:$src), (FIXBR 0, FP128:$src)>; //===----------------------------------------------------------------------===// // Addition. -let Defs = [CC] in { +let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0xF in { let isCommutable = 1 in { def AEBR : BinaryRRE<"aeb", 0xB30A, fadd, FP32, FP32>; def ADBR : BinaryRRE<"adb", 0xB31A, fadd, FP64, FP64>; @@ -247,7 +243,7 @@ let Defs = [CC] in { } // Subtraction. -let Defs = [CC] in { +let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0xF in { def SEBR : BinaryRRE<"seb", 0xB30B, fsub, FP32, FP32>; def SDBR : BinaryRRE<"sdb", 0xB31B, fsub, FP64, FP64>; def SXBR : BinaryRRE<"sxb", 0xB34B, fsub, FP128, FP128>; @@ -317,7 +313,7 @@ def DDB : BinaryRXE<"ddb", 0xED1D, fdiv, FP64, load, 8>; // Comparisons //===----------------------------------------------------------------------===// -let Defs = [CC] in { +let Defs = [CC], CCValues = 0xF in { def CEBR : CompareRRE<"ceb", 0xB309, z_cmp, FP32, FP32>; def CDBR : CompareRRE<"cdb", 0xB319, z_cmp, FP64, FP64>; def CXBR : CompareRRE<"cxb", 0xB349, z_cmp, FP128, FP128>; diff --git a/lib/Target/SystemZ/SystemZInstrFormats.td b/lib/Target/SystemZ/SystemZInstrFormats.td index 667cab3e050..954df112693 100644 --- a/lib/Target/SystemZ/SystemZInstrFormats.td +++ b/lib/Target/SystemZ/SystemZInstrFormats.td @@ -66,12 +66,9 @@ class InstSystemZ CCValues = 0; - // True if the instruction sets CC to 0 when the result is 0. - bit CCHasZero = 0; - - // True if the instruction sets CC to 1 when the result is less than 0 - // and to 2 when the result is greater than 0. - bit CCHasOrder = 0; + // The subset of CCValues that have the same meaning as they would after + // a comparison of the first operand against zero. + bits<4> CompareZeroCCMask = 0; // True if the instruction is conditional and if the CC mask operand // comes first (as for BRC, etc.). @@ -91,11 +88,10 @@ class InstSystemZ> AccessSizeShift; @@ -49,6 +49,9 @@ namespace SystemZII { static inline unsigned getCCValues(unsigned int Flags) { return (Flags & CCValuesMask) >> CCValuesShift; } + static inline unsigned getCompareZeroCCMask(unsigned int Flags) { + return (Flags & CompareZeroCCMaskMask) >> CompareZeroCCMaskShift; + } // SystemZ MachineOperand target flags. enum { diff --git a/lib/Target/SystemZ/SystemZInstrInfo.td b/lib/Target/SystemZ/SystemZInstrInfo.td index 73a6126f032..b318d674f3c 100644 --- a/lib/Target/SystemZ/SystemZInstrInfo.td +++ b/lib/Target/SystemZ/SystemZInstrInfo.td @@ -230,7 +230,7 @@ let neverHasSideEffects = 1 in { def LR : UnaryRR <"l", 0x18, null_frag, GR32, GR32>; def LGR : UnaryRRE<"lg", 0xB904, null_frag, GR64, GR64>; } -let Defs = [CC], CCValues = 0xE, CCHasZero = 1, CCHasOrder = 1 in { +let Defs = [CC], CCValues = 0xE, CompareZeroCCMask = 0xE in { def LTR : UnaryRR <"lt", 0x12, null_frag, GR32, GR32>; def LTGR : UnaryRRE<"ltg", 0xB902, null_frag, GR64, GR64>; } @@ -276,7 +276,7 @@ let canFoldAsLoad = 1, SimpleBDXLoad = 1 in { [(set GR128:$dst, (load bdxaddr20only128:$src))]>; } } -let Defs = [CC], CCValues = 0xE, CCHasZero = 1, CCHasOrder = 1 in { +let Defs = [CC], CCValues = 0xE, CompareZeroCCMask = 0xE in { def LT : UnaryRXY<"lt", 0xE312, load, GR32, 4>; def LTG : UnaryRXY<"ltg", 0xE302, load, GR64, 8>; } @@ -374,7 +374,7 @@ let neverHasSideEffects = 1 in { def LGHR : UnaryRRE<"lgh", 0xB907, sext16, GR64, GR64>; def LGFR : UnaryRRE<"lgf", 0xB914, sext32, GR64, GR32>; } -let Defs = [CC], CCValues = 0xE, CCHasZero = 1, CCHasOrder = 1 in +let Defs = [CC], CCValues = 0xE, CompareZeroCCMask = 0xE in def LTGFR : UnaryRRE<"ltgf", 0xB912, null_frag, GR64, GR64>; // Match 32-to-64-bit sign extensions in which the source is already @@ -393,7 +393,7 @@ def LGH : UnaryRXY<"lgh", 0xE315, sextloadi16, GR64, 2>; def LGF : UnaryRXY<"lgf", 0xE314, sextloadi32, GR64, 4>; def LGHRL : UnaryRILPC<"lghrl", 0xC44, aligned_sextloadi16, GR64>; def LGFRL : UnaryRILPC<"lgfrl", 0xC4C, aligned_sextloadi32, GR64>; -let Defs = [CC], CCValues = 0xE, CCHasZero = 1, CCHasOrder = 1 in +let Defs = [CC], CCValues = 0xE, CompareZeroCCMask = 0xE in def LTGF : UnaryRXY<"ltgf", 0xE332, sextloadi32, GR64, 4>; // If the sign of a load-extend operation doesn't matter, use the signed ones. @@ -532,11 +532,11 @@ let neverHasSideEffects = 1, isAsCheapAsAMove = 1, isMoveImm = 1, //===----------------------------------------------------------------------===// let Defs = [CC] in { - let CCValues = 0xF, CCHasZero = 1 in { + let CCValues = 0xF, CompareZeroCCMask = 0x8 in { def LCR : UnaryRR <"lc", 0x13, ineg, GR32, GR32>; def LCGR : UnaryRRE<"lcg", 0xB903, ineg, GR64, GR64>; } - let CCValues = 0xE, CCHasZero = 1, CCHasOrder = 1 in + let CCValues = 0xE, CompareZeroCCMask = 0xE in def LCGFR : UnaryRRE<"lcgf", 0xB913, null_frag, GR64, GR32>; } defm : SXU; @@ -589,7 +589,7 @@ def : Pat<(or (zext32 GR32:$src), imm64hf32:$imm), //===----------------------------------------------------------------------===// // Plain addition. -let Defs = [CC], CCValues = 0xF, CCHasZero = 1 in { +let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0x8 in { // Addition of a register. let isCommutable = 1 in { defm AR : BinaryRRAndK<"a", 0x1A, 0xB9F8, add, GR32, GR32>; @@ -660,7 +660,7 @@ let Defs = [CC], Uses = [CC] in { // Plain substraction. Although immediate forms exist, we use the // add-immediate instruction instead. -let Defs = [CC], CCValues = 0xF, CCHasZero = 1 in { +let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0x8 in { // Subtraction of a register. defm SR : BinaryRRAndK<"s", 0x1B, 0xB9F9, sub, GR32, GR32>; def SGFR : BinaryRRE<"sgf", 0xB919, null_frag, GR64, GR32>; @@ -710,7 +710,7 @@ let Defs = [CC], Uses = [CC] in { let Defs = [CC] in { // ANDs of a register. - let isCommutable = 1, CCValues = 0xC, CCHasZero = 1 in { + let isCommutable = 1, CCValues = 0xC, CompareZeroCCMask = 0x8 in { defm NR : BinaryRRAndK<"n", 0x14, 0xB9F4, and, GR32, GR32>; defm NGR : BinaryRREAndK<"ng", 0xB980, 0xB9E4, and, GR64, GR64>; } @@ -730,14 +730,14 @@ let Defs = [CC] in { // ANDs of a 32-bit immediate, leaving other bits unaffected. // The CC result only reflects the 32-bit field, which means we can // use it as a zero indicator for i32 operations but not otherwise. - let isCodeGenOnly = 1, CCValues = 0xC, CCHasZero = 1 in + let isCodeGenOnly = 1, CCValues = 0xC, CompareZeroCCMask = 0x8 in def NILF32 : BinaryRIL<"nilf", 0xC0B, and, GR32, uimm32>; def NILF : BinaryRIL<"nilf", 0xC0B, and, GR64, imm64lf32c>; def NIHF : BinaryRIL<"nihf", 0xC0A, and, GR64, imm64hf32c>; } // ANDs of memory. - let CCValues = 0xC, CCHasZero = 1 in { + let CCValues = 0xC, CompareZeroCCMask = 0x8 in { defm N : BinaryRXPair<"n", 0x54, 0xE354, and, GR32, load, 4>; def NG : BinaryRXY<"ng", 0xE380, and, GR64, load, 8>; } @@ -754,7 +754,7 @@ defm : RMWIByte; let Defs = [CC] in { // ORs of a register. - let isCommutable = 1, CCValues = 0xC, CCHasZero = 1 in { + let isCommutable = 1, CCValues = 0xC, CompareZeroCCMask = 0x8 in { defm OR : BinaryRRAndK<"o", 0x16, 0xB9F6, or, GR32, GR32>; defm OGR : BinaryRREAndK<"og", 0xB981, 0xB9E6, or, GR64, GR64>; } @@ -773,13 +773,13 @@ let Defs = [CC] in { // ORs of a 32-bit immediate, leaving other bits unaffected. // The CC result only reflects the 32-bit field, which means we can // use it as a zero indicator for i32 operations but not otherwise. - let isCodeGenOnly = 1, CCValues = 0xC, CCHasZero = 1 in + let isCodeGenOnly = 1, CCValues = 0xC, CompareZeroCCMask = 0x8 in def OILF32 : BinaryRIL<"oilf", 0xC0D, or, GR32, uimm32>; def OILF : BinaryRIL<"oilf", 0xC0D, or, GR64, imm64lf32>; def OIHF : BinaryRIL<"oihf", 0xC0C, or, GR64, imm64hf32>; // ORs of memory. - let CCValues = 0xC, CCHasZero = 1 in { + let CCValues = 0xC, CompareZeroCCMask = 0x8 in { defm O : BinaryRXPair<"o", 0x56, 0xE356, or, GR32, load, 4>; def OG : BinaryRXY<"og", 0xE381, or, GR64, load, 8>; } @@ -796,7 +796,7 @@ defm : RMWIByte; let Defs = [CC] in { // XORs of a register. - let isCommutable = 1, CCValues = 0xC, CCHasZero = 1 in { + let isCommutable = 1, CCValues = 0xC, CompareZeroCCMask = 0x8 in { defm XR : BinaryRRAndK<"x", 0x17, 0xB9F7, xor, GR32, GR32>; defm XGR : BinaryRREAndK<"xg", 0xB982, 0xB9E7, xor, GR64, GR64>; } @@ -804,13 +804,13 @@ let Defs = [CC] in { // XORs of a 32-bit immediate, leaving other bits unaffected. // The CC result only reflects the 32-bit field, which means we can // use it as a zero indicator for i32 operations but not otherwise. - let isCodeGenOnly = 1, CCValues = 0xC, CCHasZero = 1 in + let isCodeGenOnly = 1, CCValues = 0xC, CompareZeroCCMask = 0x8 in def XILF32 : BinaryRIL<"xilf", 0xC07, xor, GR32, uimm32>; def XILF : BinaryRIL<"xilf", 0xC07, xor, GR64, imm64lf32>; def XIHF : BinaryRIL<"xihf", 0xC06, xor, GR64, imm64hf32>; // XORs of memory. - let CCValues = 0xC, CCHasZero = 1 in { + let CCValues = 0xC, CompareZeroCCMask = 0x8 in { defm X : BinaryRXPair<"x",0x57, 0xE357, xor, GR32, load, 4>; def XG : BinaryRXY<"xg", 0xE382, xor, GR64, load, 8>; } @@ -886,7 +886,7 @@ let neverHasSideEffects = 1 in { } // Arithmetic shift right. -let Defs = [CC], CCValues = 0xE, CCHasZero = 1, CCHasOrder = 1 in { +let Defs = [CC], CCValues = 0xE, CompareZeroCCMask = 0xE in { defm SRA : ShiftRSAndK<"sra", 0x8A, 0xEBDC, sra, GR32>; def SRAG : ShiftRSY<"srag", 0xEB0A, sra, GR64>; } @@ -903,7 +903,7 @@ let neverHasSideEffects = 1 in { let Defs = [CC] in { let isCodeGenOnly = 1 in def RISBG32 : RotateSelectRIEf<"risbg", 0xEC55, GR32, GR32>; - let CCValues = 0xE, CCHasZero = 1, CCHasOrder = 1 in + let CCValues = 0xE, CompareZeroCCMask = 0xE in def RISBG : RotateSelectRIEf<"risbg", 0xEC55, GR64, GR64>; } diff --git a/test/CodeGen/SystemZ/fp-cmp-04.ll b/test/CodeGen/SystemZ/fp-cmp-04.ll new file mode 100644 index 00000000000..8d842164fa4 --- /dev/null +++ b/test/CodeGen/SystemZ/fp-cmp-04.ll @@ -0,0 +1,348 @@ +; Test that floating-point compares are ommitted if CC already has the +; right value. +; +; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z10 | FileCheck %s + +declare float @llvm.fabs.f32(float %f) + +; Test addition followed by EQ, which can use the CC result of the addition. +define float @f1(float %a, float %b, float *%dest) { +; CHECK-LABEL: f1: +; CHECK: aebr %f0, %f2 +; CHECK-NEXT: je .L{{.*}} +; CHECK: br %r14 +entry: + %res = fadd float %a, %b + %cmp = fcmp oeq float %res, 0.0 + br i1 %cmp, label %exit, label %store + +store: + store float %b, float *%dest + br label %exit + +exit: + ret float %res +} + +; ...and again with LT. +define float @f2(float %a, float %b, float *%dest) { +; CHECK-LABEL: f2: +; CHECK: aebr %f0, %f2 +; CHECK-NEXT: jl .L{{.*}} +; CHECK: br %r14 +entry: + %res = fadd float %a, %b + %cmp = fcmp olt float %res, 0.0 + br i1 %cmp, label %exit, label %store + +store: + store float %b, float *%dest + br label %exit + +exit: + ret float %res +} + +; ...and again with GT. +define float @f3(float %a, float %b, float *%dest) { +; CHECK-LABEL: f3: +; CHECK: aebr %f0, %f2 +; CHECK-NEXT: jh .L{{.*}} +; CHECK: br %r14 +entry: + %res = fadd float %a, %b + %cmp = fcmp ogt float %res, 0.0 + br i1 %cmp, label %exit, label %store + +store: + store float %b, float *%dest + br label %exit + +exit: + ret float %res +} + +; ...and again with UEQ. +define float @f4(float %a, float %b, float *%dest) { +; CHECK-LABEL: f4: +; CHECK: aebr %f0, %f2 +; CHECK-NEXT: jnlh .L{{.*}} +; CHECK: br %r14 +entry: + %res = fadd float %a, %b + %cmp = fcmp ueq float %res, 0.0 + br i1 %cmp, label %exit, label %store + +store: + store float %b, float *%dest + br label %exit + +exit: + ret float %res +} + +; Subtraction also provides a zero-based CC value. +define float @f5(float %a, float %b, float *%dest) { +; CHECK-LABEL: f5: +; CHECK: seb %f0, 0(%r2) +; CHECK-NEXT: jnhe .L{{.*}} +; CHECK: br %r14 +entry: + %cur = load float *%dest + %res = fsub float %a, %cur + %cmp = fcmp ult float %res, 0.0 + br i1 %cmp, label %exit, label %store + +store: + store float %b, float *%dest + br label %exit + +exit: + ret float %res +} + +; Test the result of LOAD POSITIVE. +define float @f6(float %dummy, float %a, float *%dest) { +; CHECK-LABEL: f6: +; CHECK: lpebr %f0, %f2 +; CHECK-NEXT: jh .L{{.*}} +; CHECK: br %r14 +entry: + %res = call float @llvm.fabs.f32(float %a) + %cmp = fcmp ogt float %res, 0.0 + br i1 %cmp, label %exit, label %store + +store: + store float %res, float *%dest + br label %exit + +exit: + ret float %res +} + +; Test the result of LOAD NEGATIVE. +define float @f7(float %dummy, float %a, float *%dest) { +; CHECK-LABEL: f7: +; CHECK: lnebr %f0, %f2 +; CHECK-NEXT: jl .L{{.*}} +; CHECK: br %r14 +entry: + %abs = call float @llvm.fabs.f32(float %a) + %res = fsub float -0.0, %abs + %cmp = fcmp olt float %res, 0.0 + br i1 %cmp, label %exit, label %store + +store: + store float %res, float *%dest + br label %exit + +exit: + ret float %res +} + +; Test the result of LOAD COMPLEMENT. +define float @f8(float %dummy, float %a, float *%dest) { +; CHECK-LABEL: f8: +; CHECK: lcebr %f0, %f2 +; CHECK-NEXT: jle .L{{.*}} +; CHECK: br %r14 +entry: + %res = fsub float -0.0, %a + %cmp = fcmp ole float %res, 0.0 + br i1 %cmp, label %exit, label %store + +store: + store float %res, float *%dest + br label %exit + +exit: + ret float %res +} + +; Multiplication (for example) does not modify CC. +define float @f9(float %a, float %b, float *%dest) { +; CHECK-LABEL: f9: +; CHECK: meebr %f0, %f2 +; CHECK-NEXT: ltebr %f0, %f0 +; CHECK-NEXT: jlh .L{{.*}} +; CHECK: br %r14 +entry: + %res = fmul float %a, %b + %cmp = fcmp one float %res, 0.0 + br i1 %cmp, label %exit, label %store + +store: + store float %b, float *%dest + br label %exit + +exit: + ret float %res +} + +; Test a combination involving a CC-setting instruction followed by +; a non-CC-setting instruction. +define float @f10(float %a, float %b, float %c, float *%dest) { +; CHECK-LABEL: f10: +; CHECK: aebr %f0, %f2 +; CHECK-NEXT: debr %f0, %f4 +; CHECK-NEXT: ltebr %f0, %f0 +; CHECK-NEXT: jne .L{{.*}} +; CHECK: br %r14 +entry: + %add = fadd float %a, %b + %res = fdiv float %add, %c + %cmp = fcmp une float %res, 0.0 + br i1 %cmp, label %exit, label %store + +store: + store float %b, float *%dest + br label %exit + +exit: + ret float %res +} + +; Test a case where CC is set based on a different register from the +; compare input. +define float @f11(float %a, float %b, float %c, float *%dest1, float *%dest2) { +; CHECK-LABEL: f11: +; CHECK: aebr %f0, %f2 +; CHECK-NEXT: sebr %f4, %f0 +; CHECK-NEXT: ste %f4, 0(%r2) +; CHECK-NEXT: ltebr %f0, %f0 +; CHECK-NEXT: je .L{{.*}} +; CHECK: br %r14 +entry: + %add = fadd float %a, %b + %sub = fsub float %c, %add + store float %sub, float *%dest1 + %cmp = fcmp oeq float %add, 0.0 + br i1 %cmp, label %exit, label %store + +store: + store float %sub, float *%dest2 + br label %exit + +exit: + ret float %add +} + +; Test that LER gets converted to LTEBR where useful. +define float @f12(float %dummy, float %val, float *%dest) { +; CHECK-LABEL: f12: +; CHECK: ltebr %f0, %f2 +; CHECK-NEXT: #APP +; CHECK-NEXT: blah %f0 +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jl .L{{.*}} +; CHECK: br %r14 +entry: + call void asm sideeffect "blah $0", "{f0}"(float %val) + %cmp = fcmp olt float %val, 0.0 + br i1 %cmp, label %exit, label %store + +store: + store float %val, float *%dest + br label %exit + +exit: + ret float %val +} + +; Test that LDR gets converted to LTDBR where useful. +define double @f13(double %dummy, double %val, double *%dest) { +; CHECK-LABEL: f13: +; CHECK: ltdbr %f0, %f2 +; CHECK-NEXT: #APP +; CHECK-NEXT: blah %f0 +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jl .L{{.*}} +; CHECK: br %r14 +entry: + call void asm sideeffect "blah $0", "{f0}"(double %val) + %cmp = fcmp olt double %val, 0.0 + br i1 %cmp, label %exit, label %store + +store: + store double %val, double *%dest + br label %exit + +exit: + ret double %val +} + +; Test that LXR gets converted to LTXBR where useful. +define void @f14(fp128 *%ptr1, fp128 *%ptr2) { +; CHECK-LABEL: f14: +; CHECK: ltxbr +; CHECK-NEXT: dxbr +; CHECK-NEXT: std +; CHECK-NEXT: std +; CHECK-NEXT: mxbr +; CHECK-NEXT: std +; CHECK-NEXT: std +; CHECK-NEXT: jl .L{{.*}} +; CHECK: br %r14 +entry: + %val1 = load fp128 *%ptr1 + %val2 = load fp128 *%ptr2 + %div = fdiv fp128 %val1, %val2 + store fp128 %div, fp128 *%ptr1 + %mul = fmul fp128 %val1, %val2 + store fp128 %mul, fp128 *%ptr2 + %cmp = fcmp olt fp128 %val1, 0xL00000000000000000000000000000000 + br i1 %cmp, label %exit, label %store + +store: + call void asm sideeffect "blah", ""() + br label %exit + +exit: + ret void +} + +; Test a case where it is the source rather than destination of LER that +; we need. +define float @f15(float %val, float %dummy, float *%dest) { +; CHECK-LABEL: f15: +; CHECK: ltebr %f2, %f0 +; CHECK-NEXT: #APP +; CHECK-NEXT: blah %f2 +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jl .L{{.*}} +; CHECK: br %r14 +entry: + call void asm sideeffect "blah $0", "{f2}"(float %val) + %cmp = fcmp olt float %val, 0.0 + br i1 %cmp, label %exit, label %store + +store: + store float %val, float *%dest + br label %exit + +exit: + ret float %val +} + +; Test a case where it is the source rather than destination of LDR that +; we need. +define double @f16(double %val, double %dummy, double *%dest) { +; CHECK-LABEL: f16: +; CHECK: ltdbr %f2, %f0 +; CHECK-NEXT: #APP +; CHECK-NEXT: blah %f2 +; CHECK-NEXT: #NO_APP +; CHECK-NEXT: jl .L{{.*}} +; CHECK: br %r14 +entry: + call void asm sideeffect "blah $0", "{f2}"(double %val) + %cmp = fcmp olt double %val, 0.0 + br i1 %cmp, label %exit, label %store + +store: + store double %val, double *%dest + br label %exit + +exit: + ret double %val +}