Index: lib/Target/SystemZ/SystemZAsmPrinter.cpp =================================================================== --- lib/Target/SystemZ/SystemZAsmPrinter.cpp +++ lib/Target/SystemZ/SystemZAsmPrinter.cpp @@ -430,6 +430,33 @@ OutStreamer->emitRawComment("MEMBARRIER"); return; + // We want to emit "j .+2" for traps, jumping to the relative immediate field + // of the jump instruction, which is an illegal instruction. We cannot emit a "." symbol, + // so create and emit a temp label before the instruction and jump to that label instead. + case SystemZ::Trap: { + MCSymbol *DotSym = OutContext.createTempSymbol(); + OutStreamer->EmitLabel(DotSym); + + const MCSymbolRefExpr *Expr = MCSymbolRefExpr::create(DotSym, OutContext); + LoweredMI = MCInstBuilder(SystemZ::J) + .addExpr(MCBinaryExpr::createAdd(Expr, MCConstantExpr::create(2, OutContext), OutContext)); + } + break; + + // Conditional traps will create a branch on condition instruction that jumps to the relative + // immediate field of the jump instruction. (eg. "jo .+2") + case SystemZ::CondTrap: { + MCSymbol *DotSym = OutContext.createTempSymbol(); + OutStreamer->EmitLabel(DotSym); + + const MCSymbolRefExpr *Expr = MCSymbolRefExpr::create(DotSym, OutContext); + LoweredMI = MCInstBuilder(SystemZ::BRC) + .addImm(MI->getOperand(0).getImm()) + .addImm(MI->getOperand(1).getImm()) + .addExpr(MCBinaryExpr::createAdd(Expr, MCConstantExpr::create(2, OutContext), OutContext)); + } + break; + default: Lower.lower(MI, LoweredMI); break; Index: lib/Target/SystemZ/SystemZElimCompare.cpp =================================================================== --- lib/Target/SystemZ/SystemZElimCompare.cpp +++ lib/Target/SystemZ/SystemZElimCompare.cpp @@ -78,8 +78,8 @@ SmallVectorImpl &CCUsers); bool optimizeCompareZero(MachineInstr *Compare, SmallVectorImpl &CCUsers); - bool fuseCompareAndBranch(MachineInstr *Compare, - SmallVectorImpl &CCUsers); + bool fuseCompareOperations(MachineInstr *Compare, + SmallVectorImpl &CCUsers); const SystemZInstrInfo *TII; const TargetRegisterInfo *TRI; @@ -377,13 +377,13 @@ // Try to fuse comparison instruction Compare into a later branch. // Return true on success and if Compare is therefore redundant. bool SystemZElimCompare:: -fuseCompareAndBranch(MachineInstr *Compare, - SmallVectorImpl &CCUsers) { +fuseCompareOperations(MachineInstr *Compare, + SmallVectorImpl &CCUsers) { // See whether we have a single branch with which to fuse. if (CCUsers.size() != 1) return false; MachineInstr *Branch = CCUsers[0]; - SystemZII::CompareAndBranchType Type; + SystemZII::FusedCompareType Type; switch (Branch->getOpcode()) { case SystemZ::BRC: Type = SystemZII::CompareAndBranch; @@ -394,13 +394,16 @@ case SystemZ::CallBCR: Type = SystemZII::CompareAndSibcall; break; + case SystemZ::CondTrap: + Type = SystemZII::CompareAndTrap; + break; default: return false; } // See whether we have a comparison that can be fused. - unsigned FusedOpcode = TII->getCompareAndBranch(Compare->getOpcode(), - Type, Compare); + unsigned FusedOpcode = TII->getFusedCompare(Compare->getOpcode(), + Type, Compare); if (!FusedOpcode) return false; @@ -481,7 +484,7 @@ if (CompleteCCUsers && (MI->isCompare() || isLoadAndTestAsCmp(MI)) && (optimizeCompareZero(MI, CCUsers) || - fuseCompareAndBranch(MI, CCUsers))) { + fuseCompareOperations(MI, CCUsers))) { ++MBBI; MI->eraseFromParent(); Changed = true; Index: lib/Target/SystemZ/SystemZISelLowering.h =================================================================== --- lib/Target/SystemZ/SystemZISelLowering.h +++ lib/Target/SystemZ/SystemZISelLowering.h @@ -583,6 +583,8 @@ MachineBasicBlock *emitLoadAndTestCmp0(MachineInstr *MI, MachineBasicBlock *MBB, unsigned Opcode) const; + MachineBasicBlock *emitTrap(MachineInstr *MI, + MachineBasicBlock *MBB) const; }; } // end namespace llvm Index: lib/Target/SystemZ/SystemZISelLowering.cpp =================================================================== --- lib/Target/SystemZ/SystemZISelLowering.cpp +++ lib/Target/SystemZ/SystemZISelLowering.cpp @@ -216,6 +216,9 @@ setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Custom); + // Traps are legal + setOperationAction(ISD::TRAP, MVT::Other, Legal); + // z10 has instructions for signed but not unsigned FP conversion. // Handle unsigned 32-bit types as signed 64-bit types. if (!Subtarget.hasFPExtension()) { @@ -5760,6 +5763,14 @@ return MBB; } +MachineBasicBlock * +SystemZTargetLowering::emitTrap(MachineInstr *MI, + MachineBasicBlock *MBB) const { + // Trap instructions should be terminators for a basic block + // Split the block in case the trap is not at the end of a basic block + return splitBlockAfter(MI, MBB); +} + // Decompose string pseudo-instruction MI into a loop that continually performs // Opcode until CC != 3. MachineBasicBlock * @@ -6152,6 +6163,9 @@ case SystemZ::LTXBRCompare_VecPseudo: return emitLoadAndTestCmp0(MI, MBB, SystemZ::LTXBR); + case SystemZ::Trap: + return emitTrap(MI, MBB); + default: llvm_unreachable("Unexpected instr type to insert"); } Index: lib/Target/SystemZ/SystemZInstrFormats.td =================================================================== --- lib/Target/SystemZ/SystemZInstrFormats.td +++ lib/Target/SystemZ/SystemZInstrFormats.td @@ -202,6 +202,24 @@ let Inst{7-0} = op{7-0}; } +class InstRIEa op, dag outs, dag ins, string asmstr, list pattern> + : InstSystemZ<6, outs, ins, asmstr, pattern> { + field bits<48> Inst; + field bits<48> SoftFail = 0; + + bits<4> R1; + bits<16> I2; + bits<4> M3; + + let Inst{47-40} = op{15-8}; + let Inst{39-36} = R1; + let Inst{35-32} = 0; + let Inst{31-16} = I2; + let Inst{15-12} = M3; + let Inst{11-8} = 0; + let Inst{7-0} = op{7-0}; +} + class InstRIEc op, dag outs, dag ins, string asmstr, list pattern> : InstSystemZ<6, outs, ins, asmstr, pattern> { field bits<48> Inst; @@ -349,6 +367,22 @@ let Inst{3-0} = R2; } +class InstRRFc op, dag outs, dag ins, string asmstr, list pattern> + : InstSystemZ<4, outs, ins, asmstr, pattern> { + field bits<32> Inst; + field bits<32> SoftFail = 0; + + bits<4> R1; + bits<4> R2; + bits<4> M3; + + let Inst{31-16} = op; + let Inst{15-12} = M3; + let Inst{11-8} = 0; + let Inst{7-4} = R1; + let Inst{3-0} = R2; +} + class InstRRS op, dag outs, dag ins, string asmstr, list pattern> : InstSystemZ<6, outs, ins, asmstr, pattern> { field bits<48> Inst; Index: lib/Target/SystemZ/SystemZInstrInfo.h =================================================================== --- lib/Target/SystemZ/SystemZInstrInfo.h +++ lib/Target/SystemZ/SystemZInstrInfo.h @@ -111,10 +111,10 @@ const MachineOperand *target) : Type(type), CCValid(ccValid), CCMask(ccMask), Target(target) {} }; -// Kinds of branch in compare-and-branch instructions. Together with type -// of the converted compare, this identifies the compare-and-branch +// Kinds of fused compares in compare-and-* instructions. Together with type +// of the converted compare, this identifies the compare-and-* // instruction. -enum CompareAndBranchType { +enum FusedCompareType { // Relative branch - CRJ etc. CompareAndBranch, @@ -122,7 +122,10 @@ CompareAndReturn, // Indirect branch, used for sibcall - CRBCall etc. - CompareAndSibcall + CompareAndSibcall, + + // Trap + CompareAndTrap }; } // end namespace SystemZII @@ -247,12 +250,12 @@ bool isRxSBGMask(uint64_t Mask, unsigned BitSize, unsigned &Start, unsigned &End) const; - // If Opcode is a COMPARE opcode for which an associated COMPARE AND - // BRANCH exists, return the opcode for the latter, otherwise return 0. + // If Opcode is a COMPARE opcode for which an associated fused COMPARE AND * + // operation exists, return the opcode for the latter, otherwise return 0. // MI, if nonnull, is the compare instruction. - unsigned getCompareAndBranch(unsigned Opcode, - SystemZII::CompareAndBranchType Type, - const MachineInstr *MI = nullptr) const; + unsigned getFusedCompare(unsigned Opcode, + SystemZII::FusedCompareType Type, + const MachineInstr *MI = nullptr) const; // Emit code before MBBI in MI to move immediate value Value into // physical register Reg. Index: lib/Target/SystemZ/SystemZInstrInfo.cpp =================================================================== --- lib/Target/SystemZ/SystemZInstrInfo.cpp +++ lib/Target/SystemZ/SystemZInstrInfo.cpp @@ -543,6 +543,7 @@ if (STI.hasLoadStoreOnCond() && getConditionalMove(Opcode)) return true; if (Opcode == SystemZ::Return || + Opcode == SystemZ::Trap || Opcode == SystemZ::CallJG || Opcode == SystemZ::CallBR) return true; @@ -558,7 +559,11 @@ // making the loop body longer). This doesn't apply for low-probability // loops (eg. compare-and-swap retry), so just decide based on branch // probability instead of looping structure. - if (MBB.succ_empty() && Probability < BranchProbability(1, 8)) + // However, since Compare and Trap instructions cost the same as a regular + // Compare instruction, we should allow the if conversion to convert this + // into a Conditional Compare regardless of the branch probability. + if (MBB.getFirstTerminator()->getOpcode() != SystemZ::Trap && + MBB.succ_empty() && Probability < BranchProbability(1, 8)) return false; // For now only convert single instructions. return NumCycles == 1; @@ -598,6 +603,13 @@ return true; } } + if (Opcode == SystemZ::Trap) { + MI.setDesc(get(SystemZ::CondTrap)); + MachineInstrBuilder(*MI.getParent()->getParent(), MI) + .addImm(CCValid).addImm(CCMask) + .addReg(SystemZ::CC, RegState::Implicit); + return true; + } if (Opcode == SystemZ::Return) { MI.setDesc(get(SystemZ::CondReturn)); MachineInstrBuilder(*MI.getParent()->getParent(), MI) @@ -1370,9 +1382,9 @@ return false; } -unsigned SystemZInstrInfo::getCompareAndBranch(unsigned Opcode, - SystemZII::CompareAndBranchType Type, - const MachineInstr *MI) const { +unsigned SystemZInstrInfo::getFusedCompare(unsigned Opcode, + SystemZII::FusedCompareType Type, + const MachineInstr *MI) const { switch (Opcode) { case SystemZ::CHI: case SystemZ::CGHI: @@ -1448,6 +1460,27 @@ default: return 0; } + case SystemZII::CompareAndTrap: + switch (Opcode) { + case SystemZ::CR: + return SystemZ::CRT; + case SystemZ::CGR: + return SystemZ::CGRT; + case SystemZ::CHI: + return SystemZ::CIT; + case SystemZ::CGHI: + return SystemZ::CGIT; + case SystemZ::CLR: + return SystemZ::CLRT; + case SystemZ::CLGR: + return SystemZ::CLGRT; + case SystemZ::CLFI: + return SystemZ::CLFIT; + case SystemZ::CLGFI: + return SystemZ::CLGIT; + default: + return 0; + } } return 0; } Index: lib/Target/SystemZ/SystemZInstrInfo.td =================================================================== --- lib/Target/SystemZ/SystemZInstrInfo.td +++ lib/Target/SystemZ/SystemZInstrInfo.td @@ -67,6 +67,14 @@ def JG : InstRIL<0xC04, (outs), (ins brtarget32:$I2), "jg\t$I2", []>; } +let isTerminator = 1, isBarrier = 1, hasCtrlDep = 1, usesCustomInserter = 1 in { + def Trap : Alias<2, (outs), (ins), [(trap)]>; +} + +let isTerminator = 1, isBarrier = 1, hasCtrlDep = 1, Uses = [CC] in { + def CondTrap : Alias<2, (outs), (ins cond4:$valid, cond4:$R1), []>; +} + // Conditional branches. It's easier for LLVM to handle these branches // in their raw BRC/BRCL form, with the 4-bit condition-code mask being // the first operand. It seems friendlier to use mnemonic forms like @@ -109,59 +117,78 @@ let isBranch = 1, isTerminator = 1, Defs = [CC] in { def RJ : InstRIEb<0xEC76, (outs), (ins GR32:$R1, GR32:$R2, ccmask:$M3, brtarget16:$RI4), - "crj"##pos1##"\t$R1, $R2, "##pos2##"$RI4", []>; + "crj"##pos1##"\t$R1, $R2"##pos2##", $RI4", []>; def GRJ : InstRIEb<0xEC64, (outs), (ins GR64:$R1, GR64:$R2, ccmask:$M3, brtarget16:$RI4), - "cgrj"##pos1##"\t$R1, $R2, "##pos2##"$RI4", []>; + "cgrj"##pos1##"\t$R1, $R2"##pos2##", $RI4", []>; def IJ : InstRIEc<0xEC7E, (outs), (ins GR32:$R1, imm32sx8:$I2, ccmask:$M3, brtarget16:$RI4), - "cij"##pos1##"\t$R1, $I2, "##pos2##"$RI4", []>; + "cij"##pos1##"\t$R1, $I2"##pos2##", $RI4", []>; def GIJ : InstRIEc<0xEC7C, (outs), (ins GR64:$R1, imm64sx8:$I2, ccmask:$M3, brtarget16:$RI4), - "cgij"##pos1##"\t$R1, $I2, "##pos2##"$RI4", []>; + "cgij"##pos1##"\t$R1, $I2"##pos2##", $RI4", []>; def LRJ : InstRIEb<0xEC77, (outs), (ins GR32:$R1, GR32:$R2, ccmask:$M3, brtarget16:$RI4), - "clrj"##pos1##"\t$R1, $R2, "##pos2##"$RI4", []>; + "clrj"##pos1##"\t$R1, $R2"##pos2##", $RI4", []>; def LGRJ : InstRIEb<0xEC65, (outs), (ins GR64:$R1, GR64:$R2, ccmask:$M3, brtarget16:$RI4), - "clgrj"##pos1##"\t$R1, $R2, "##pos2##"$RI4", []>; + "clgrj"##pos1##"\t$R1, $R2"##pos2##", $RI4", []>; def LIJ : InstRIEc<0xEC7F, (outs), (ins GR32:$R1, imm32zx8:$I2, ccmask:$M3, brtarget16:$RI4), - "clij"##pos1##"\t$R1, $I2, "##pos2##"$RI4", []>; + "clij"##pos1##"\t$R1, $I2"##pos2##", $RI4", []>; def LGIJ : InstRIEc<0xEC7D, (outs), (ins GR64:$R1, imm64zx8:$I2, ccmask:$M3, brtarget16:$RI4), - "clgij"##pos1##"\t$R1, $I2, "##pos2##"$RI4", []>; + "clgij"##pos1##"\t$R1, $I2"##pos2##", $RI4", []>; let isIndirectBranch = 1 in { def RB : InstRRS<0xECF6, (outs), (ins GR32:$R1, GR32:$R2, ccmask:$M3, bdaddr12only:$BD4), - "crb"##pos1##"\t$R1, $R2, "##pos2##"$BD4", []>; + "crb"##pos1##"\t$R1, $R2"##pos2##", $BD4", []>; def GRB : InstRRS<0xECE4, (outs), (ins GR64:$R1, GR64:$R2, ccmask:$M3, bdaddr12only:$BD4), - "cgrb"##pos1##"\t$R1, $R2, "##pos2##"$BD4", []>; + "cgrb"##pos1##"\t$R1, $R2"##pos2##", $BD4", []>; def IB : InstRIS<0xECFE, (outs), (ins GR32:$R1, imm32sx8:$I2, ccmask:$M3, bdaddr12only:$BD4), - "cib"##pos1##"\t$R1, $I2, "##pos2##"$BD4", []>; + "cib"##pos1##"\t$R1, $I2"##pos2##", $BD4", []>; def GIB : InstRIS<0xECFC, (outs), (ins GR64:$R1, imm64sx8:$I2, ccmask:$M3, bdaddr12only:$BD4), - "cgib"##pos1##"\t$R1, $I2, "##pos2##"$BD4", []>; + "cgib"##pos1##"\t$R1, $I2"##pos2##", $BD4", []>; def LRB : InstRRS<0xECF7, (outs), (ins GR32:$R1, GR32:$R2, ccmask:$M3, bdaddr12only:$BD4), - "clrb"##pos1##"\t$R1, $R2, "##pos2##"$BD4", []>; + "clrb"##pos1##"\t$R1, $R2"##pos2##", $BD4", []>; def LGRB : InstRRS<0xECE5, (outs), (ins GR64:$R1, GR64:$R2, ccmask:$M3, bdaddr12only:$BD4), - "clgrb"##pos1##"\t$R1, $R2, "##pos2##"$BD4", []>; + "clgrb"##pos1##"\t$R1, $R2"##pos2##", $BD4", []>; def LIB : InstRIS<0xECFF, (outs), (ins GR32:$R1, imm32zx8:$I2, ccmask:$M3, bdaddr12only:$BD4), - "clib"##pos1##"\t$R1, $I2, "##pos2##"$BD4", []>; + "clib"##pos1##"\t$R1, $I2"##pos2##", $BD4", []>; def LGIB : InstRIS<0xECFD, (outs), (ins GR64:$R1, imm64zx8:$I2, ccmask:$M3, bdaddr12only:$BD4), - "clgib"##pos1##"\t$R1, $I2, "##pos2##"$BD4", []>; + "clgib"##pos1##"\t$R1, $I2"##pos2##", $BD4", []>; } } + + let isTerminator = 1, isBarrier = 1, hasCtrlDep = 1 in { + def RT : InstRRFc<0xB972, (outs), (ins GR32:$R1, GR32:$R2, ccmask:$M3), + "crt"##pos1##"\t$R1, $R2"##pos2, []>; + def GRT : InstRRFc<0xB960, (outs), (ins GR64:$R1, GR64:$R2, ccmask:$M3), + "cgrt"##pos1##"\t$R1, $R2"##pos2, []>; + def LRT : InstRRFc<0xB973, (outs), (ins GR32:$R1, GR32:$R2, ccmask:$M3), + "clrt"##pos1##"\t$R1, $R2"##pos2, []>; + def LGRT : InstRRFc<0xB961, (outs), (ins GR64:$R1, GR64:$R2, ccmask:$M3), + "clgrt"##pos1##"\t$R1, $R2"##pos2, []>; + def IT : InstRIEa<0xEC72, (outs), (ins GR32:$R1, imm32sx16:$I2, ccmask:$M3), + "cit"##pos1##"\t$R1, $I2"##pos2, []>; + def GIT : InstRIEa<0xEC70, (outs), (ins GR64:$R1, imm32sx16:$I2, ccmask:$M3), + "cgit"##pos1##"\t$R1, $I2"##pos2, []>; + def LFIT : InstRIEa<0xEC73, (outs), (ins GR32:$R1, imm32zx16:$I2, ccmask:$M3), + "clfit"##pos1##"\t$R1, $I2"##pos2, []>; + def LGIT : InstRIEa<0xEC71, (outs), (ins GR64:$R1, imm32zx16:$I2, ccmask:$M3), + "clgit"##pos1##"\t$R1, $I2"##pos2, []>; + } } let isCodeGenOnly = 1 in defm C : CompareBranches; -defm AsmC : CompareBranches; +defm AsmC : CompareBranches; // Define AsmParser mnemonics for each general condition-code mask // (integer or floating-point) @@ -262,6 +289,25 @@ "clgib"##name##"\t$R1, $I2, $BD4", []>; } } + + let isBarrier = 1, hasCtrlDep = 1, isTerminator = 1, M3 = ccmask in { + def CRT : InstRRFc<0xB972, (outs), (ins GR32:$R1, GR32:$R2), + "crt"##name##"\t$R1, $R2", []>; + def CGRT : InstRRFc<0xB960, (outs), (ins GR64:$R1, GR64:$R2), + "cgrt"##name##"\t$R1, $R2", []>; + def CLRT : InstRRFc<0xB973, (outs), (ins GR32:$R1, GR32:$R2), + "clrt"##name##"\t$R1, $R2", []>; + def CLGRT : InstRRFc<0xB961, (outs), (ins GR64:$R1, GR64:$R2), + "clgrt"##name##"\t$R1, $R2", []>; + def CIT : InstRIEa<0xEC72, (outs), (ins GR32:$R1, imm32sx16:$I2), + "cit"##name##"\t$R1, $I2", []>; + def CGIT : InstRIEa<0xEC70, (outs), (ins GR64:$R1, imm32sx16:$I2), + "cgit"##name##"\t$R1, $I2", []>; + def CLFIT : InstRIEa<0xEC73, (outs), (ins GR32:$R1, imm32zx16:$I2), + "clfit"##name##"\t$R1, $I2", []>; + def CLGIT : InstRIEa<0xEC71, (outs), (ins GR64:$R1, imm32zx16:$I2), + "clgit"##name##"\t$R1, $I2", []>; + } } multiclass IntCondExtendedMnemonic ccmask, string name1, string name2> : IntCondExtendedMnemonicA { Index: test/CodeGen/SystemZ/trap-01.ll =================================================================== --- /dev/null +++ test/CodeGen/SystemZ/trap-01.ll @@ -0,0 +1,149 @@ +; Test conditional traps +; +; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s + +declare void @llvm.trap() + +; Check conditional compare immediate and trap +define i32 @f1(i32 signext %a) { +; CHECK-LABEL: f1: +; CHECK: cithe %r2, 15 +; CHECK: lhi %r2, 0 +; CHECK: br %r14 +entry: + %cmp = icmp sgt i32 %a, 14 + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %entry + tail call void @llvm.trap() + unreachable + +if.end: ; preds = %entry + ret i32 0 +} + +; Check conditional compare grande immediate and trap +define i64 @f2(i64 signext %a) { +; CHECK-LABEL: f2: +; CHECK: cgitle %r2, 14 +; CHECK: lghi %r2, 0 +; CHECK: br %r14 +entry: + %cmp = icmp slt i64 %a, 15 + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %entry + tail call void @llvm.trap() + unreachable + +if.end: ; preds = %entry + ret i64 0 +} + +; Check conditional compare logical immediate and trap +define i32 @f3(i32 zeroext %a) { +; CHECK-LABEL: f3: +; CHECK: clfithe %r2, 15 +; CHECK: lhi %r2, 0 +; CHECK: br %r14 +entry: + %cmp = icmp ugt i32 %a, 14 + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %entry + tail call void @llvm.trap() + unreachable + +if.end: ; preds = %entry + ret i32 0 +} + +; Check conditional compare grande logical immediate and trap +define i64 @f4(i64 zeroext %a) { +; CHECK-LABEL: f4: +; CHECK: clgitle %r2, 14 +; CHECK: lghi %r2, 0 +; CHECK: br %r14 +entry: + %cmp = icmp ult i64 %a, 15 + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %entry + tail call void @llvm.trap() + unreachable + +if.end: ; preds = %entry + ret i64 0 +} + +; Check conditional compare and trap +define i32 @f5(i32 signext %a, i32 signext %b) { +; CHECK-LABEL: f5: +; CHECK: crte %r2, %r3 +; CHECK: lhi %r2, 0 +; CHECK: br %r14 +entry: + %cmp = icmp eq i32 %a, %b + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %entry + tail call void @llvm.trap() + unreachable + +if.end: ; preds = %entry + ret i32 0 +} + +; Check conditional compare grande and trap +define i64 @f6(i64 signext %a, i64 signext %b) { +; CHECK-LABEL: f6: +; CHECK: cgrtl %r2, %r3 +; CHECK: lghi %r2, 0 +; CHECK: br %r14 +entry: + %cmp = icmp slt i64 %a, %b + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %entry + tail call void @llvm.trap() + unreachable + +if.end: ; preds = %entry + ret i64 0 +} + +; Check conditional compare logical and trap +define i32 @f7(i32 zeroext %a, i32 zeroext %b) { +; CHECK-LABEL: f7: +; CHECK: clrth %r2, %r3 +; CHECK: lhi %r2, 0 +; CHECK: br %r14 +entry: + %cmp = icmp ugt i32 %a, %b + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %entry + tail call void @llvm.trap() + unreachable + +if.end: ; preds = %entry + ret i32 0 +} + +; Check conditional compare logical grande and trap +define i64 @f8(i64 zeroext %a, i64 zeroext %b) { +; CHECK-LABEL: f8: +; CHECK: clgrtl %r2, %r3 +; CHECK: lghi %r2, 0 +; CHECK: br %r14 +entry: + %cmp = icmp ult i64 %a, %b + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %entry + tail call void @llvm.trap() + unreachable + +if.end: ; preds = %entry + ret i64 0 +}