Index: llvm/trunk/lib/Target/X86/X86InstructionSelector.cpp =================================================================== --- llvm/trunk/lib/Target/X86/X86InstructionSelector.cpp +++ llvm/trunk/lib/Target/X86/X86InstructionSelector.cpp @@ -83,6 +83,8 @@ MachineFunction &MF) const; bool selectExtract(MachineInstr &I, MachineRegisterInfo &MRI, MachineFunction &MF) const; + bool selectCondBranch(MachineInstr &I, MachineRegisterInfo &MRI, + MachineFunction &MF) const; // emit insert subreg instruction and insert it before MachineInstr &I bool emitInsertSubreg(unsigned DstReg, unsigned SrcReg, MachineInstr &I, @@ -330,6 +332,8 @@ return true; if (selectInsert(I, MRI, MF)) return true; + if (selectCondBranch(I, MRI, MF)) + return true; return false; } @@ -1101,6 +1105,29 @@ I.eraseFromParent(); return true; } + +bool X86InstructionSelector::selectCondBranch(MachineInstr &I, + MachineRegisterInfo &MRI, + MachineFunction &MF) const { + if (I.getOpcode() != TargetOpcode::G_BRCOND) + return false; + + const unsigned CondReg = I.getOperand(0).getReg(); + MachineBasicBlock *DestMBB = I.getOperand(1).getMBB(); + + MachineInstr &TestInst = + *BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(X86::TEST8ri)) + .addReg(CondReg) + .addImm(1); + BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(X86::JNE_1)) + .addMBB(DestMBB); + + constrainSelectedInstRegOperands(TestInst, TII, TRI, RBI); + + I.eraseFromParent(); + return true; +} + InstructionSelector * llvm::createX86InstructionSelector(const X86TargetMachine &TM, X86Subtarget &Subtarget, Index: llvm/trunk/lib/Target/X86/X86LegalizerInfo.cpp =================================================================== --- llvm/trunk/lib/Target/X86/X86LegalizerInfo.cpp +++ llvm/trunk/lib/Target/X86/X86LegalizerInfo.cpp @@ -80,6 +80,9 @@ for (auto Ty : {s1, s8, s16}) setAction({G_GEP, 1, Ty}, WidenScalar); + // Control-flow + setAction({G_BRCOND, s1}, Legal); + // Constants for (auto Ty : {s8, s16, s32, p0}) setAction({TargetOpcode::G_CONSTANT, Ty}, Legal); @@ -141,6 +144,9 @@ for (auto Ty : {s1, s8, s16}) setAction({G_GEP, 1, Ty}, WidenScalar); + // Control-flow + setAction({G_BRCOND, s1}, Legal); + // Constants for (auto Ty : {s8, s16, s32, s64, p0}) setAction({TargetOpcode::G_CONSTANT, Ty}, Legal); Index: llvm/trunk/test/CodeGen/X86/GlobalISel/brcond.ll =================================================================== --- llvm/trunk/test/CodeGen/X86/GlobalISel/brcond.ll +++ llvm/trunk/test/CodeGen/X86/GlobalISel/brcond.ll @@ -0,0 +1,91 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -mtriple=x86_64-linux-gnu -global-isel -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=X64 +; RUN: llc -mtriple=i386-linux-gnu -global-isel -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=X32 + +define i32 @test_1(i32 %a, i32 %b, i32 %tValue, i32 %fValue) { +; X64-LABEL: test_1: +; X64: # BB#0: # %entry +; X64-NEXT: cmpl %esi, %edi +; X64-NEXT: setl %al +; X64-NEXT: testb $1, %al +; X64-NEXT: je .LBB0_2 +; X64-NEXT: # BB#1: # %if.then +; X64-NEXT: movl %edx, -{{[0-9]+}}(%rsp) +; X64-NEXT: movl -{{[0-9]+}}(%rsp), %eax +; X64-NEXT: retq +; X64-NEXT: .LBB0_2: # %if.else +; X64-NEXT: movl %ecx, -{{[0-9]+}}(%rsp) +; X64-NEXT: movl -{{[0-9]+}}(%rsp), %eax +; X64-NEXT: retq +; +; X32-LABEL: test_1: +; X32: # BB#0: # %entry +; X32-NEXT: pushl %eax +; X32-NEXT: .Lcfi0: +; X32-NEXT: .cfi_def_cfa_offset 8 +; X32-NEXT: movl {{[0-9]+}}(%esp), %eax +; X32-NEXT: cmpl %eax, {{[0-9]+}}(%esp) +; X32-NEXT: setl %al +; X32-NEXT: testb $1, %al +; X32-NEXT: je .LBB0_2 +; X32-NEXT: # BB#1: # %if.then +; X32-NEXT: movl {{[0-9]+}}(%esp), %eax +; X32-NEXT: jmp .LBB0_3 +; X32-NEXT: .LBB0_2: # %if.else +; X32-NEXT: movl {{[0-9]+}}(%esp), %eax +; X32-NEXT: .LBB0_3: # %return +; X32-NEXT: movl %eax, (%esp) +; X32-NEXT: movl (%esp), %eax +; X32-NEXT: popl %ecx +; X32-NEXT: retl +entry: + %retval = alloca i32, align 4 + %cmp = icmp slt i32 %a, %b + br i1 %cmp, label %if.then, label %if.else + +if.then: + store i32 %tValue, i32* %retval, align 4 + br label %return + +if.else: + store i32 %fValue, i32* %retval, align 4 + br label %return + +return: + %0 = load i32, i32* %retval, align 4 + ret i32 %0 +} + +define i32 @test_2(i32 %a) { +; X64-LABEL: test_2: +; X64: # BB#0: # %entry +; X64-NEXT: testb $1, %dil +; X64-NEXT: je .LBB1_2 +; X64-NEXT: # BB#1: # %if.then +; X64-NEXT: xorl %eax, %eax +; X64-NEXT: retq +; X64-NEXT: .LBB1_2: # %if.else +; X64-NEXT: movl $1, %eax +; X64-NEXT: retq +; +; X32-LABEL: test_2: +; X32: # BB#0: # %entry +; X32-NEXT: movl {{[0-9]+}}(%esp), %eax +; X32-NEXT: testb $1, %al +; X32-NEXT: je .LBB1_2 +; X32-NEXT: # BB#1: # %if.then +; X32-NEXT: xorl %eax, %eax +; X32-NEXT: retl +; X32-NEXT: .LBB1_2: # %if.else +; X32-NEXT: movl $1, %eax +; X32-NEXT: retl +entry: + %cmp = trunc i32 %a to i1 + br i1 %cmp, label %if.then, label %if.else + +if.then: + ret i32 0 +if.else: + ret i32 1 +} + Index: llvm/trunk/test/CodeGen/X86/GlobalISel/legalize-brcond.mir =================================================================== --- llvm/trunk/test/CodeGen/X86/GlobalISel/legalize-brcond.mir +++ llvm/trunk/test/CodeGen/X86/GlobalISel/legalize-brcond.mir @@ -0,0 +1,58 @@ +# RUN: llc -mtriple=x86_64-linux-gnu -global-isel -run-pass=legalizer %s -o - | FileCheck %s --check-prefix=ALL --check-prefix=X64 +# RUN: llc -mtriple=i386-linux-gnu -global-isel -run-pass=legalizer %s -o - | FileCheck %s --check-prefix=ALL --check-prefix=X32 + +--- | + + define i32 @test(i32 %a) { + entry: + %cmp = trunc i32 %a to i1 + br i1 %cmp, label %if.then, label %if.else + + if.then: ; preds = %entry + ret i32 0 + + if.else: ; preds = %entry + ret i32 1 + } +... +--- +name: test +# ALL-LABEL: name: test +alignment: 4 +legalized: false +regBankSelected: false +registers: + - { id: 0, class: _, preferred-register: '' } + - { id: 1, class: _, preferred-register: '' } + - { id: 2, class: _, preferred-register: '' } + - { id: 3, class: _, preferred-register: '' } +# ALL: %1(s1) = G_TRUNC %0(s32) +# ALL-NEXT: G_BRCOND %1(s1), %[[TRUE:bb.[0-9]+.if.then]] +# ALL-NEXT: G_BR %[[FALSE:bb.[0-9]+.if.else]] +# ALL: [[TRUE]]: +# ALL-NEXT: %eax = COPY %2(s32) +# ALL-NEXT: RET 0, implicit %eax +# ALL: [[FALSE]]: +# ALL-NEXT: %eax = COPY %3(s32) +# ALL-NEXT: RET 0, implicit %eax +body: | + bb.1.entry: + successors: %bb.2.if.then(0x40000000), %bb.3.if.else(0x40000000) + liveins: %edi + + %0(s32) = COPY %edi + %2(s32) = G_CONSTANT i32 0 + %3(s32) = G_CONSTANT i32 1 + %1(s1) = G_TRUNC %0(s32) + G_BRCOND %1(s1), %bb.2.if.then + G_BR %bb.3.if.else + + bb.2.if.then: + %eax = COPY %2(s32) + RET 0, implicit %eax + + bb.3.if.else: + %eax = COPY %3(s32) + RET 0, implicit %eax + +... Index: llvm/trunk/test/CodeGen/X86/GlobalISel/select-brcond.mir =================================================================== --- llvm/trunk/test/CodeGen/X86/GlobalISel/select-brcond.mir +++ llvm/trunk/test/CodeGen/X86/GlobalISel/select-brcond.mir @@ -0,0 +1,76 @@ +# RUN: llc -mtriple=x86_64-linux-gnu -global-isel -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=X64 +# RUN: llc -mtriple=i386-linux-gnu -global-isel -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=X32 + +--- | + + define i32 @test(i32 %a) { + entry: + %cmp = trunc i32 %a to i1 + br i1 %cmp, label %true, label %false + + true: ; preds = %entry + ret i32 0 + + false: ; preds = %entry + ret i32 1 + } + +... +--- +name: test +# CHECK-LABEL: name: test +alignment: 4 +legalized: true +regBankSelected: true +# X64: registers: +# X64-NEXT: - { id: 0, class: gr32, preferred-register: '' } +# X64-NEXT: - { id: 1, class: gr8, preferred-register: '' } +# X64-NEXT: - { id: 2, class: gr32, preferred-register: '' } +# X64-NEXT: - { id: 3, class: gr32, preferred-register: '' } +# +# X32: registers: +# X32-NEXT: - { id: 0, class: gr32_abcd, preferred-register: '' } +# X32-NEXT: - { id: 1, class: gr8, preferred-register: '' } +# X32-NEXT: - { id: 2, class: gr32, preferred-register: '' } +# X32-NEXT: - { id: 3, class: gr32, preferred-register: '' } +registers: + - { id: 0, class: gpr, preferred-register: '' } + - { id: 1, class: gpr, preferred-register: '' } + - { id: 2, class: gpr, preferred-register: '' } + - { id: 3, class: gpr, preferred-register: '' } +# CHECK: %0 = COPY %edi +# CHECK-NEXT: %2 = MOV32r0 implicit-def %eflags +# CHECK-NEXT: %3 = MOV32ri 1 +# CHECK-NEXT: %1 = COPY %0.sub_8bit +# CHECK-NEXT: TEST8ri %1, 1, implicit-def %eflags +# CHECK-NEXT: JNE_1 %[[TRUE:bb.[0-9].true]], implicit %eflags +# CHECK-NEXT: JMP_1 %[[FALSE:bb.[0-9].false]] +# CHECK: [[TRUE]]: +# CHECK-NEXT: %eax = COPY %2 +# CHECK-NEXT: RET 0, implicit %eax +# CHECK: [[FALSE]]: +# CHECK-NEXT: %eax = COPY %3 +# CHECK-NEXT: RET 0, implicit %eax + + +body: | + bb.1.entry: + successors: %bb.2.true(0x40000000), %bb.3.false(0x40000000) + liveins: %edi + + %0(s32) = COPY %edi + %2(s32) = G_CONSTANT i32 0 + %3(s32) = G_CONSTANT i32 1 + %1(s1) = G_TRUNC %0(s32) + G_BRCOND %1(s1), %bb.2.true + G_BR %bb.3.false + + bb.2.true: + %eax = COPY %2(s32) + RET 0, implicit %eax + + bb.3.false: + %eax = COPY %3(s32) + RET 0, implicit %eax + +...