diff --git a/lib/Target/SystemZ/SystemZISelLowering.cpp b/lib/Target/SystemZ/SystemZISelLowering.cpp index 180c631ce13..9fc56fe9167 100644 --- a/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -1069,73 +1069,33 @@ static void adjustSubwordCmp(SelectionDAG &DAG, bool &IsUnsigned, CmpOp1 = DAG.getConstant(Value, MVT::i32); } -// Return true if a comparison described by CCMask, CmpOp0 and CmpOp1 -// is an equality comparison that is better implemented using unsigned -// rather than signed comparison instructions. -static bool preferUnsignedComparison(SDValue CmpOp0, SDValue CmpOp1, - unsigned CCMask) { - // The test must be for equality or inequality. - if (CCMask != SystemZ::CCMASK_CMP_EQ && CCMask != SystemZ::CCMASK_CMP_NE) - return false; - - if (CmpOp1.getOpcode() == ISD::Constant) { - uint64_t Value = cast(CmpOp1)->getSExtValue(); - - // If we're comparing with memory, prefer unsigned comparisons for - // values that are in the unsigned 16-bit range but not the signed - // 16-bit range. We want to use CLFHSI and CLGHSI. - if (CmpOp0.hasOneUse() && - ISD::isNormalLoad(CmpOp0.getNode()) && - (Value >= 32768 && Value < 65536)) - return true; - - // Use unsigned comparisons for values that are in the CLGFI range - // but not in the CGFI range. - if (CmpOp0.getValueType() == MVT::i64 && (Value >> 31) == 1) - return true; - - return false; - } - - // Prefer CL for zero-extended loads. - if (CmpOp1.getOpcode() == ISD::ZERO_EXTEND || - ISD::isZEXTLoad(CmpOp1.getNode())) - return true; - - // ...and for "in-register" zero extensions. - if (CmpOp1.getOpcode() == ISD::AND && CmpOp1.getValueType() == MVT::i64) { - SDValue Mask = CmpOp1.getOperand(1); - if (Mask.getOpcode() == ISD::Constant && - cast(Mask)->getZExtValue() == 0xffffffff) - return true; - } - - return false; -} - -// Return true if Op is either an unextended load, or a load with the -// extension type given by IsUnsigned. -static bool isNaturalMemoryOperand(SDValue Op, bool IsUnsigned) { +// Return true if Op is either an unextended load, or a load suitable +// for integer register-memory comparisons of type ICmpType. +static bool isNaturalMemoryOperand(SDValue Op, unsigned ICmpType) { LoadSDNode *Load = dyn_cast(Op.getNode()); - if (Load) + if (Load) { + // There are no instructions to compare a register with a memory byte. + if (Load->getMemoryVT() == MVT::i8) + return false; + // Otherwise decide on extension type. switch (Load->getExtensionType()) { case ISD::NON_EXTLOAD: - case ISD::EXTLOAD: return true; case ISD::SEXTLOAD: - return !IsUnsigned; + return ICmpType != SystemZICMP::UnsignedOnly; case ISD::ZEXTLOAD: - return IsUnsigned; + return ICmpType != SystemZICMP::SignedOnly; default: break; } + } return false; } // Return true if it is better to swap comparison operands Op0 and Op1. -// IsUnsigned says whether an integer comparison is signed or unsigned. +// ICmpType is the type of an integer comparison. static bool shouldSwapCmpOperands(SDValue Op0, SDValue Op1, - bool IsUnsigned) { + unsigned ICmpType) { // Leave f128 comparisons alone, since they have no memory forms. if (Op0.getValueType() == MVT::f128) return false; @@ -1154,23 +1114,22 @@ static bool shouldSwapCmpOperands(SDValue Op0, SDValue Op1, // Look for cases where Cmp0 is a single-use load and Cmp1 isn't. // In that case we generally prefer the memory to be second. - if ((isNaturalMemoryOperand(Op0, IsUnsigned) && Op0.hasOneUse()) && - !(isNaturalMemoryOperand(Op1, IsUnsigned) && Op1.hasOneUse())) { + if ((isNaturalMemoryOperand(Op0, ICmpType) && Op0.hasOneUse()) && + !(isNaturalMemoryOperand(Op1, ICmpType) && Op1.hasOneUse())) { // The only exceptions are when the second operand is a constant and // we can use things like CHHSI. if (!COp1) return true; - if (IsUnsigned) { - // The memory-immediate instructions require 16-bit unsigned integers. - if (isUInt<16>(COp1->getZExtValue())) - return false; - } else { - // There are no comparisons between integers and signed memory bytes. - // The others require 16-bit signed integers. - if (cast(Op0.getNode())->getMemoryVT() == MVT::i8 || - isInt<16>(COp1->getSExtValue())) - return false; - } + // The unsigned memory-immediate instructions can handle 16-bit + // unsigned integers. + if (ICmpType != SystemZICMP::SignedOnly && + isUInt<16>(COp1->getZExtValue())) + return false; + // The signed memory-immediate instructions can handle 16-bit + // signed integers. + if (ICmpType != SystemZICMP::UnsignedOnly && + isInt<16>(COp1->getSExtValue())) + return false; return true; } return false; @@ -1182,9 +1141,9 @@ static bool shouldSwapCmpOperands(SDValue Op0, SDValue Op1, // BitSize is the number of bits in the operands. Return the CC mask that // should be used for the TEST UNDER MASK result, or 0 if the condition is // too complex. -static unsigned getTestUnderMaskCond(unsigned BitSize, unsigned Opcode, - unsigned CCMask, uint64_t Mask, - uint64_t CmpVal) { +static unsigned getTestUnderMaskCond(unsigned BitSize, unsigned CCMask, + uint64_t Mask, uint64_t CmpVal, + unsigned ICmpType) { assert(Mask != 0 && "ANDs with zero should have been removed by now"); // Work out the masks for the lowest and highest bits. @@ -1194,8 +1153,7 @@ static unsigned getTestUnderMaskCond(unsigned BitSize, unsigned Opcode, // Signed ordered comparisons are effectively unsigned if the sign // bit is dropped. - bool EffectivelyUnsigned = (Opcode == SystemZISD::UCMP - || HighShift < BitSize - 1); + bool EffectivelyUnsigned = (ICmpType != SystemZICMP::SignedOnly); // Check for equality comparisons with 0, or the equivalent. if (CmpVal == 0) { @@ -1274,7 +1232,7 @@ static unsigned getTestUnderMaskCond(unsigned BitSize, unsigned Opcode, // TM version if so. static void adjustForTestUnderMask(unsigned &Opcode, SDValue &CmpOp0, SDValue &CmpOp1, unsigned &CCValid, - unsigned &CCMask) { + unsigned &CCMask, unsigned ICmpType) { // Check that we have a comparison with a constant. ConstantSDNode *ConstCmpOp1 = dyn_cast(CmpOp1); if (!ConstCmpOp1) @@ -1298,8 +1256,9 @@ static void adjustForTestUnderMask(unsigned &Opcode, SDValue &CmpOp0, // Check whether the combination of mask, comparison value and comparison // type are suitable. unsigned BitSize = CmpOp0.getValueType().getSizeInBits(); - unsigned NewCCMask = getTestUnderMaskCond(BitSize, Opcode, CCMask, MaskVal, - ConstCmpOp1->getZExtValue()); + unsigned NewCCMask = getTestUnderMaskCond(BitSize, CCMask, MaskVal, + ConstCmpOp1->getZExtValue(), + ICmpType); if (!NewCCMask) return; @@ -1315,24 +1274,39 @@ static void adjustForTestUnderMask(unsigned &Opcode, SDValue &CmpOp0, // 2-bit result in CC. Set CCValid to the CCMASK_* of all possible // 2-bit results and CCMask to the subset of those results that are // associated with Cond. -static SDValue emitCmp(SelectionDAG &DAG, SDLoc DL, SDValue CmpOp0, - SDValue CmpOp1, ISD::CondCode Cond, unsigned &CCValid, +static SDValue emitCmp(const SystemZTargetMachine &TM, SelectionDAG &DAG, + SDLoc DL, SDValue CmpOp0, SDValue CmpOp1, + ISD::CondCode Cond, unsigned &CCValid, unsigned &CCMask) { bool IsUnsigned = false; CCMask = CCMaskForCondCode(Cond); - if (CmpOp0.getValueType().isFloatingPoint()) + unsigned Opcode, ICmpType = 0; + if (CmpOp0.getValueType().isFloatingPoint()) { CCValid = SystemZ::CCMASK_FCMP; - else { + Opcode = SystemZISD::FCMP; + } else { IsUnsigned = CCMask & SystemZ::CCMASK_CMP_UO; CCValid = SystemZ::CCMASK_ICMP; CCMask &= CCValid; adjustZeroCmp(DAG, IsUnsigned, CmpOp0, CmpOp1, CCMask); adjustSubwordCmp(DAG, IsUnsigned, CmpOp0, CmpOp1, CCMask); - if (preferUnsignedComparison(CmpOp0, CmpOp1, CCMask)) - IsUnsigned = true; + Opcode = SystemZISD::ICMP; + // Choose the type of comparison. Equality and inequality tests can + // use either signed or unsigned comparisons. The choice also doesn't + // matter if both sign bits are known to be clear. In those cases we + // want to give the main isel code the freedom to choose whichever + // form fits best. + if (CCMask == SystemZ::CCMASK_CMP_EQ || + CCMask == SystemZ::CCMASK_CMP_NE || + (DAG.SignBitIsZero(CmpOp0) && DAG.SignBitIsZero(CmpOp1))) + ICmpType = SystemZICMP::Any; + else if (IsUnsigned) + ICmpType = SystemZICMP::UnsignedOnly; + else + ICmpType = SystemZICMP::SignedOnly; } - if (shouldSwapCmpOperands(CmpOp0, CmpOp1, IsUnsigned)) { + if (shouldSwapCmpOperands(CmpOp0, CmpOp1, ICmpType)) { std::swap(CmpOp0, CmpOp1); CCMask = ((CCMask & SystemZ::CCMASK_CMP_EQ) | (CCMask & SystemZ::CCMASK_CMP_GT ? SystemZ::CCMASK_CMP_LT : 0) | @@ -1340,8 +1314,10 @@ static SDValue emitCmp(SelectionDAG &DAG, SDLoc DL, SDValue CmpOp0, (CCMask & SystemZ::CCMASK_CMP_UO)); } - unsigned Opcode = (IsUnsigned ? SystemZISD::UCMP : SystemZISD::CMP); - adjustForTestUnderMask(Opcode, CmpOp0, CmpOp1, CCValid, CCMask); + adjustForTestUnderMask(Opcode, CmpOp0, CmpOp1, CCValid, CCMask, ICmpType); + if (Opcode == SystemZISD::ICMP) + return DAG.getNode(Opcode, DL, MVT::Glue, CmpOp0, CmpOp1, + DAG.getConstant(ICmpType, MVT::i32)); return DAG.getNode(Opcode, DL, MVT::Glue, CmpOp0, CmpOp1); } @@ -1391,7 +1367,7 @@ SDValue SystemZTargetLowering::lowerBR_CC(SDValue Op, SelectionDAG &DAG) const { SDLoc DL(Op); unsigned CCValid, CCMask; - SDValue Flags = emitCmp(DAG, DL, CmpOp0, CmpOp1, CC, CCValid, CCMask); + SDValue Flags = emitCmp(TM, DAG, DL, CmpOp0, CmpOp1, CC, CCValid, CCMask); return DAG.getNode(SystemZISD::BR_CCMASK, DL, Op.getValueType(), Chain, DAG.getConstant(CCValid, MVT::i32), DAG.getConstant(CCMask, MVT::i32), Dest, Flags); @@ -1407,7 +1383,7 @@ SDValue SystemZTargetLowering::lowerSELECT_CC(SDValue Op, SDLoc DL(Op); unsigned CCValid, CCMask; - SDValue Flags = emitCmp(DAG, DL, CmpOp0, CmpOp1, CC, CCValid, CCMask); + SDValue Flags = emitCmp(TM, DAG, DL, CmpOp0, CmpOp1, CC, CCValid, CCMask); SmallVector Ops; Ops.push_back(TrueOp); @@ -2041,8 +2017,8 @@ const char *SystemZTargetLowering::getTargetNodeName(unsigned Opcode) const { OPCODE(CALL); OPCODE(SIBCALL); OPCODE(PCREL_WRAPPER); - OPCODE(CMP); - OPCODE(UCMP); + OPCODE(ICMP); + OPCODE(FCMP); OPCODE(TM); OPCODE(BR_CCMASK); OPCODE(SELECT_CCMASK); diff --git a/lib/Target/SystemZ/SystemZISelLowering.h b/lib/Target/SystemZ/SystemZISelLowering.h index 8b2d19a1d2d..500abcef929 100644 --- a/lib/Target/SystemZ/SystemZISelLowering.h +++ b/lib/Target/SystemZ/SystemZISelLowering.h @@ -38,12 +38,12 @@ namespace SystemZISD { // accesses (LARL). Operand 0 is the address. PCREL_WRAPPER, - // Signed integer and floating-point comparisons. The operands are the - // two values to compare. - CMP, + // Integer comparisons. There are three operands: the two values + // to compare, and an integer of type SystemZICMP. + ICMP, - // Likewise unsigned integer comparison. - UCMP, + // Floating-point comparisons. The two operands are the values to compare. + FCMP, // Test under mask. The first operand is ANDed with the second operand // and the condition codes are set on the result. @@ -162,6 +162,16 @@ namespace SystemZISD { }; } +namespace SystemZICMP { + // Describes whether an integer comparison needs to be signed or unsigned, + // or whether either type is OK. + enum { + Any, + UnsignedOnly, + SignedOnly + }; +} + class SystemZSubtarget; class SystemZTargetMachine; diff --git a/lib/Target/SystemZ/SystemZInstrFP.td b/lib/Target/SystemZ/SystemZInstrFP.td index 24adaeec0cd..576f6668048 100644 --- a/lib/Target/SystemZ/SystemZInstrFP.td +++ b/lib/Target/SystemZ/SystemZInstrFP.td @@ -349,12 +349,12 @@ def DDB : BinaryRXE<"ddb", 0xED1D, fdiv, FP64, load, 8>; //===----------------------------------------------------------------------===// 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>; + def CEBR : CompareRRE<"ceb", 0xB309, z_fcmp, FP32, FP32>; + def CDBR : CompareRRE<"cdb", 0xB319, z_fcmp, FP64, FP64>; + def CXBR : CompareRRE<"cxb", 0xB349, z_fcmp, FP128, FP128>; - def CEB : CompareRXE<"ceb", 0xED09, z_cmp, FP32, load, 4>; - def CDB : CompareRXE<"cdb", 0xED19, z_cmp, FP64, load, 8>; + def CEB : CompareRXE<"ceb", 0xED09, z_fcmp, FP32, load, 4>; + def CDB : CompareRXE<"cdb", 0xED19, z_fcmp, FP64, load, 8>; } //===----------------------------------------------------------------------===// diff --git a/lib/Target/SystemZ/SystemZInstrInfo.td b/lib/Target/SystemZ/SystemZInstrInfo.td index abe28a57ec4..5bfa06d87dd 100644 --- a/lib/Target/SystemZ/SystemZInstrInfo.td +++ b/lib/Target/SystemZ/SystemZInstrInfo.td @@ -954,39 +954,41 @@ let Defs = [CC] in { // Comparison //===----------------------------------------------------------------------===// -// Signed comparisons. +// Signed comparisons. We put these before the unsigned comparisons because +// some of the signed forms have COMPARE AND BRANCH equivalents whereas none +// of the unsigned forms do. let Defs = [CC], CCValues = 0xE in { // Comparison with a register. - def CR : CompareRR <"c", 0x19, z_cmp, GR32, GR32>; + def CR : CompareRR <"c", 0x19, z_scmp, GR32, GR32>; def CGFR : CompareRRE<"cgf", 0xB930, null_frag, GR64, GR32>; - def CGR : CompareRRE<"cg", 0xB920, z_cmp, GR64, GR64>; + def CGR : CompareRRE<"cg", 0xB920, z_scmp, GR64, GR64>; // Comparison with a signed 16-bit immediate. - def CHI : CompareRI<"chi", 0xA7E, z_cmp, GR32, imm32sx16>; - def CGHI : CompareRI<"cghi", 0xA7F, z_cmp, GR64, imm64sx16>; + def CHI : CompareRI<"chi", 0xA7E, z_scmp, GR32, imm32sx16>; + def CGHI : CompareRI<"cghi", 0xA7F, z_scmp, GR64, imm64sx16>; // Comparison with a signed 32-bit immediate. - def CFI : CompareRIL<"cfi", 0xC2D, z_cmp, GR32, simm32>; - def CGFI : CompareRIL<"cgfi", 0xC2C, z_cmp, GR64, imm64sx32>; + def CFI : CompareRIL<"cfi", 0xC2D, z_scmp, GR32, simm32>; + def CGFI : CompareRIL<"cgfi", 0xC2C, z_scmp, GR64, imm64sx32>; // Comparison with memory. - defm CH : CompareRXPair<"ch", 0x49, 0xE379, z_cmp, GR32, sextloadi16, 2>; - defm C : CompareRXPair<"c", 0x59, 0xE359, z_cmp, GR32, load, 4>; - def CGH : CompareRXY<"cgh", 0xE334, z_cmp, GR64, sextloadi16, 2>; - def CGF : CompareRXY<"cgf", 0xE330, z_cmp, GR64, sextloadi32, 4>; - def CG : CompareRXY<"cg", 0xE320, z_cmp, GR64, load, 8>; - def CHRL : CompareRILPC<"chrl", 0xC65, z_cmp, GR32, aligned_sextloadi16>; - def CRL : CompareRILPC<"crl", 0xC6D, z_cmp, GR32, aligned_load>; - def CGHRL : CompareRILPC<"cghrl", 0xC64, z_cmp, GR64, aligned_sextloadi16>; - def CGFRL : CompareRILPC<"cgfrl", 0xC6C, z_cmp, GR64, aligned_sextloadi32>; - def CGRL : CompareRILPC<"cgrl", 0xC68, z_cmp, GR64, aligned_load>; + defm CH : CompareRXPair<"ch", 0x49, 0xE379, z_scmp, GR32, sextloadi16, 2>; + defm C : CompareRXPair<"c", 0x59, 0xE359, z_scmp, GR32, load, 4>; + def CGH : CompareRXY<"cgh", 0xE334, z_scmp, GR64, sextloadi16, 2>; + def CGF : CompareRXY<"cgf", 0xE330, z_scmp, GR64, sextloadi32, 4>; + def CG : CompareRXY<"cg", 0xE320, z_scmp, GR64, load, 8>; + def CHRL : CompareRILPC<"chrl", 0xC65, z_scmp, GR32, aligned_sextloadi16>; + def CRL : CompareRILPC<"crl", 0xC6D, z_scmp, GR32, aligned_load>; + def CGHRL : CompareRILPC<"cghrl", 0xC64, z_scmp, GR64, aligned_sextloadi16>; + def CGFRL : CompareRILPC<"cgfrl", 0xC6C, z_scmp, GR64, aligned_sextloadi32>; + def CGRL : CompareRILPC<"cgrl", 0xC68, z_scmp, GR64, aligned_load>; // Comparison between memory and a signed 16-bit immediate. - def CHHSI : CompareSIL<"chhsi", 0xE554, z_cmp, sextloadi16, imm32sx16>; - def CHSI : CompareSIL<"chsi", 0xE55C, z_cmp, load, imm32sx16>; - def CGHSI : CompareSIL<"cghsi", 0xE558, z_cmp, load, imm64sx16>; + def CHHSI : CompareSIL<"chhsi", 0xE554, z_scmp, sextloadi16, imm32sx16>; + def CHSI : CompareSIL<"chsi", 0xE55C, z_scmp, load, imm32sx16>; + def CGHSI : CompareSIL<"cghsi", 0xE558, z_scmp, load, imm64sx16>; } -defm : SXB; +defm : SXB; // Unsigned comparisons. let Defs = [CC], CCValues = 0xE, IsLogical = 1 in { diff --git a/lib/Target/SystemZ/SystemZOperators.td b/lib/Target/SystemZ/SystemZOperators.td index c89e31548b9..c135b3b82b0 100644 --- a/lib/Target/SystemZ/SystemZOperators.td +++ b/lib/Target/SystemZ/SystemZOperators.td @@ -15,6 +15,9 @@ def SDT_CallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i64>, SDTCisVT<1, i64>]>; def SDT_ZCall : SDTypeProfile<0, -1, [SDTCisPtrTy<0>]>; def SDT_ZCmp : SDTypeProfile<0, 2, [SDTCisSameAs<0, 1>]>; +def SDT_ZICmp : SDTypeProfile<0, 3, + [SDTCisSameAs<0, 1>, + SDTCisVT<2, i32>]>; def SDT_ZBRCCMask : SDTypeProfile<0, 3, [SDTCisVT<0, i8>, SDTCisVT<1, i8>, @@ -94,8 +97,8 @@ def z_sibcall : SDNode<"SystemZISD::SIBCALL", SDT_ZCall, [SDNPHasChain, SDNPOutGlue, SDNPOptInGlue, SDNPVariadic]>; def z_pcrel_wrapper : SDNode<"SystemZISD::PCREL_WRAPPER", SDT_ZWrapPtr, []>; -def z_cmp : SDNode<"SystemZISD::CMP", SDT_ZCmp, [SDNPOutGlue]>; -def z_ucmp : SDNode<"SystemZISD::UCMP", SDT_ZCmp, [SDNPOutGlue]>; +def z_icmp : SDNode<"SystemZISD::ICMP", SDT_ZICmp, [SDNPOutGlue]>; +def z_fcmp : SDNode<"SystemZISD::FCMP", SDT_ZCmp, [SDNPOutGlue]>; def z_tm : SDNode<"SystemZISD::TM", SDT_ZCmp, [SDNPOutGlue]>; def z_br_ccmask : SDNode<"SystemZISD::BR_CCMASK", SDT_ZBRCCMask, [SDNPHasChain, SDNPInGlue]>; @@ -163,6 +166,16 @@ def z_prefetch : SDNode<"SystemZISD::PREFETCH", SDT_ZPrefetch, // Pattern fragments //===----------------------------------------------------------------------===// +// Signed and unsigned comparisons. +def z_scmp : PatFrag<(ops node:$a, node:$b), (z_icmp node:$a, node:$b, imm), [{ + unsigned Type = cast(N->getOperand(2))->getZExtValue(); + return Type != SystemZICMP::UnsignedOnly; +}]>; +def z_ucmp : PatFrag<(ops node:$a, node:$b), (z_icmp node:$a, node:$b, imm), [{ + unsigned Type = cast(N->getOperand(2))->getZExtValue(); + return Type != SystemZICMP::SignedOnly; +}]>; + // Register sign-extend operations. Sub-32-bit values are represented as i32s. def sext8 : PatFrag<(ops node:$src), (sext_inreg node:$src, i8)>; def sext16 : PatFrag<(ops node:$src), (sext_inreg node:$src, i16)>; diff --git a/lib/Target/SystemZ/SystemZPatterns.td b/lib/Target/SystemZ/SystemZPatterns.td index bc3775f2795..481534b26a9 100644 --- a/lib/Target/SystemZ/SystemZPatterns.td +++ b/lib/Target/SystemZ/SystemZPatterns.td @@ -103,4 +103,4 @@ multiclass BlockLoadStore - : Pat<(z_cmp cls:$reg, (fpimm0)), (insn cls:$reg, cls:$reg)>; + : Pat<(z_fcmp cls:$reg, (fpimm0)), (insn cls:$reg, cls:$reg)>; diff --git a/test/CodeGen/SystemZ/branch-06.ll b/test/CodeGen/SystemZ/branch-06.ll index 13e5a843f13..2fa23b744af 100644 --- a/test/CodeGen/SystemZ/branch-06.ll +++ b/test/CodeGen/SystemZ/branch-06.ll @@ -3,6 +3,7 @@ ; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s declare i32 @foo() +@g1 = global i16 0 define void @f1(i32 %target) { ; CHECK-LABEL: f1: @@ -87,3 +88,103 @@ loop: exit: ret void } + +; Check that CRJ is used for checking equality with a zero-extending +; character load. +define void @f7(i8 *%targetptr) { +; CHECK-LABEL: f7: +; CHECK: .cfi_def_cfa_offset +; CHECK: .L[[LABEL:.*]]: +; CHECK: llc [[REG:%r[0-5]]], +; CHECK: crje %r2, [[REG]], .L[[LABEL]] + br label %loop +loop: + %val = call i32 @foo() + %byte = load i8 *%targetptr + %target = zext i8 %byte to i32 + %cond = icmp eq i32 %val, %target + br i1 %cond, label %loop, label %exit +exit: + ret void +} + +; ...and zero-extending i16 loads. +define void @f8(i16 *%targetptr) { +; CHECK-LABEL: f8: +; CHECK: .cfi_def_cfa_offset +; CHECK: .L[[LABEL:.*]]: +; CHECK: llh [[REG:%r[0-5]]], +; CHECK: crje %r2, [[REG]], .L[[LABEL]] + br label %loop +loop: + %val = call i32 @foo() + %half = load i16 *%targetptr + %target = zext i16 %half to i32 + %cond = icmp eq i32 %val, %target + br i1 %cond, label %loop, label %exit +exit: + ret void +} + +; ...unless the address is a global. +define void @f9(i16 *%targetptr) { +; CHECK-LABEL: f9: +; CHECK: .cfi_def_cfa_offset +; CHECK: .L[[LABEL:.*]]: +; CHECK: clhrl %r2, g1 +; CHECK: je .L[[LABEL]] + br label %loop +loop: + %val = call i32 @foo() + %half = load i16 *@g1 + %target = zext i16 %half to i32 + %cond = icmp eq i32 %val, %target + br i1 %cond, label %loop, label %exit +exit: + ret void +} + +; Check that CRJ is used for checking order between two zero-extending +; byte loads, even if the original comparison was unsigned. +define void @f10(i8 *%targetptr1) { +; CHECK-LABEL: f10: +; CHECK: .cfi_def_cfa_offset +; CHECK: .L[[LABEL:.*]]: +; CHECK-DAG: llc [[REG1:%r[0-5]]], 0( +; CHECK-DAG: llc [[REG2:%r[0-5]]], 1( +; CHECK: crjl [[REG1]], [[REG2]], .L[[LABEL]] + br label %loop +loop: + %val = call i32 @foo() + %targetptr2 = getelementptr i8 *%targetptr1, i64 1 + %byte1 = load i8 *%targetptr1 + %byte2 = load i8 *%targetptr2 + %ext1 = zext i8 %byte1 to i32 + %ext2 = zext i8 %byte2 to i32 + %cond = icmp ult i32 %ext1, %ext2 + br i1 %cond, label %loop, label %exit +exit: + ret void +} + +; ...likewise halfword loads. +define void @f11(i16 *%targetptr1) { +; CHECK-LABEL: f11: +; CHECK: .cfi_def_cfa_offset +; CHECK: .L[[LABEL:.*]]: +; CHECK-DAG: llh [[REG1:%r[0-5]]], 0( +; CHECK-DAG: llh [[REG2:%r[0-5]]], 2( +; CHECK: crjl [[REG1]], [[REG2]], .L[[LABEL]] + br label %loop +loop: + %val = call i32 @foo() + %targetptr2 = getelementptr i16 *%targetptr1, i64 1 + %half1 = load i16 *%targetptr1 + %half2 = load i16 *%targetptr2 + %ext1 = zext i16 %half1 to i32 + %ext2 = zext i16 %half2 to i32 + %cond = icmp ult i32 %ext1, %ext2 + br i1 %cond, label %loop, label %exit +exit: + ret void +}