[SystemZ] Tweak integer comparison code

The architecture has many comparison instructions, including some that
extend one of the operands.  The signed comparison instructions use sign
extensions and the unsigned comparison instructions use zero extensions.
In cases where we had a free choice between signed or unsigned comparisons,
we were trying to decide at lowering time which would best fit the available
instructions, taking things like extension type into account.  The code
to do that was getting increasingly hairy and was also making some bad
decisions.  E.g. when comparing the result of two LLCs, it is better to use
CR rather than CLR, since CR can be fused with a branch while CLR can't.

This patch removes the lowering code and instead adds an operand to
integer comparisons to say whether signed comparison is required,
whether unsigned comparison is required, or whether either is OK.
We can then leave the choice of instruction up to the normal isel code.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@190138 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Richard Sandiford 2013-09-06 11:51:39 +00:00
parent e3273b3275
commit aff1c6427c
7 changed files with 223 additions and 121 deletions

View File

@ -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<ConstantSDNode>(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<ConstantSDNode>(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<LoadSDNode>(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<LoadSDNode>(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<ConstantSDNode>(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<SDValue, 5> 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);

View File

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

View File

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

View File

@ -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<z_cmp, GR64, CGFR>;
defm : SXB<z_scmp, GR64, CGFR>;
// Unsigned comparisons.
let Defs = [CC], CCValues = 0xE, IsLogical = 1 in {

View File

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

View File

@ -103,4 +103,4 @@ multiclass BlockLoadStore<SDPatternOperator load, ValueType vt,
// registers in CLS against zero. The instruction has separate R1 and R2
// operands, but they must be the same when the instruction is used like this.
class CompareZeroFP<Instruction insn, RegisterOperand cls>
: Pat<(z_cmp cls:$reg, (fpimm0)), (insn cls:$reg, cls:$reg)>;
: Pat<(z_fcmp cls:$reg, (fpimm0)), (insn cls:$reg, cls:$reg)>;

View File

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