diff options
Diffstat (limited to 'llvm/lib/Target/SystemZ')
-rw-r--r-- | llvm/lib/Target/SystemZ/SystemZ.h | 2 | ||||
-rw-r--r-- | llvm/lib/Target/SystemZ/SystemZElimCompare.cpp | 133 | ||||
-rw-r--r-- | llvm/lib/Target/SystemZ/SystemZInstrFormats.td | 15 | ||||
-rw-r--r-- | llvm/lib/Target/SystemZ/SystemZInstrInfo.cpp | 8 | ||||
-rw-r--r-- | llvm/lib/Target/SystemZ/SystemZInstrInfo.h | 3 | ||||
-rw-r--r-- | llvm/lib/Target/SystemZ/SystemZInstrInfo.td | 13 |
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>; |