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,
return true;
if (selectInsert(I, MRI, MF))
return true;
+ if (selectCondBranch(I, MRI, MF))
+ return true;
return false;
}
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,
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);
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);
--- /dev/null
+; 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
+}
+
--- /dev/null
+# 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
+
+...
--- /dev/null
+# 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
+
+...