summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target/SystemZ
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/SystemZ')
-rw-r--r--llvm/lib/Target/SystemZ/SystemZ.h2
-rw-r--r--llvm/lib/Target/SystemZ/SystemZElimCompare.cpp133
-rw-r--r--llvm/lib/Target/SystemZ/SystemZInstrFormats.td15
-rw-r--r--llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp8
-rw-r--r--llvm/lib/Target/SystemZ/SystemZInstrInfo.h3
-rw-r--r--llvm/lib/Target/SystemZ/SystemZInstrInfo.td13
6 files changed, 141 insertions, 33 deletions
diff --git a/llvm/lib/Target/SystemZ/SystemZ.h b/llvm/lib/Target/SystemZ/SystemZ.h
index 88cf589a3f1..0808160f627 100644
--- a/llvm/lib/Target/SystemZ/SystemZ.h
+++ b/llvm/lib/Target/SystemZ/SystemZ.h
@@ -55,7 +55,7 @@ const unsigned CCMASK_ARITH = CCMASK_ANY;
// Condition-code mask assignments for logical operations.
const unsigned CCMASK_LOGICAL_ZERO = CCMASK_0 | CCMASK_2;
-const unsigned CCMASK_LOGICAL_NONZERO = CCMASK_1 | CCMASK_2;
+const unsigned CCMASK_LOGICAL_NONZERO = CCMASK_1 | CCMASK_3;
const unsigned CCMASK_LOGICAL_CARRY = CCMASK_2 | CCMASK_3;
const unsigned CCMASK_LOGICAL_NOCARRY = CCMASK_0 | CCMASK_1;
const unsigned CCMASK_LOGICAL_BORROW = CCMASK_LOGICAL_NOCARRY;
diff --git a/llvm/lib/Target/SystemZ/SystemZElimCompare.cpp b/llvm/lib/Target/SystemZ/SystemZElimCompare.cpp
index 8b128084181..9e6d99f4305 100644
--- a/llvm/lib/Target/SystemZ/SystemZElimCompare.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZElimCompare.cpp
@@ -88,6 +88,8 @@ private:
SmallVectorImpl<MachineInstr *> &CCUsers);
bool convertToLoadAndTest(MachineInstr &MI, MachineInstr &Compare,
SmallVectorImpl<MachineInstr *> &CCUsers);
+ bool convertToLogical(MachineInstr &MI, MachineInstr &Compare,
+ SmallVectorImpl<MachineInstr *> &CCUsers);
bool adjustCCMasksForInstr(MachineInstr &MI, MachineInstr &Compare,
SmallVectorImpl<MachineInstr *> &CCUsers,
unsigned ConvOpc = 0);
@@ -303,6 +305,52 @@ bool SystemZElimCompare::convertToLoadAndTest(
return true;
}
+// See if MI is an instruction with an equivalent "logical" opcode that can
+// be used and replace MI. This is useful for EQ/NE comparisons where the
+// "nsw" flag is missing since the "logical" opcode always sets CC to reflect
+// the result being zero or non-zero.
+bool SystemZElimCompare::convertToLogical(
+ MachineInstr &MI, MachineInstr &Compare,
+ SmallVectorImpl<MachineInstr *> &CCUsers) {
+
+ unsigned ConvOpc = 0;
+ switch (MI.getOpcode()) {
+ case SystemZ::AR: ConvOpc = SystemZ::ALR; break;
+ case SystemZ::ARK: ConvOpc = SystemZ::ALRK; break;
+ case SystemZ::AGR: ConvOpc = SystemZ::ALGR; break;
+ case SystemZ::AGRK: ConvOpc = SystemZ::ALGRK; break;
+ case SystemZ::A: ConvOpc = SystemZ::AL; break;
+ case SystemZ::AY: ConvOpc = SystemZ::ALY; break;
+ case SystemZ::AG: ConvOpc = SystemZ::ALG; break;
+ default: break;
+ }
+ if (!ConvOpc || !adjustCCMasksForInstr(MI, Compare, CCUsers, ConvOpc))
+ return false;
+
+ // Operands should be identical, so just change the opcode and remove the
+ // dead flag on CC.
+ MI.setDesc(TII->get(ConvOpc));
+ MI.clearRegisterDeads(SystemZ::CC);
+ return true;
+}
+
+#ifndef NDEBUG
+static bool isAddWithImmediate(unsigned Opcode) {
+ switch(Opcode) {
+ case SystemZ::AHI:
+ case SystemZ::AHIK:
+ case SystemZ::AGHI:
+ case SystemZ::AGHIK:
+ case SystemZ::AFI:
+ case SystemZ::AIH:
+ case SystemZ::AGFI:
+ return true;
+ default: break;
+ }
+ return false;
+}
+#endif
+
// The CC users in CCUsers are testing the result of a comparison of some
// value X against zero and we know that any CC value produced by MI would
// also reflect the value of X. ConvOpc may be used to pass the transfomed
@@ -313,6 +361,8 @@ bool SystemZElimCompare::adjustCCMasksForInstr(
MachineInstr &MI, MachineInstr &Compare,
SmallVectorImpl<MachineInstr *> &CCUsers,
unsigned ConvOpc) {
+ unsigned CompareFlags = Compare.getDesc().TSFlags;
+ unsigned CompareCCValues = SystemZII::getCCValues(CompareFlags);
int Opcode = (ConvOpc ? ConvOpc : MI.getOpcode());
const MCInstrDesc &Desc = TII->get(Opcode);
unsigned MIFlags = Desc.TSFlags;
@@ -330,60 +380,97 @@ bool SystemZElimCompare::adjustCCMasksForInstr(
}
// See which compare-style condition codes are available.
- unsigned ReusableCCMask = SystemZII::getCompareZeroCCMask(MIFlags);
-
+ unsigned CCValues = SystemZII::getCCValues(MIFlags);
+ unsigned ReusableCCMask = CCValues;
// For unsigned comparisons with zero, only equality makes sense.
- unsigned CompareFlags = Compare.getDesc().TSFlags;
if (CompareFlags & SystemZII::IsLogical)
ReusableCCMask &= SystemZ::CCMASK_CMP_EQ;
-
+ unsigned OFImplies = 0;
+ bool LogicalMI = false;
+ bool MIEquivalentToCmp = false;
+ if (MI.getFlag(MachineInstr::NoSWrap) &&
+ (MIFlags & SystemZII::CCIfNoSignedWrap)) {
+ // If MI has the NSW flag set in combination with the
+ // SystemZII::CCIfNoSignedWrap flag, all CCValues are valid.
+ }
+ else if ((MIFlags & SystemZII::CCIfNoSignedWrap) &&
+ MI.getOperand(2).isImm()) {
+ // Signed addition of immediate. If adding a positive immediate
+ // overflows, the result must be less than zero. If adding a negative
+ // immediate overflows, the result must be larger than zero (except in
+ // the special case of adding the minimum value of the result range, in
+ // which case we cannot predict whether the result is larger than or
+ // equal to zero).
+ assert(isAddWithImmediate(Opcode) && "Expected an add with immediate.");
+ assert(!MI.mayLoadOrStore() && "Expected an immediate term.");
+ int64_t RHS = MI.getOperand(2).getImm();
+ if (SystemZ::GRX32BitRegClass.contains(MI.getOperand(0).getReg()) &&
+ RHS == INT32_MIN)
+ return false;
+ OFImplies = (RHS > 0 ? SystemZ::CCMASK_CMP_LT : SystemZ::CCMASK_CMP_GT);
+ }
+ else if ((MIFlags & SystemZII::IsLogical) && CCValues) {
+ // Use CCMASK_CMP_EQ to match with CCUsers. On success CCMask:s will be
+ // converted to CCMASK_LOGICAL_ZERO or CCMASK_LOGICAL_NONZERO.
+ LogicalMI = true;
+ ReusableCCMask = SystemZ::CCMASK_CMP_EQ;
+ }
+ else {
+ ReusableCCMask &= SystemZII::getCompareZeroCCMask(MIFlags);
+ assert((ReusableCCMask & ~CCValues) == 0 && "Invalid CCValues");
+ MIEquivalentToCmp =
+ ReusableCCMask == CCValues && CCValues == CompareCCValues;
+ }
if (ReusableCCMask == 0)
return false;
- unsigned CCValues = SystemZII::getCCValues(MIFlags);
- assert((ReusableCCMask & ~CCValues) == 0 && "Invalid CCValues");
-
- bool MIEquivalentToCmp =
- (ReusableCCMask == CCValues &&
- CCValues == SystemZII::getCCValues(CompareFlags));
-
if (!MIEquivalentToCmp) {
// Now check whether these flags are enough for all users.
SmallVector<MachineOperand *, 4> AlterMasks;
for (unsigned int I = 0, E = CCUsers.size(); I != E; ++I) {
- MachineInstr *MI = CCUsers[I];
+ MachineInstr *CCUserMI = CCUsers[I];
// Fail if this isn't a use of CC that we understand.
- unsigned Flags = MI->getDesc().TSFlags;
+ unsigned Flags = CCUserMI->getDesc().TSFlags;
unsigned FirstOpNum;
if (Flags & SystemZII::CCMaskFirst)
FirstOpNum = 0;
else if (Flags & SystemZII::CCMaskLast)
- FirstOpNum = MI->getNumExplicitOperands() - 2;
+ FirstOpNum = CCUserMI->getNumExplicitOperands() - 2;
else
return false;
// Check whether the instruction predicate treats all CC values
// outside of ReusableCCMask in the same way. In that case it
// doesn't matter what those CC values mean.
- unsigned CCValid = MI->getOperand(FirstOpNum).getImm();
- unsigned CCMask = MI->getOperand(FirstOpNum + 1).getImm();
+ unsigned CCValid = CCUserMI->getOperand(FirstOpNum).getImm();
+ unsigned CCMask = CCUserMI->getOperand(FirstOpNum + 1).getImm();
+ assert(CCValid == CompareCCValues && (CCMask & ~CCValid) == 0 &&
+ "Corrupt CC operands of CCUser.");
unsigned OutValid = ~ReusableCCMask & CCValid;
unsigned OutMask = ~ReusableCCMask & CCMask;
if (OutMask != 0 && OutMask != OutValid)
return false;
- AlterMasks.push_back(&MI->getOperand(FirstOpNum));
- AlterMasks.push_back(&MI->getOperand(FirstOpNum + 1));
+ AlterMasks.push_back(&CCUserMI->getOperand(FirstOpNum));
+ AlterMasks.push_back(&CCUserMI->getOperand(FirstOpNum + 1));
}
// All users are OK. Adjust the masks for MI.
for (unsigned I = 0, E = AlterMasks.size(); I != E; I += 2) {
AlterMasks[I]->setImm(CCValues);
unsigned CCMask = AlterMasks[I + 1]->getImm();
- if (CCMask & ~ReusableCCMask)
- AlterMasks[I + 1]->setImm((CCMask & ReusableCCMask) |
- (CCValues & ~ReusableCCMask));
+ if (LogicalMI) {
+ // Translate the CCMask into its "logical" value.
+ CCMask = (CCMask == SystemZ::CCMASK_CMP_EQ ?
+ SystemZ::CCMASK_LOGICAL_ZERO : SystemZ::CCMASK_LOGICAL_NONZERO);
+ CCMask &= CCValues; // Logical subtracts never set CC=0.
+ } else {
+ if (CCMask & ~ReusableCCMask)
+ CCMask = (CCMask & ReusableCCMask) | (CCValues & ~ReusableCCMask);
+ CCMask |= (CCMask & OFImplies) ? SystemZ::CCMASK_ARITH_OVERFLOW : 0;
+ }
+ AlterMasks[I + 1]->setImm(CCMask);
}
}
@@ -460,7 +547,9 @@ bool SystemZElimCompare::optimizeCompareZero(
}
// Try to eliminate Compare by reusing a CC result from MI.
if ((!CCRefs && convertToLoadAndTest(MI, Compare, CCUsers)) ||
- (!CCRefs.Def && adjustCCMasksForInstr(MI, Compare, CCUsers))) {
+ (!CCRefs.Def &&
+ (adjustCCMasksForInstr(MI, Compare, CCUsers) ||
+ convertToLogical(MI, Compare, CCUsers)))) {
EliminatedComparisons += 1;
return true;
}
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrFormats.td b/llvm/lib/Target/SystemZ/SystemZInstrFormats.td
index c9dbe3da686..ba87ddb20f9 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrFormats.td
+++ b/llvm/lib/Target/SystemZ/SystemZInstrFormats.td
@@ -75,8 +75,9 @@ class InstSystemZ<int size, dag outs, dag ins, string asmstr,
// SystemZ::CCMASK_*.
bits<4> CCValues = 0;
- // The subset of CCValues that have the same meaning as they would after
- // a comparison of the first operand against zero.
+ // The subset of CCValues that have the same meaning as they would after a
+ // comparison of the first operand against zero. "Logical" instructions
+ // leave this blank as they set CC in a different way.
bits<4> CompareZeroCCMask = 0;
// True if the instruction is conditional and if the CC mask operand
@@ -87,9 +88,16 @@ class InstSystemZ<int size, dag outs, dag ins, string asmstr,
bit CCMaskLast = 0;
// True if the instruction is the "logical" rather than "arithmetic" form,
- // in cases where a distinction exists.
+ // in cases where a distinction exists. Except for logical compares, if the
+ // instruction sets this flag along with a non-zero CCValues field, it is
+ // assumed to set CC to either CCMASK_LOGICAL_ZERO or
+ // CCMASK_LOGICAL_NONZERO.
bit IsLogical = 0;
+ // True if the (add or sub) instruction sets CC like a compare of the
+ // result against zero, but only if the 'nsw' flag is set.
+ bit CCIfNoSignedWrap = 0;
+
let TSFlags{0} = SimpleBDXLoad;
let TSFlags{1} = SimpleBDXStore;
let TSFlags{2} = Has20BitOffset;
@@ -101,6 +109,7 @@ class InstSystemZ<int size, dag outs, dag ins, string asmstr,
let TSFlags{18} = CCMaskFirst;
let TSFlags{19} = CCMaskLast;
let TSFlags{20} = IsLogical;
+ let TSFlags{21} = CCIfNoSignedWrap;
}
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
index 181a50786a2..97c8fa7aa32 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp
@@ -945,6 +945,12 @@ static void transferDeadCC(MachineInstr *OldMI, MachineInstr *NewMI) {
}
}
+static void transferMIFlag(MachineInstr *OldMI, MachineInstr *NewMI,
+ MachineInstr::MIFlag Flag) {
+ if (OldMI->getFlag(Flag))
+ NewMI->setFlag(Flag);
+}
+
MachineInstr *SystemZInstrInfo::convertToThreeAddress(
MachineFunction::iterator &MFI, MachineInstr &MI, LiveVariables *LV) const {
MachineBasicBlock *MBB = MI.getParent();
@@ -1050,6 +1056,7 @@ MachineInstr *SystemZInstrInfo::foldMemoryOperandImpl(
.addImm(0)
.addImm(MI.getOperand(2).getImm());
transferDeadCC(&MI, BuiltMI);
+ transferMIFlag(&MI, BuiltMI, MachineInstr::NoSWrap);
return BuiltMI;
}
@@ -1200,6 +1207,7 @@ MachineInstr *SystemZInstrInfo::foldMemoryOperandImpl(
if (MemDesc.TSFlags & SystemZII::HasIndex)
MIB.addReg(0);
transferDeadCC(&MI, MIB);
+ transferMIFlag(&MI, MIB, MachineInstr::NoSWrap);
return MIB;
}
}
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.h b/llvm/lib/Target/SystemZ/SystemZInstrInfo.h
index 4b4cfab1f8f..8391970c7d9 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.h
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.h
@@ -46,7 +46,8 @@ enum {
CompareZeroCCMaskShift = 14,
CCMaskFirst = (1 << 18),
CCMaskLast = (1 << 19),
- IsLogical = (1 << 20)
+ IsLogical = (1 << 20),
+ CCIfNoSignedWrap = (1 << 21)
};
static inline unsigned getAccessSize(unsigned int Flags) {
diff --git a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
index 041971ca7cb..aa981e718b5 100644
--- a/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
+++ b/llvm/lib/Target/SystemZ/SystemZInstrInfo.td
@@ -915,7 +915,7 @@ def : Pat<(or (zext32 GR32:$src), imm64hf32:$imm),
//===----------------------------------------------------------------------===//
// Addition producing a signed overflow flag.
-let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0x8 in {
+let Defs = [CC], CCValues = 0xF, CCIfNoSignedWrap = 1 in {
// Addition of a register.
let isCommutable = 1 in {
defm AR : BinaryRRAndK<"ar", 0x1A, 0xB9F8, z_sadd, GR32, GR32>;
@@ -957,7 +957,7 @@ let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0x8 in {
defm : SXB<z_sadd, GR64, AGFR>;
// Addition producing a carry.
-let Defs = [CC] in {
+let Defs = [CC], CCValues = 0xF, IsLogical = 1 in {
// Addition of a register.
let isCommutable = 1 in {
defm ALR : BinaryRRAndK<"alr", 0x1E, 0xB9FA, z_uadd, GR32, GR32>;
@@ -997,7 +997,7 @@ let Defs = [CC] in {
defm : ZXB<z_uadd, GR64, ALGFR>;
// Addition producing and using a carry.
-let Defs = [CC], Uses = [CC] in {
+let Defs = [CC], Uses = [CC], CCValues = 0xF, IsLogical = 1 in {
// Addition of a register.
def ALCR : BinaryRRE<"alcr", 0xB998, z_addcarry, GR32, GR32>;
def ALCGR : BinaryRRE<"alcgr", 0xB988, z_addcarry, GR64, GR64>;
@@ -1017,7 +1017,8 @@ def ALSIHN : BinaryRIL<"alsihn", 0xCCB, null_frag, GRH32, simm32>,
//===----------------------------------------------------------------------===//
// Subtraction producing a signed overflow flag.
-let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0x8 in {
+let Defs = [CC], CCValues = 0xF, CompareZeroCCMask = 0x8,
+ CCIfNoSignedWrap = 1 in {
// Subtraction of a register.
defm SR : BinaryRRAndK<"sr", 0x1B, 0xB9F9, z_ssub, GR32, GR32>;
def SGFR : BinaryRRE<"sgfr", 0xB919, null_frag, GR64, GR32>;
@@ -1066,7 +1067,7 @@ def : Pat<(z_saddo GR64:$src1, imm64lf32n:$src2),
(SGR GR64:$src1, (LLILF imm64lf32n:$src2))>;
// Subtraction producing a carry.
-let Defs = [CC] in {
+let Defs = [CC], CCValues = 0x7, IsLogical = 1 in {
// Subtraction of a register.
defm SLR : BinaryRRAndK<"slr", 0x1F, 0xB9FB, z_usub, GR32, GR32>;
def SLGFR : BinaryRRE<"slgfr", 0xB91B, null_frag, GR64, GR32>;
@@ -1104,7 +1105,7 @@ def : Pat<(add GR64:$src1, imm64zx32n:$src2),
(SLGFI GR64:$src1, imm64zx32n:$src2)>;
// Subtraction producing and using a carry.
-let Defs = [CC], Uses = [CC] in {
+let Defs = [CC], Uses = [CC], CCValues = 0xF, IsLogical = 1 in {
// Subtraction of a register.
def SLBR : BinaryRRE<"slbr", 0xB999, z_subcarry, GR32, GR32>;
def SLBGR : BinaryRRE<"slbgr", 0xB989, z_subcarry, GR64, GR64>;
OpenPOWER on IntegriCloud