Index: lib/Target/NDS32/NDS32InstrFormats.td =================================================================== --- lib/Target/NDS32/NDS32InstrFormats.td +++ lib/Target/NDS32/NDS32InstrFormats.td @@ -147,9 +147,46 @@ } +class JIForm pattern> + : 32BitInst<0b100100, outs, ins, asmstr, pattern>; + class JREGForm pattern> : 32BitInst<0b100101, outs, ins, asmstr, pattern>; +class BR1Form pattern, + bit beq_bne> + : 32BitInst<0b100110, outs, ins, asmstr, pattern> { + bits<5> Rt; + bits<5> Ra; + bits<14> offset; + let Inst{24-20} = Rt; + let Inst{19-15} = Ra; + let Inst{14} = beq_bne; + let Inst{13-0} = offset; +} + +class BR2Form pattern, + bits<4> branch_encode> + : 32BitInst<0b100111, outs, ins, asmstr, pattern> { + bits<5> Rt; + bits<16> offset; + let Inst{24-20} = Rt; + let Inst{19-16} = branch_encode; + let Inst{15-0} = offset; +} + +class BR3Form pattern, + bit branch_encode> + : 32BitInst<0b101101, outs, ins, asmstr, pattern> { + bits<5> Rt; + bits<8> offset; + bits<11> imm; + let Inst{24-20} = Rt; + let Inst{19} = branch_encode; + let Inst{18-8} = imm; + let Inst{7-0} = offset; +} + // Pseudo instructions class Pseudo pattern> : 32BitInst<0b110010, outs, ins, asmstr, pattern> { Index: lib/Target/NDS32/NDS32InstrInfo.h =================================================================== --- lib/Target/NDS32/NDS32InstrInfo.h +++ lib/Target/NDS32/NDS32InstrInfo.h @@ -76,6 +76,12 @@ MachineMemOperand::Flags Flags) const; private: + void BuildCondBr(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + const DebugLoc &DL, ArrayRef Cond) const; + + void AnalyzeCondBr(const MachineInstr *Inst, unsigned Opc, + MachineBasicBlock *&BB, + SmallVectorImpl &Cond) const; }; const NDS32InstrInfo *createNDS32InstrInfo(const NDS32Subtarget &STI); Index: lib/Target/NDS32/NDS32InstrInfo.cpp =================================================================== --- lib/Target/NDS32/NDS32InstrInfo.cpp +++ lib/Target/NDS32/NDS32InstrInfo.cpp @@ -62,6 +62,53 @@ // Branch Analysis //===----------------------------------------------------------------------===// +static bool isUncondBranch(unsigned Opcode) { + + if (Opcode == NDS32::J) + return true; + return false; +} + +static bool isCondBranch(unsigned Opcode) { + + if (Opcode == NDS32::BEQ || + Opcode == NDS32::BNE || + Opcode == NDS32::BEQZ || + Opcode == NDS32::BNEZ || + Opcode == NDS32::BGEZ || + Opcode == NDS32::BGTZ || + Opcode == NDS32::BLEZ || + Opcode == NDS32::BLTZ || + Opcode == NDS32::BEQC || + Opcode == NDS32::BNEC) + return true; + return false; +} + +static bool isIndirectBranch(unsigned Opcode) { + if (Opcode == NDS32::JR) + return true; + return false; +} + +void NDS32InstrInfo::BuildCondBr(MachineBasicBlock &MBB, MachineBasicBlock *TBB, + const DebugLoc &DL, + ArrayRef Cond) const { + unsigned Opc = Cond[0].getImm(); + const MCInstrDesc &MCID = get(Opc); + MachineInstrBuilder MIB = BuildMI(&MBB, DL, MCID); + + for (unsigned i = 1; i < Cond.size(); ++i) { + if (Cond[i].isReg()) + MIB.addReg(Cond[i].getReg()); + else if (Cond[i].isImm()) + MIB.addImm(Cond[i].getImm()); + else + assert(false && "Cannot copy operand"); + } + MIB.addMBB(TBB); +} + unsigned NDS32InstrInfo::insertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, @@ -70,7 +117,21 @@ int *BytesAdded) const { // Shouldn't be a fall through. assert(TBB && "InsertBranch must not be told to insert a fallthrough"); - return 0; + + // Two-way Conditional branch. + if (FBB) { + BuildCondBr(MBB, TBB, DL, Cond); + BuildMI(&MBB, DL, get(NDS32::J)).addMBB(FBB); + return 2; + } + + // One way branch. + // Unconditional branch. + if (Cond.empty()) + BuildMI(&MBB, DL, get(NDS32::J)).addMBB(TBB); + else // Conditional branch. + BuildCondBr(MBB, TBB, DL, Cond); + return 1; } // removeBranch will remove last branch or last two @@ -78,7 +139,29 @@ // could do the right thing. unsigned NDS32InstrInfo::removeBranch(MachineBasicBlock &MBB, int *BytesRemoved) const { - return 0; + assert(!BytesRemoved && "code size not handled"); + + MachineBasicBlock::iterator I = MBB.getLastNonDebugInstr(); + if (I == MBB.end()) + return 0; + + if (!isUncondBranch(I->getOpcode()) && + !isCondBranch(I->getOpcode())) + return 0; + + // Remove the branch. + I->eraseFromParent(); + + I = MBB.end(); + + if (I == MBB.begin()) return 1; + --I; + if (!isCondBranch(I->getOpcode())) + return 1; + + // Remove the branch. + I->eraseFromParent(); + return 2; } bool NDS32InstrInfo:: @@ -87,10 +170,87 @@ return true; } +void NDS32InstrInfo::AnalyzeCondBr(const MachineInstr *Inst, unsigned Opc, + MachineBasicBlock *&BB, + SmallVectorImpl &Cond) const { + int NumOp = Inst->getNumExplicitOperands(); + + // for both int and fp branches, the last explicit operand is the + // MBB. + BB = Inst->getOperand(NumOp-1).getMBB(); + Cond.push_back(MachineOperand::CreateImm(Opc)); + + for (int i=0; igetOperand(i)); +} + bool NDS32InstrInfo::analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, MachineBasicBlock *&FBB, SmallVectorImpl &Cond, bool AllowModify) const { - return true; + // Start from the bottom of the block and work up, examining the + // terminator instructions. + MachineBasicBlock::iterator I = MBB.end(); + while (I != MBB.begin()) { + --I; + if (I->isDebugValue()) + continue; + + // Working from the bottom, when we see a non-terminator + // instruction, we're done. + if (!isUnpredicatedTerminator(*I)) + break; + + // A terminator that isn't a branch can't easily be handled + // by this analysis. + if (!I->isBranch()) + return true; + + // Cannot handle indirect branches. + if (isIndirectBranch (I->getOpcode())) + return true; + + // Handle unconditional branches. + if (isUncondBranch (I->getOpcode())) { + if (!AllowModify) { + TBB = I->getOperand(0).getMBB(); + continue; + } + + // If the block has any instructions after a J, delete them. + while (std::next(I) != MBB.end()) + std::next(I)->eraseFromParent(); + Cond.clear(); + FBB = nullptr; + + // Delete the J if it's equivalent to a fall-through. + if (MBB.isLayoutSuccessor(I->getOperand(0).getMBB())) { + TBB = nullptr; + I->eraseFromParent(); + I = MBB.end(); + continue; + } + + // TBB is used to indicate the unconditinal destination. + TBB = I->getOperand(0).getMBB(); + continue; + } + + // Handle conditional branches. + if (isCondBranch (I->getOpcode())) { + // Working from the bottom, handle the first conditional branch. + if (!Cond.empty()) + return true; + + FBB = TBB; + MachineInstr *LastInst = &*I; + AnalyzeCondBr(LastInst, I->getOpcode(), TBB, Cond); + return false; + } + + return true; + } + + return false; } Index: lib/Target/NDS32/NDS32InstrInfo.td =================================================================== --- lib/Target/NDS32/NDS32InstrInfo.td +++ lib/Target/NDS32/NDS32InstrInfo.td @@ -335,6 +335,10 @@ def SB : MEM_store< "sb", truncstorei8, 0b00001000>; +//===----------------------------------------------------------------------===// +// Control Flow Instructions +// + class JREG_ret pat, bits<2> dt_it> : JREGForm<(outs), (ins), opstr, pat> { let Inst{24-15} = 0; @@ -349,6 +353,78 @@ def RET : JREG_ret<"ret", [(NDS32ret)], 0b00>; } +class JREG_jump pat, bits<2> dt_it, + bits<5> sub_opcode> : + JREGForm<(outs), (ins GPR:$Rb), + !strconcat(opstr, "\t$Rb"), pat> { + bits<5> Rb; + let Inst{24-15} = 0; + let Inst{14-10} = Rb; + let Inst{9-8} = dt_it; // DT/IT + let Inst{7-6} = 0; + let Inst{5} = 0; + let Inst{4-0} = sub_opcode; +} + +let isBranch = 1, isTerminator = 1, isBarrier=1 in { + + // Unconditional jump + def J : JIForm<(outs), (ins nds32_j_target:$target), + "j\t$target", + [(br bb:$target)]> { + bits<24> target; + let Inst{24} = 0; + let Inst{23-0} = target; + } + // Unconditional jump to to the target in register + def JR : JREG_jump<"jr", [(brind GPR:$Rb)], 0b00, 0b00000> { + let isIndirectBranch = 1; + } +} // isBranch, isTerminator + +// Conditional Branch +class CondBranch : + BR1Form<(outs), (ins GPR:$Rt, GPR:$Ra, brtarget:$offset), + !strconcat(opstr, "\t$Rt, $Ra, $offset"), + [(brcond (i32 (cond_op GPR:$Rt, GPR:$Ra)), bb:$offset)], beq_bne> { + let isBranch = 1; + let isTerminator = 1; +} + +def BEQ : CondBranch<"beq", seteq, 0>; +def BNE : CondBranch<"bne", setne, 1>; + + +// Conditional Branch compare with zero +class CondBranchZero branch_encode> : + BR2Form<(outs), (ins GPR:$Rt, brzerotarget:$offset), + !strconcat(opstr, "\t$Rt, $offset"), + [(brcond (i32 (cond_op GPR:$Rt, 0)), bb:$offset)], branch_encode> { + let isBranch = 1; + let isTerminator = 1; +} + +def BEQZ : CondBranchZero<"beqz", seteq, 0b0010>; +def BGEZ : CondBranchZero<"bgez", setge, 0b0100>; +def BGTZ : CondBranchZero<"bgtz", setgt, 0b0110>; +def BLEZ : CondBranchZero<"blez", setle, 0b0111>; +def BLTZ : CondBranchZero<"bltz", setlt, 0b0101>; +def BNEZ : CondBranchZero<"bnez", setne, 0b0011>; + + +// Conditional Branch compare with a constant +class CondBranchConstant : + BR3Form<(outs), (ins GPR:$Rt, imm11s:$imm, brtargetImm8s_32bit:$offset), + !strconcat(opstr, "\t$Rt, $imm, $offset"), + [(brcond (i32 (cond_op GPR:$Rt, imm11s:$imm)), bb:$offset)], + branch_encode> { + let isBranch = 1; + let isTerminator = 1; +} + +def BEQC : CondBranchConstant<"beqc", seteq, 0>; +def BNEC : CondBranchConstant<"bnec", setne, 1>; + //===----------------------------------------------------------------------===// // Pattern Transformation @@ -375,3 +451,47 @@ (SDIVREM i32:$Ra, i32:$Rb)>; def : Pat<(NDS32udivrem i32:$Ra, i32:$Rb), (UDIVREM i32:$Ra, i32:$Rb)>; + +// brcond patterns +def : Pat<(brcond (i32 (setlt i32:$lhs, 1)), bb:$dst), + (BLEZ i32:$lhs, bb:$dst)>; +def : Pat<(brcond (i32 (setgt i32:$lhs, -1)), bb:$dst), + (BGEZ i32:$lhs, bb:$dst)>; +def : Pat<(brcond GPR:$cond, bb:$dst), + (BNEZ GPR:$cond, bb:$dst)>; + +// seteq patterns +def : Pat<(seteq GPR:$lhs, 0), + (SLTI GPR:$lhs, 1)>; +def : Pat<(seteq GPR:$lhs, imm15u:$imm), + (SLTI (XORI GPR:$lhs, imm15u:$imm), 1)>; +def : Pat<(seteq GPR:$lhs, GPR:$rhs), + (SLTI (XOR GPR:$lhs, GPR:$rhs), 1)>; + +// setne patterns +def : Pat<(setne GPR:$lhs, imm15u:$imm), + (SLT (MOVI 0), (XORI GPR:$lhs, imm15u:$imm))>; +def : Pat<(setne GPR:$lhs, GPR:$rhs), + (SLT (MOVI 0), (XOR GPR:$lhs, GPR:$rhs))>; + +// setge/setuge patterns +def : Pat<(setge GPR:$lhs, GPR:$rhs), + (XORI (SLTS GPR:$lhs, GPR:$rhs), 1)>; +def : Pat<(setge GPR:$lhs, imm15s:$rhs), + (XORI (SLTSI GPR:$lhs, imm15s:$rhs), 1)>; +def : Pat<(setuge GPR:$lhs, GPR:$rhs), + (XORI (SLT GPR:$lhs, GPR:$rhs), 1)>; +def : Pat<(setuge GPR:$lhs, imm15s:$rhs), + (XORI (SLTI GPR:$lhs, imm15s:$rhs), 1)>; + +// setgt/setugt patterns +def : Pat<(setgt GPR:$lhs, GPR:$rhs), + (SLTS GPR:$rhs, GPR:$lhs)>; +def : Pat<(setugt GPR:$lhs, GPR:$rhs), + (SLT GPR:$rhs, GPR:$lhs)>; + +// setle/setule patterns +def : Pat<(setle GPR:$lhs, GPR:$rhs), + (XORI (SLTS GPR:$rhs, GPR:$lhs), 1)>; +def : Pat<(setule GPR:$lhs, GPR:$rhs), + (XORI (SLT GPR:$rhs, GPR:$lhs), 1)>; Index: lib/Target/NDS32/NDS32Predicate.td =================================================================== --- lib/Target/NDS32/NDS32Predicate.td +++ lib/Target/NDS32/NDS32Predicate.td @@ -27,6 +27,16 @@ class ImmAsmOperand : AsmOperandClass { let RenderMethod = "addImmOperands"; } +/// imm11s predicate - Immediate in the range [-(1 << 10) , (1 << 10)]. +def Imm11sAsmOperand: ImmAsmOperand { + let Name = "Imm11s"; + let DiagnosticType = "ImmRange11s"; +} +def imm11s : Operand, ImmLeaf= -(1 << 10) && Imm < (1 << 10); +}]> { +} + /// imm15s predicate - Immediate in the range [-(1 << 14) , (1 << 14)]. def Imm15sAsmOperand: ImmAsmOperand { let Name = "Imm15s"; @@ -126,3 +136,36 @@ let MIOperandInfo = (ops GPR:$base, GPR:$offsreg, i32imm:$shift); let PrintMethod = "printAddrRegShift"; } + + +//===----------------------------------------------------------------------===// +// Branch/Jump target Operands Predicates +// + +def NDS32JumpTarget : AsmOperandClass { + let Name = "NDS32JumpTarget"; +} + +def nds32_jump_target : Operand { + let OperandType = "OPERAND_PCREL"; +} + +def nds32_jal_target : Operand { + let OperandType = "OPERAND_PCREL"; +} + +def nds32_j_target : Operand { + let OperandType = "OPERAND_PCREL"; +} + +def brtarget : Operand { + let OperandType = "OPERAND_PCREL"; +} + +def brzerotarget : Operand { + let OperandType = "OPERAND_PCREL"; +} + +def brtargetImm8s_32bit : Operand { + let OperandType = "OPERAND_PCREL"; +} Index: test/CodeGen/NDS32/branch.ll =================================================================== --- /dev/null +++ test/CodeGen/NDS32/branch.ll @@ -0,0 +1,276 @@ +; RUN: llc < %s | FileCheck %s +target datalayout = "e-m:e-p:32:32-i64:64-a:0:32-n32-S64" +target triple = "nds32le---elf" + +; Function Attrs: noinline nounwind +define i32 @bne(i32 %a, i32 %b) #0 { +entry: + %retval = alloca i32, align 4 + %a.addr = alloca i32, align 4 + %b.addr = alloca i32, align 4 + store i32 %a, i32* %a.addr, align 4 + store i32 %b, i32* %b.addr, align 4 + %0 = load i32, i32* %a.addr, align 4 + %1 = load i32, i32* %b.addr, align 4 + %cmp = icmp eq i32 %0, %1 + br i1 %cmp, label %if.then, label %if.end +; CHECK: bne $r0, $r1, .LBB0_2 + +if.then: ; preds = %entry + %2 = load i32, i32* %a.addr, align 4 + store i32 %2, i32* %retval, align 4 + br label %return +; CHECK: j .LBB0_3 + +if.end: ; preds = %entry + store i32 0, i32* %retval, align 4 + br label %return + +return: ; preds = %if.end, %if.then + %3 = load i32, i32* %retval, align 4 + ret i32 %3 +} + +; Function Attrs: noinline nounwind +define i32 @beq(i32 %a, i32 %b) #0 { +entry: + %retval = alloca i32, align 4 + %a.addr = alloca i32, align 4 + %b.addr = alloca i32, align 4 + store i32 %a, i32* %a.addr, align 4 + store i32 %b, i32* %b.addr, align 4 + %0 = load i32, i32* %a.addr, align 4 + %1 = load i32, i32* %b.addr, align 4 + %cmp = icmp ne i32 %0, %1 + br i1 %cmp, label %if.then, label %if.end +; CHECK: beq $r0, $r1, .LBB1_2 + +if.then: ; preds = %entry + %2 = load i32, i32* %a.addr, align 4 + store i32 %2, i32* %retval, align 4 + br label %return + +if.end: ; preds = %entry + store i32 0, i32* %retval, align 4 + br label %return + +return: ; preds = %if.end, %if.then + %3 = load i32, i32* %retval, align 4 + ret i32 %3 +} + +; Function Attrs: noinline nounwind +define i32 @bnez(i32 %a, i32 %b) #0 { +entry: + %retval = alloca i32, align 4 + %a.addr = alloca i32, align 4 + %b.addr = alloca i32, align 4 + store i32 %a, i32* %a.addr, align 4 + store i32 %b, i32* %b.addr, align 4 + %0 = load i32, i32* %a.addr, align 4 + %cmp = icmp eq i32 %0, 0 + br i1 %cmp, label %if.then, label %if.end +; CHECK: bnez $r0, .LBB2_2 + +if.then: ; preds = %entry + %1 = load i32, i32* %b.addr, align 4 + store i32 %1, i32* %retval, align 4 + br label %return + +if.end: ; preds = %entry + store i32 0, i32* %retval, align 4 + br label %return + +return: ; preds = %if.end, %if.then + %2 = load i32, i32* %retval, align 4 + ret i32 %2 +} + +; Function Attrs: noinline nounwind +define i32 @beqz(i32 %a, i32 %b) #0 { +entry: + %retval = alloca i32, align 4 + %a.addr = alloca i32, align 4 + %b.addr = alloca i32, align 4 + store i32 %a, i32* %a.addr, align 4 + store i32 %b, i32* %b.addr, align 4 + %0 = load i32, i32* %a.addr, align 4 + %cmp = icmp ne i32 %0, 0 + br i1 %cmp, label %if.then, label %if.end +; CHECK: beqz $r0, .LBB3_2 + +if.then: ; preds = %entry + %1 = load i32, i32* %b.addr, align 4 + store i32 %1, i32* %retval, align 4 + br label %return + +if.end: ; preds = %entry + store i32 0, i32* %retval, align 4 + br label %return + +return: ; preds = %if.end, %if.then + %2 = load i32, i32* %retval, align 4 + ret i32 %2 +} + +; Function Attrs: noinline nounwind +define i32 @bltz(i32 %a, i32 %b) #0 { +entry: + %retval = alloca i32, align 4 + %a.addr = alloca i32, align 4 + %b.addr = alloca i32, align 4 + store i32 %a, i32* %a.addr, align 4 + store i32 %b, i32* %b.addr, align 4 + %0 = load i32, i32* %a.addr, align 4 + %cmp = icmp sge i32 %0, 0 + br i1 %cmp, label %if.then, label %if.end +; CHECK: bltz $r0, .LBB4_2 + +if.then: ; preds = %entry + %1 = load i32, i32* %b.addr, align 4 + store i32 %1, i32* %retval, align 4 + br label %return + +if.end: ; preds = %entry + store i32 0, i32* %retval, align 4 + br label %return + +return: ; preds = %if.end, %if.then + %2 = load i32, i32* %retval, align 4 + ret i32 %2 +} + +; Function Attrs: noinline nounwind +define i32 @bgez(i32 %a, i32 %b) #0 { +entry: + %retval = alloca i32, align 4 + %a.addr = alloca i32, align 4 + %b.addr = alloca i32, align 4 + store i32 %a, i32* %a.addr, align 4 + store i32 %b, i32* %b.addr, align 4 + %0 = load i32, i32* %a.addr, align 4 + %cmp = icmp slt i32 %0, 0 + br i1 %cmp, label %if.then, label %if.end +; CHECK: bgez $r0, .LBB5_2 + +if.then: ; preds = %entry + %1 = load i32, i32* %b.addr, align 4 + store i32 %1, i32* %retval, align 4 + br label %return + +if.end: ; preds = %entry + store i32 0, i32* %retval, align 4 + br label %return + +return: ; preds = %if.end, %if.then + %2 = load i32, i32* %retval, align 4 + ret i32 %2 +} + +; Function Attrs: noinline nounwind +define i32 @blez(i32 %a, i32 %b) #0 { +entry: + %retval = alloca i32, align 4 + %a.addr = alloca i32, align 4 + %b.addr = alloca i32, align 4 + store i32 %a, i32* %a.addr, align 4 + store i32 %b, i32* %b.addr, align 4 + %0 = load i32, i32* %a.addr, align 4 + %cmp = icmp sgt i32 %0, 0 + br i1 %cmp, label %if.then, label %if.end +; CHECK: blez $r0, .LBB6_2 + +if.then: ; preds = %entry + %1 = load i32, i32* %b.addr, align 4 + store i32 %1, i32* %retval, align 4 + br label %return + +if.end: ; preds = %entry + store i32 0, i32* %retval, align 4 + br label %return + +return: ; preds = %if.end, %if.then + %2 = load i32, i32* %retval, align 4 + ret i32 %2 +} + +; Function Attrs: noinline nounwind +define i32 @bgtz(i32 %a, i32 %b) #0 { +entry: + %retval = alloca i32, align 4 + %a.addr = alloca i32, align 4 + %b.addr = alloca i32, align 4 + store i32 %a, i32* %a.addr, align 4 + store i32 %b, i32* %b.addr, align 4 + %0 = load i32, i32* %a.addr, align 4 + %cmp = icmp sle i32 %0, 0 + br i1 %cmp, label %if.then, label %if.end +; CHECK: bgtz $r0, .LBB7_2 + +if.then: ; preds = %entry + %1 = load i32, i32* %b.addr, align 4 + store i32 %1, i32* %retval, align 4 + br label %return + +if.end: ; preds = %entry + store i32 0, i32* %retval, align 4 + br label %return + +return: ; preds = %if.end, %if.then + %2 = load i32, i32* %retval, align 4 + ret i32 %2 +} + +; Function Attrs: noinline nounwind +define i32 @bnec(i32 %a, i32 %b) #0 { +entry: + %retval = alloca i32, align 4 + %a.addr = alloca i32, align 4 + %b.addr = alloca i32, align 4 + store i32 %a, i32* %a.addr, align 4 + store i32 %b, i32* %b.addr, align 4 + %0 = load i32, i32* %a.addr, align 4 + %cmp = icmp eq i32 %0, 5 + br i1 %cmp, label %if.then, label %if.end +; CHECK: bnec $r0, 5, .LBB8_2 + +if.then: ; preds = %entry + %1 = load i32, i32* %b.addr, align 4 + store i32 %1, i32* %retval, align 4 + br label %return + +if.end: ; preds = %entry + store i32 0, i32* %retval, align 4 + br label %return + +return: ; preds = %if.end, %if.then + %2 = load i32, i32* %retval, align 4 + ret i32 %2 +} + +; Function Attrs: noinline nounwind +define i32 @beqc(i32 %a, i32 %b) #0 { +entry: + %retval = alloca i32, align 4 + %a.addr = alloca i32, align 4 + %b.addr = alloca i32, align 4 + store i32 %a, i32* %a.addr, align 4 + store i32 %b, i32* %b.addr, align 4 + %0 = load i32, i32* %a.addr, align 4 + %cmp = icmp ne i32 %0, 5 + br i1 %cmp, label %if.then, label %if.end +; CHECK: beqc $r0, 5, .LBB9_2 + +if.then: ; preds = %entry + %1 = load i32, i32* %b.addr, align 4 + store i32 %1, i32* %retval, align 4 + br label %return + +if.end: ; preds = %entry + store i32 0, i32* %retval, align 4 + br label %return + +return: ; preds = %if.end, %if.then + %2 = load i32, i32* %retval, align 4 + ret i32 %2 +}