llvm.org GIT mirror llvm / 04f47c7
[GlobalISel][X86] Support add i64 in IA32. Summary: support G_UADDE instruction selection. Reviewers: zvi, guyblank Reviewed By: guyblank Subscribers: rovka, kristof.beyls, llvm-commits Differential Revision: https://reviews.llvm.org/D33096 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@303255 91177308-0d34-0410-b5e6-96231b3b80d8 Igor Breger 3 years ago
6 changed file(s) with 291 addition(s) and 44 deletion(s). Raw diff Collapse all Expand all
1818 #include "X86Subtarget.h"
1919 #include "X86TargetMachine.h"
2020 #include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
21 #include "llvm/CodeGen/GlobalISel/Utils.h"
2122 #include "llvm/CodeGen/MachineBasicBlock.h"
2223 #include "llvm/CodeGen/MachineFunction.h"
2324 #include "llvm/CodeGen/MachineInstr.h"
7071 MachineFunction &MF) const;
7172 bool selectCmp(MachineInstr &I, MachineRegisterInfo &MRI,
7273 MachineFunction &MF) const;
74
75 bool selectUadde(MachineInstr &I, MachineRegisterInfo &MRI,
76 MachineFunction &MF) const;
7377
7478 const X86TargetMachine &TM;
7579 const X86Subtarget &STI;
241245 if (selectZext(I, MRI, MF))
242246 return true;
243247 if (selectCmp(I, MRI, MF))
248 return true;
249 if (selectUadde(I, MRI, MF))
244250 return true;
245251
246252 return false;
563569 return true;
564570 }
565571
572 bool X86InstructionSelector::selectUadde(MachineInstr &I,
573 MachineRegisterInfo &MRI,
574 MachineFunction &MF) const {
575 if (I.getOpcode() != TargetOpcode::G_UADDE)
576 return false;
577
578 const unsigned DstReg = I.getOperand(0).getReg();
579 const unsigned CarryOutReg = I.getOperand(1).getReg();
580 const unsigned Op0Reg = I.getOperand(2).getReg();
581 const unsigned Op1Reg = I.getOperand(3).getReg();
582 unsigned CarryInReg = I.getOperand(4).getReg();
583
584 const LLT DstTy = MRI.getType(DstReg);
585
586 if (DstTy != LLT::scalar(32))
587 return false;
588
589 // find CarryIn def instruction.
590 MachineInstr *Def = MRI.getVRegDef(CarryInReg);
591 while (Def->getOpcode() == TargetOpcode::G_TRUNC) {
592 CarryInReg = Def->getOperand(1).getReg();
593 Def = MRI.getVRegDef(CarryInReg);
594 }
595
596 unsigned Opcode;
597 if (Def->getOpcode() == TargetOpcode::G_UADDE) {
598 // carry set by prev ADD.
599
600 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(X86::COPY), X86::EFLAGS)
601 .addReg(CarryInReg);
602
603 if (!RBI.constrainGenericRegister(CarryInReg, X86::GR32RegClass, MRI))
604 return false;
605
606 Opcode = X86::ADC32rr;
607 } else if (auto val = getConstantVRegVal(CarryInReg, MRI)) {
608 // carry is constant, support only 0.
609 if (*val != 0)
610 return false;
611
612 Opcode = X86::ADD32rr;
613 } else
614 return false;
615
616 MachineInstr &AddInst =
617 *BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opcode), DstReg)
618 .addReg(Op0Reg)
619 .addReg(Op1Reg);
620
621 BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(X86::COPY), CarryOutReg)
622 .addReg(X86::EFLAGS);
623
624 if (!constrainSelectedInstRegOperands(AddInst, TII, TRI, RBI) ||
625 !RBI.constrainGenericRegister(CarryOutReg, X86::GR32RegClass, MRI))
626 return false;
627
628 I.eraseFromParent();
629 return true;
630 }
631
566632 InstructionSelector *
567633 llvm::createX86InstructionSelector(const X86TargetMachine &TM,
568634 X86Subtarget &Subtarget,
5858 for (auto Ty : {s8, s16, s32})
5959 setAction({BinOp, Ty}, Legal);
6060
61 for (unsigned Op : {G_UADDE}) {
62 setAction({Op, s32}, Legal);
63 setAction({Op, 1, s1}, Legal);
64 }
65
6166 for (unsigned MemOp : {G_LOAD, G_STORE}) {
6267 for (auto Ty : {s8, s16, s32, p0})
6368 setAction({MemOp, Ty}, Legal);
0 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
11 ; RUN: llc -mtriple=x86_64-linux-gnu -global-isel < %s -o - | FileCheck %s --check-prefix=ALL --check-prefix=X64
2 ; RUN: llc -mtriple=i386-linux-gnu -global-isel < %s -o - | FileCheck %s --check-prefix=ALL --check-prefix=X32
23
34 define i64 @test_add_i64(i64 %arg1, i64 %arg2) {
4 ; ALL-LABEL: test_add_i64:
5 ; ALL: # BB#0:
6 ; ALL-NEXT: leaq (%rsi,%rdi), %rax
7 ; ALL-NEXT: retq
5 ; X64-LABEL: test_add_i64:
6 ; X64: # BB#0:
7 ; X64-NEXT: leaq (%rsi,%rdi), %rax
8 ; X64-NEXT: retq
9 ;
10 ; X32-LABEL: test_add_i64:
11 ; X32: # BB#0:
12 ; X32-NEXT: pushl %ebp
13 ; X32-NEXT: .Lcfi0:
14 ; X32-NEXT: .cfi_def_cfa_offset 8
15 ; X32-NEXT: .Lcfi1:
16 ; X32-NEXT: .cfi_offset %ebp, -8
17 ; X32-NEXT: movl %esp, %ebp
18 ; X32-NEXT: .Lcfi2:
19 ; X32-NEXT: .cfi_def_cfa_register %ebp
20 ; X32-NEXT: pushl %esi
21 ; X32-NEXT: .Lcfi3:
22 ; X32-NEXT: .cfi_offset %esi, -12
23 ; X32-NEXT: leal 8(%ebp), %ecx
24 ; X32-NEXT: leal 12(%ebp), %esi
25 ; X32-NEXT: leal 16(%ebp), %eax
26 ; X32-NEXT: movl (%eax), %eax
27 ; X32-NEXT: leal 20(%ebp), %edx
28 ; X32-NEXT: movl (%edx), %edx
29 ; X32-NEXT: addl (%ecx), %eax
30 ; X32-NEXT: adcl (%esi), %edx
31 ; X32-NEXT: popl %esi
32 ; X32-NEXT: popl %ebp
33 ; X32-NEXT: retl
834 %ret = add i64 %arg1, %arg2
935 ret i64 %ret
1036 }
1137
1238 define i32 @test_add_i32(i32 %arg1, i32 %arg2) {
13 ; ALL-LABEL: test_add_i32:
14 ; ALL: # BB#0:
15 ; ALL-NEXT: # kill: %EDI %EDI %RDI
16 ; ALL-NEXT: # kill: %ESI %ESI %RSI
17 ; ALL-NEXT: leal (%rsi,%rdi), %eax
18 ; ALL-NEXT: retq
39 ; X64-LABEL: test_add_i32:
40 ; X64: # BB#0:
41 ; X64-NEXT: # kill: %EDI %EDI %RDI
42 ; X64-NEXT: # kill: %ESI %ESI %RSI
43 ; X64-NEXT: leal (%rsi,%rdi), %eax
44 ; X64-NEXT: retq
45 ;
46 ; X32-LABEL: test_add_i32:
47 ; X32: # BB#0:
48 ; X32-NEXT: leal 4(%esp), %ecx
49 ; X32-NEXT: leal 8(%esp), %eax
50 ; X32-NEXT: movl (%eax), %eax
51 ; X32-NEXT: addl (%ecx), %eax
52 ; X32-NEXT: retl
1953 %ret = add i32 %arg1, %arg2
2054 ret i32 %ret
2155 }
2256
2357 define i16 @test_add_i16(i16 %arg1, i16 %arg2) {
24 ; ALL-LABEL: test_add_i16:
25 ; ALL: # BB#0:
26 ; ALL-NEXT: # kill: %DI %DI %RDI
27 ; ALL-NEXT: # kill: %SI %SI %RSI
28 ; ALL-NEXT: leal (%rsi,%rdi), %eax
29 ; ALL-NEXT: # kill: %AX %AX %EAX
30 ; ALL-NEXT: retq
58 ; X64-LABEL: test_add_i16:
59 ; X64: # BB#0:
60 ; X64-NEXT: # kill: %DI %DI %RDI
61 ; X64-NEXT: # kill: %SI %SI %RSI
62 ; X64-NEXT: leal (%rsi,%rdi), %eax
63 ; X64-NEXT: # kill: %AX %AX %EAX
64 ; X64-NEXT: retq
65 ;
66 ; X32-LABEL: test_add_i16:
67 ; X32: # BB#0:
68 ; X32-NEXT: leal 4(%esp), %ecx
69 ; X32-NEXT: leal 8(%esp), %eax
70 ; X32-NEXT: movzwl (%eax), %eax
71 ; X32-NEXT: addw (%ecx), %ax
72 ; X32-NEXT: retl
3173 %ret = add i16 %arg1, %arg2
3274 ret i16 %ret
3375 }
3476
3577 define i8 @test_add_i8(i8 %arg1, i8 %arg2) {
36 ; ALL-LABEL: test_add_i8:
37 ; ALL: # BB#0:
38 ; ALL-NEXT: addb %dil, %sil
39 ; ALL-NEXT: movl %esi, %eax
40 ; ALL-NEXT: retq
78 ; X64-LABEL: test_add_i8:
79 ; X64: # BB#0:
80 ; X64-NEXT: addb %dil, %sil
81 ; X64-NEXT: movl %esi, %eax
82 ; X64-NEXT: retq
83 ;
84 ; X32-LABEL: test_add_i8:
85 ; X32: # BB#0:
86 ; X32-NEXT: leal 4(%esp), %ecx
87 ; X32-NEXT: leal 8(%esp), %eax
88 ; X32-NEXT: movb (%eax), %al
89 ; X32-NEXT: addb (%ecx), %al
90 ; X32-NEXT: retl
4191 %ret = add i8 %arg1, %arg2
4292 ret i8 %ret
4393 }
None # RUN: llc -mtriple=x86_64-linux-gnu -global-isel -run-pass=legalizer %s -o - | FileCheck %s
0 # RUN: llc -mtriple=x86_64-linux-gnu -global-isel -run-pass=legalizer %s -o - | FileCheck %s --check-prefix=ALL --check-prefix=X64
1 # RUN: llc -mtriple=i386-linux-gnu -global-isel -run-pass=legalizer %s -o - | FileCheck %s --check-prefix=ALL --check-prefix=X32
2 --- |
3 define void @test_add_i32() {
4 ret void
5 }
16
2 --- |
3 ; ModuleID = ''
4 source_filename = ""
5 target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
6 target triple = "x86_64--linux-gnu"
7
8 define i32 @test_add_i32(i32 %arg1, i32 %arg2) {
9 %ret = add i32 %arg1, %arg2
10 ret i32 %ret
7 define void @test_add_i64() {
8 ret void
119 }
1210
1311 ...
1412 ---
1513 name: test_add_i32
14 # ALL-LABEL: name: test_add_i32
1615 alignment: 4
1716 legalized: false
1817 regBankSelected: false
19 selected: false
20 tracksRegLiveness: true
2118 registers:
2219 - { id: 0, class: _ }
2320 - { id: 1, class: _ }
2421 - { id: 2, class: _ }
22 # ALL: %0(s32) = IMPLICIT_DEF
23 # ALL-NEXT: %1(s32) = IMPLICIT_DEF
24 # ALL-NEXT: %2(s32) = G_ADD %0, %1
25 # ALL-NEXT: RET 0
2526 body: |
2627 bb.1 (%ir-block.0):
27 liveins: %edi, %esi
28 ; CHECK-LABEL: name: test_add_i32
29 ; CHECK: [[VAL1:%.*]](s32) = COPY %edi
30 ; CHECK: [[VAL2:%.*]](s32) = COPY %esi
31 ; CHECK: [[RES:%.*]](s32) = G_ADD [[VAL1:%.*]], [[VAL2:%.*]]
32
33 %0(s32) = COPY %edi
34 %1(s32) = COPY %esi
28 %0(s32) = IMPLICIT_DEF
29 %1(s32) = IMPLICIT_DEF
3530 %2(s32) = G_ADD %0, %1
36 %eax = COPY %2(s32)
37 RET 0, implicit %eax
31 RET 0
3832
3933 ...
34 ---
35 name: test_add_i64
36 # ALL-LABEL: name: test_add_i64
37 alignment: 4
38 legalized: false
39 regBankSelected: false
40 registers:
41 - { id: 0, class: _ }
42 - { id: 1, class: _ }
43 - { id: 2, class: _ }
44 # X64: %0(s64) = IMPLICIT_DEF
45 # X64-NEXT: %1(s64) = IMPLICIT_DEF
46 # X64-NEXT: %2(s64) = G_ADD %0, %1
47 # X64-NEXT: RET 0
48 #
49 # X32: %0(s64) = IMPLICIT_DEF
50 # X32-NEXT: %1(s64) = IMPLICIT_DEF
51 # X32-NEXT: %3(s32), %4(s32) = G_UNMERGE_VALUES %0(s64)
52 # X32-NEXT: %5(s32), %6(s32) = G_UNMERGE_VALUES %1(s64)
53 # X32-NEXT: %12(s8) = G_CONSTANT i8 0
54 # X32-NEXT: %7(s1) = G_TRUNC %12(s8)
55 # X32-NEXT: %8(s32), %9(s1) = G_UADDE %3, %5, %7
56 # X32-NEXT: %10(s32), %11(s1) = G_UADDE %4, %6, %9
57 # X32-NEXT: %2(s64) = G_MERGE_VALUES %8(s32), %10(s32)
58 # X32-NEXT: RET 0
59 body: |
60 bb.1 (%ir-block.0):
61 %0(s64) = IMPLICIT_DEF
62 %1(s64) = IMPLICIT_DEF
63 %2(s64) = G_ADD %0, %1
64 RET 0
65
66 ...
0 # RUN: llc -mtriple=i386-linux-gnu -global-isel -run-pass=regbankselect %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=FAST
1 # RUN: llc -mtriple=i386-linux-gnu -global-isel -regbankselect-greedy -run-pass=regbankselect %s -o - | FileCheck %s --check-prefix=CHECK --check-prefix=GREEDY
2
3 --- |
4 define void @test_uadde_i32() {
5 ret void
6 }
7
8 ...
9 ---
10 name: test_uadde_i32
11 # CHECK-LABEL: name: test_uadde_i32
12 alignment: 4
13 legalized: true
14 regBankSelected: false
15 # CHECK: registers:
16 # CHECK-NEXT: - { id: 0, class: gpr }
17 # CHECK-NEXT: - { id: 1, class: gpr }
18 # CHECK-NEXT: - { id: 2, class: gpr }
19 # CHECK-NEXT: - { id: 3, class: gpr }
20 # CHECK-NEXT: - { id: 4, class: gpr }
21 registers:
22 - { id: 0, class: _ }
23 - { id: 1, class: _ }
24 - { id: 2, class: _ }
25 - { id: 3, class: _ }
26 - { id: 4, class: _ }
27 body: |
28 bb.0 (%ir-block.0):
29 %0(s32) = IMPLICIT_DEF
30 %1(s32) = IMPLICIT_DEF
31 %2(s1) = IMPLICIT_DEF
32 %3(s32), %4(s1) = G_UADDE %0, %1, %2
33 RET 0
34
35 ...
0 # RUN: llc -mtriple=i386-linux-gnu -global-isel -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=X32
1 --- |
2 define i64 @test_add_i64(i64 %a, i64 %b) {
3 %r = add i64 %a, %b
4 ret i64 %r
5 }
6
7 ...
8 ---
9 name: test_add_i64
10 # X32-LABEL: name: test_add_i64
11 alignment: 4
12 legalized: true
13 regBankSelected: true
14 # X32: registers:
15 # X32-NEXT: - { id: 0, class: gr32 }
16 # X32-NEXT: - { id: 1, class: gr32 }
17 # X32-NEXT: - { id: 2, class: gr32 }
18 # X32-NEXT: - { id: 3, class: gr32 }
19 # X32-NEXT: - { id: 4, class: gpr }
20 # X32-NEXT: - { id: 5, class: gr32 }
21 # X32-NEXT: - { id: 6, class: gr32 }
22 # X32-NEXT: - { id: 7, class: gr32 }
23 # X32-NEXT: - { id: 8, class: gr32 }
24 # X32-NEXT: - { id: 9, class: gpr }
25 registers:
26 - { id: 0, class: gpr }
27 - { id: 1, class: gpr }
28 - { id: 2, class: gpr }
29 - { id: 3, class: gpr }
30 - { id: 4, class: gpr }
31 - { id: 5, class: gpr }
32 - { id: 6, class: gpr }
33 - { id: 7, class: gpr }
34 - { id: 8, class: gpr }
35 - { id: 9, class: gpr }
36 # X32: %0 = IMPLICIT_DEF
37 # X32-NEXT: %1 = IMPLICIT_DEF
38 # X32-NEXT: %2 = IMPLICIT_DEF
39 # X32-NEXT: %3 = IMPLICIT_DEF
40 # X32-NEXT: %5 = ADD32rr %0, %2, implicit-def %eflags
41 # X32-NEXT: %6 = COPY %eflags
42 # X32-NEXT: %eflags = COPY %6
43 # X32-NEXT: %7 = ADC32rr %1, %3, implicit-def %eflags, implicit %eflags
44 # X32-NEXT: %8 = COPY %eflags
45 # X32-NEXT: %eax = COPY %5
46 # X32-NEXT: %edx = COPY %7
47 # X32-NEXT: RET 0, implicit %eax, implicit %edx
48 body: |
49 bb.0 (%ir-block.0):
50 %0(s32) = IMPLICIT_DEF
51 %1(s32) = IMPLICIT_DEF
52 %2(s32) = IMPLICIT_DEF
53 %3(s32) = IMPLICIT_DEF
54 %9(s8) = G_CONSTANT i8 0
55 %4(s1) = G_TRUNC %9(s8)
56 %5(s32), %6(s1) = G_UADDE %0, %2, %4
57 %7(s32), %8(s1) = G_UADDE %1, %3, %6
58 %eax = COPY %5(s32)
59 %edx = COPY %7(s32)
60 RET 0, implicit %eax, implicit %edx
61
62 ...