diff --git a/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp b/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp index a52aa2560bc..1a58b531c03 100644 --- a/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp +++ b/lib/Target/SystemZ/SystemZISelDAGToDAG.cpp @@ -898,6 +898,9 @@ SDNode *SystemZDAGToDAGISel::tryRISBGZero(SDNode *N) { } unsigned Opcode = SystemZ::RISBG; + // Prefer RISBGN if available, since it does not clobber CC. + if (Subtarget->hasMiscellaneousExtensions()) + Opcode = SystemZ::RISBGN; EVT OpcodeVT = MVT::i64; if (VT == MVT::i32 && Subtarget->hasHighWord()) { Opcode = SystemZ::RISBMux; @@ -945,9 +948,13 @@ SDNode *SystemZDAGToDAGISel::tryRxSBG(SDNode *N, unsigned Opcode) { // See whether we can avoid an AND in the first operand by converting // ROSBG to RISBG. - if (Opcode == SystemZ::ROSBG && detectOrAndInsertion(Op0, RxSBG[I].Mask)) + if (Opcode == SystemZ::ROSBG && detectOrAndInsertion(Op0, RxSBG[I].Mask)) { Opcode = SystemZ::RISBG; - + // Prefer RISBGN if available, since it does not clobber CC. + if (Subtarget->hasMiscellaneousExtensions()) + Opcode = SystemZ::RISBGN; + } + EVT VT = N->getValueType(0); SDValue Ops[5] = { convertTo(SDLoc(N), MVT::i64, Op0), diff --git a/lib/Target/SystemZ/SystemZInstrInfo.cpp b/lib/Target/SystemZ/SystemZInstrInfo.cpp index 5128993713f..3a028594fa4 100644 --- a/lib/Target/SystemZ/SystemZInstrInfo.cpp +++ b/lib/Target/SystemZ/SystemZInstrInfo.cpp @@ -723,9 +723,12 @@ SystemZInstrInfo::convertToThreeAddress(MachineFunction::iterator &MFI, unsigned Start, End; if (isRxSBGMask(Imm, And.RegSize, Start, End)) { unsigned NewOpcode; - if (And.RegSize == 64) + if (And.RegSize == 64) { NewOpcode = SystemZ::RISBG; - else { + // Prefer RISBGN if available, since it does not clobber CC. + if (STI.hasMiscellaneousExtensions()) + NewOpcode = SystemZ::RISBGN; + } else { NewOpcode = SystemZ::RISBMux; Start &= 31; End &= 31; @@ -1146,17 +1149,22 @@ unsigned SystemZInstrInfo::getOpcodeForOffset(unsigned Opcode, unsigned SystemZInstrInfo::getLoadAndTest(unsigned Opcode) const { switch (Opcode) { - case SystemZ::L: return SystemZ::LT; - case SystemZ::LY: return SystemZ::LT; - case SystemZ::LG: return SystemZ::LTG; - case SystemZ::LGF: return SystemZ::LTGF; - case SystemZ::LR: return SystemZ::LTR; - case SystemZ::LGFR: return SystemZ::LTGFR; - case SystemZ::LGR: return SystemZ::LTGR; - case SystemZ::LER: return SystemZ::LTEBR; - case SystemZ::LDR: return SystemZ::LTDBR; - case SystemZ::LXR: return SystemZ::LTXBR; - default: return 0; + case SystemZ::L: return SystemZ::LT; + case SystemZ::LY: return SystemZ::LT; + case SystemZ::LG: return SystemZ::LTG; + case SystemZ::LGF: return SystemZ::LTGF; + case SystemZ::LR: return SystemZ::LTR; + case SystemZ::LGFR: return SystemZ::LTGFR; + case SystemZ::LGR: return SystemZ::LTGR; + case SystemZ::LER: return SystemZ::LTEBR; + case SystemZ::LDR: return SystemZ::LTDBR; + case SystemZ::LXR: return SystemZ::LTXBR; + // On zEC12 we prefer to use RISBGN. But if there is a chance to + // actually use the condition code, we may turn it back into RISGB. + // Note that RISBG is not really a "load-and-test" instruction, + // but sets the same condition code values, so is OK to use here. + case SystemZ::RISBGN: return SystemZ::RISBG; + default: return 0; } } diff --git a/lib/Target/SystemZ/SystemZInstrInfo.td b/lib/Target/SystemZ/SystemZInstrInfo.td index 31db301d95e..cc95975e014 100644 --- a/lib/Target/SystemZ/SystemZInstrInfo.td +++ b/lib/Target/SystemZ/SystemZInstrInfo.td @@ -1061,6 +1061,10 @@ let Defs = [CC] in { def RISBG : RotateSelectRIEf<"risbg", 0xEC55, GR64, GR64>; } +// On zEC12 we have a variant of RISBG that does not set CC. +let Predicates = [FeatureMiscellaneousExtensions] in + def RISBGN : RotateSelectRIEf<"risbgn", 0xEC59, GR64, GR64>; + // Forms of RISBG that only affect one word of the destination register. // They do not set CC. let Predicates = [FeatureHighWord] in { diff --git a/lib/Target/SystemZ/SystemZProcessors.td b/lib/Target/SystemZ/SystemZProcessors.td index b8bbd5677e0..0563cae637e 100644 --- a/lib/Target/SystemZ/SystemZProcessors.td +++ b/lib/Target/SystemZ/SystemZProcessors.td @@ -55,6 +55,11 @@ def FeatureInterlockedAccess1 : SystemZFeature< >; def FeatureNoInterlockedAccess1 : SystemZMissingFeature<"InterlockedAccess1">; +def FeatureMiscellaneousExtensions : SystemZFeature< + "miscellaneous-extensions", "MiscellaneousExtensions", + "Assume that the miscellaneous-extensions facility is installed" +>; + def : Processor<"generic", NoItineraries, []>; def : Processor<"z10", NoItineraries, []>; def : Processor<"z196", NoItineraries, @@ -64,4 +69,5 @@ def : Processor<"z196", NoItineraries, def : Processor<"zEC12", NoItineraries, [FeatureDistinctOps, FeatureLoadStoreOnCond, FeatureHighWord, FeatureFPExtension, FeaturePopulationCount, - FeatureFastSerialization, FeatureInterlockedAccess1]>; + FeatureFastSerialization, FeatureInterlockedAccess1, + FeatureMiscellaneousExtensions]>; diff --git a/lib/Target/SystemZ/SystemZSubtarget.cpp b/lib/Target/SystemZ/SystemZSubtarget.cpp index 0999b45c9d6..8b8d2edab42 100644 --- a/lib/Target/SystemZ/SystemZSubtarget.cpp +++ b/lib/Target/SystemZ/SystemZSubtarget.cpp @@ -39,7 +39,7 @@ SystemZSubtarget::SystemZSubtarget(const std::string &TT, : SystemZGenSubtargetInfo(TT, CPU, FS), HasDistinctOps(false), HasLoadStoreOnCond(false), HasHighWord(false), HasFPExtension(false), HasPopulationCount(false), HasFastSerialization(false), - HasInterlockedAccess1(false), + HasInterlockedAccess1(false), HasMiscellaneousExtensions(false), TargetTriple(TT), InstrInfo(initializeSubtargetDependencies(CPU, FS)), TLInfo(TM, *this), TSInfo(*TM.getDataLayout()), FrameLowering() {} diff --git a/lib/Target/SystemZ/SystemZSubtarget.h b/lib/Target/SystemZ/SystemZSubtarget.h index b3e7a3512cd..d48de44ed96 100644 --- a/lib/Target/SystemZ/SystemZSubtarget.h +++ b/lib/Target/SystemZ/SystemZSubtarget.h @@ -41,6 +41,7 @@ protected: bool HasPopulationCount; bool HasFastSerialization; bool HasInterlockedAccess1; + bool HasMiscellaneousExtensions; private: Triple TargetTriple; @@ -96,6 +97,11 @@ public: // Return true if the target has interlocked-access facility 1. bool hasInterlockedAccess1() const { return HasInterlockedAccess1; } + // Return true if the target has the miscellaneous-extensions facility. + bool hasMiscellaneousExtensions() const { + return HasMiscellaneousExtensions; + } + // Return true if GV can be accessed using LARL for reloc model RM // and code model CM. bool isPC32DBLSymbol(const GlobalValue *GV, Reloc::Model RM, diff --git a/test/CodeGen/SystemZ/risbg-03.ll b/test/CodeGen/SystemZ/risbg-03.ll new file mode 100644 index 00000000000..c3c08ad1796 --- /dev/null +++ b/test/CodeGen/SystemZ/risbg-03.ll @@ -0,0 +1,30 @@ +; Test use of RISBG vs RISBGN on zEC12. +; +; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=zEC12 | FileCheck %s + +; On zEC12, we generally prefer RISBGN. +define i64 @f1(i64 %a, i64 %b) { +; CHECK-LABEL: f1: +; CHECK: risbgn %r2, %r3, 60, 62, 0 +; CHECK: br %r14 + %anda = and i64 %a, -15 + %andb = and i64 %b, 14 + %or = or i64 %anda, %andb + ret i64 %or +} + +; But we may fall back to RISBG if we can use the condition code. +define i64 @f2(i64 %a, i64 %b, i32* %c) { +; CHECK-LABEL: f2: +; CHECK: risbg %r2, %r3, 60, 62, 0 +; CHECK-NEXT: ipm +; CHECK: br %r14 + %anda = and i64 %a, -15 + %andb = and i64 %b, 14 + %or = or i64 %anda, %andb + %cmp = icmp sgt i64 %or, 0 + %conv = zext i1 %cmp to i32 + store i32 %conv, i32* %c, align 4 + ret i64 %or +} + diff --git a/test/MC/Disassembler/SystemZ/insns.txt b/test/MC/Disassembler/SystemZ/insns.txt index df032dc53f9..cf130899790 100644 --- a/test/MC/Disassembler/SystemZ/insns.txt +++ b/test/MC/Disassembler/SystemZ/insns.txt @@ -6367,6 +6367,27 @@ # CHECK: risbg %r4, %r5, 6, 7, 8 0xec 0x45 0x06 0x07 0x08 0x55 +# CHECK: risbgn %r0, %r0, 0, 0, 0 +0xec 0x00 0x00 0x00 0x00 0x59 + +# CHECK: risbgn %r0, %r0, 0, 0, 63 +0xec 0x00 0x00 0x00 0x3f 0x59 + +# CHECK: risbgn %r0, %r0, 0, 255, 0 +0xec 0x00 0x00 0xff 0x00 0x59 + +# CHECK: risbgn %r0, %r0, 255, 0, 0 +0xec 0x00 0xff 0x00 0x00 0x59 + +# CHECK: risbgn %r0, %r15, 0, 0, 0 +0xec 0x0f 0x00 0x00 0x00 0x59 + +# CHECK: risbgn %r15, %r0, 0, 0, 0 +0xec 0xf0 0x00 0x00 0x00 0x59 + +# CHECK: risbgn %r4, %r5, 6, 7, 8 +0xec 0x45 0x06 0x07 0x08 0x59 + # CHECK: risbhg %r0, %r0, 0, 0, 0 0xec 0x00 0x00 0x00 0x00 0x5d diff --git a/test/MC/SystemZ/insn-bad-z196.s b/test/MC/SystemZ/insn-bad-z196.s index 47dbe08b252..deebe6dce2b 100644 --- a/test/MC/SystemZ/insn-bad-z196.s +++ b/test/MC/SystemZ/insn-bad-z196.s @@ -546,6 +546,11 @@ locr %r0,%r0,-1 locr %r0,%r0,16 +#CHECK: error: {{(instruction requires: miscellaneous-extensions)?}} +#CHECK: risbgn %r1, %r2, 0, 0, 0 + + risbgn %r1, %r2, 0, 0, 0 + #CHECK: error: invalid operand #CHECK: risbhg %r0,%r0,0,0,-1 #CHECK: error: invalid operand diff --git a/test/MC/SystemZ/insn-bad-zEC12.s b/test/MC/SystemZ/insn-bad-zEC12.s new file mode 100644 index 00000000000..42d41ca6f9c --- /dev/null +++ b/test/MC/SystemZ/insn-bad-zEC12.s @@ -0,0 +1,24 @@ +# For zEC12 only. +# RUN: not llvm-mc -triple s390x-linux-gnu -mcpu=zEC12 < %s 2> %t +# RUN: FileCheck < %t %s + +#CHECK: error: invalid operand +#CHECK: risbgn %r0,%r0,0,0,-1 +#CHECK: error: invalid operand +#CHECK: risbgn %r0,%r0,0,0,64 +#CHECK: error: invalid operand +#CHECK: risbgn %r0,%r0,0,-1,0 +#CHECK: error: invalid operand +#CHECK: risbgn %r0,%r0,0,256,0 +#CHECK: error: invalid operand +#CHECK: risbgn %r0,%r0,-1,0,0 +#CHECK: error: invalid operand +#CHECK: risbgn %r0,%r0,256,0,0 + + risbgn %r0,%r0,0,0,-1 + risbgn %r0,%r0,0,0,64 + risbgn %r0,%r0,0,-1,0 + risbgn %r0,%r0,0,256,0 + risbgn %r0,%r0,-1,0,0 + risbgn %r0,%r0,256,0,0 + diff --git a/test/MC/SystemZ/insn-good-zEC12.s b/test/MC/SystemZ/insn-good-zEC12.s new file mode 100644 index 00000000000..6f8f0ac5f9b --- /dev/null +++ b/test/MC/SystemZ/insn-good-zEC12.s @@ -0,0 +1,19 @@ +# For zEC12 and above. +# RUN: llvm-mc -triple s390x-linux-gnu -mcpu=zEC12 -show-encoding %s | FileCheck %s + +#CHECK: risbgn %r0, %r0, 0, 0, 0 # encoding: [0xec,0x00,0x00,0x00,0x00,0x59] +#CHECK: risbgn %r0, %r0, 0, 0, 63 # encoding: [0xec,0x00,0x00,0x00,0x3f,0x59] +#CHECK: risbgn %r0, %r0, 0, 255, 0 # encoding: [0xec,0x00,0x00,0xff,0x00,0x59] +#CHECK: risbgn %r0, %r0, 255, 0, 0 # encoding: [0xec,0x00,0xff,0x00,0x00,0x59] +#CHECK: risbgn %r0, %r15, 0, 0, 0 # encoding: [0xec,0x0f,0x00,0x00,0x00,0x59] +#CHECK: risbgn %r15, %r0, 0, 0, 0 # encoding: [0xec,0xf0,0x00,0x00,0x00,0x59] +#CHECK: risbgn %r4, %r5, 6, 7, 8 # encoding: [0xec,0x45,0x06,0x07,0x08,0x59] + + risbgn %r0,%r0,0,0,0 + risbgn %r0,%r0,0,0,63 + risbgn %r0,%r0,0,255,0 + risbgn %r0,%r0,255,0,0 + risbgn %r0,%r15,0,0,0 + risbgn %r15,%r0,0,0,0 + risbgn %r4,%r5,6,7,8 +