LLVM_DEBUG(dbgs() << "FixLEA: Replaced by: ";);
MachineInstr *NewMI = nullptr;
+ bool BaseOrIndexIsDst = DestReg == BaseReg || DestReg == IndexReg;
+ // First try and remove the base while sticking with LEA iff base == index and
+ // scale == 1. We can handle:
+ // 1. lea D(%base,%index,1) -> lea D(,%index,2)
+ // 2. lea D(%r13/%rbp,%index) -> lea D(,%index,2)
+ // Only do this if the LEA would otherwise be split into 2-instruction
+ // (either it has a an Offset or neither base nor index are dst)
+ if (IsScale1 && BaseReg == IndexReg &&
+ (hasLEAOffset(Offset) || (IsInefficientBase && !BaseOrIndexIsDst))) {
+ NewMI = BuildMI(MBB, MI, MI.getDebugLoc(), TII->get(LEAOpcode))
+ .add(Dest)
+ .addReg(0)
+ .addImm(2)
+ .add(Index)
+ .add(Offset)
+ .add(Segment);
+ LLVM_DEBUG(NewMI->dump(););
+
+ MBB.getParent()->substituteDebugValuesForInst(*I, *NewMI, 1);
+ MBB.erase(I);
+ I = NewMI;
+ return;
+ } else if (IsScale1 && BaseOrIndexIsDst) {
+ // Try to replace LEA with one or two (for the 3-op LEA case)
+ // add instructions:
+ // 1.lea (%base,%index,1), %base => add %index,%base
+ // 2.lea (%base,%index,1), %index => add %base,%index
- // First try to replace LEA with one or two (for the 3-op LEA case)
- // add instructions:
- // 1.lea (%base,%index,1), %base => add %index,%base
- // 2.lea (%base,%index,1), %index => add %base,%index
- if (IsScale1 && (DestReg == BaseReg || DestReg == IndexReg)) {
unsigned NewOpc = getADDrrFromLEA(MI.getOpcode());
if (DestReg != BaseReg)
std::swap(BaseReg, IndexReg);
ret i32 0
}
- ;test1mov1add_ebp_32: 2 operands LEA32r that can be replaced with 1 add 1 mov instructions
+ ;test_leab_ebp_leais_32: 2 operands LEA32r that can be replaced with LEA_IS form
; where the base is rbp/r13/ebp register
- define i32 @test1mov1add_ebp_32() {
+ define i32 @test_leab_ebp_leais_32() {
ret i32 0
}
- ;testleaadd_ebp_index_32: 3 operands LEA32r that can be replaced with 1 lea 1 add instructions
+ ;test_leabi_ebp_leais_32: 3 operands LEA32r that can be replaced with LEA_IS form
; where the base and the index are ebp register and there is offset
- define i32 @testleaadd_ebp_index_32() {
+ define i32 @test_leabi_ebp_leais_32() {
ret i32 0
}
...
---
-name: test1mov1add_ebp_32
+name: test_leab_ebp_leais_32
alignment: 16
exposesReturnsTwice: false
legalized: false
bb.0 (%ir-block.0):
liveins: $eax, $ebp, $ebx
- ; CHECK-LABEL: name: test1mov1add_ebp_32
+ ; CHECK-LABEL: name: test_leab_ebp_leais_32
; CHECK: liveins: $eax, $ebp, $ebx
- ; CHECK: $ebx = MOV32rr $ebp
- ; CHECK: $ebx = ADD32rr $ebx, $ebp, implicit-def $eflags
+ ; CHECK: $ebx = LEA32r $noreg, 2, $ebp, 0, $noreg
; CHECK: RET64 $ebx
$ebx = LEA32r killed $ebp, 1, $ebp, 0, $noreg
RET64 $ebx
...
---
-name: testleaadd_ebp_index_32
+name: test_leabi_ebp_leais_32
alignment: 16
exposesReturnsTwice: false
legalized: false
bb.0 (%ir-block.0):
liveins: $eax, $ebp, $ebx
- ; CHECK-LABEL: name: testleaadd_ebp_index_32
+ ; CHECK-LABEL: name: test_leabi_ebp_leais_32
; CHECK: liveins: $eax, $ebp, $ebx
- ; CHECK: $ebx = LEA32r $noreg, 1, $ebp, 5, $noreg
- ; CHECK: $ebx = ADD32rr $ebx, $ebp, implicit-def $eflags
+ ; CHECK: $ebx = LEA32r $noreg, 2, $ebp, 5, $noreg
; CHECK: RET64 $ebx
$ebx = LEA32r $ebp, 1, $ebp, 5, $noreg
RET64 $ebx
ret i32 0
}
- ;test1mov1add_rbp_64_32: 2 operands LEA64_32r cannot be replaced with 1 add 1 mov instructions
+ ;test_leab_rbp_leais_64_32: 2 operands LEA64_32r that can be replaced with LEA_IS form
; where the base is rbp/r13/ebp register
- define i32 @test1mov1add_rbp_64_32() {
+ define i32 @test_leab_rbp_leais_64_32() {
ret i32 0
}
- ;testleaadd_rbp_index_64_32: 3 operands LEA64_32r that cannot replaced with 1 lea 1 add instructions
+ ;test_leabi_rbp_leais_64_32: 3 operands LEA64_32r that can be replaced with LEA_IS form
; where the base and the index are ebp register and there is offset
- define i32 @testleaadd_rbp_index_64_32() {
+ define i32 @test_leabi_rbp_leais_64_32() {
ret i32 0
}
ret i32 0
}
- ;test1mov1add_rbp_64: 2 operands LEA64r that can be replaced with 1 add 1 mov instructions
+ ;test_leab_rbp_leais_64: 2 operands LEA64r that can be replaced with LEA_IS form
; where the base is rbp/r13/ebp register
- define i32 @test1mov1add_rbp_64() {
+ define i32 @test_leab_rbp_leais_64() {
ret i32 0
}
- ;testleaadd_rbp_index_64: 3 operands LEA64r that can be replaced with 1 lea 1 add instructions
+ ;test_leabi_rbp_leais_64: 3 operands LEA64r that can be replaced with LEA_IS form
; where the base and the index are ebp register and there is offset
- define i32 @testleaadd_rbp_index_64() {
+ define i32 @test_leabi_rbp_leais_64() {
ret i32 0
}
...
---
-name: test1mov1add_rbp_64_32
+name: test_leab_rbp_leais_64_32
alignment: 16
exposesReturnsTwice: false
legalized: false
bb.0 (%ir-block.0):
liveins: $rax, $rbp, $rbx
- ; CHECK-LABEL: name: test1mov1add_rbp_64_32
+ ; CHECK-LABEL: name: test_leab_rbp_leais_64_32
; CHECK: liveins: $rax, $rbp, $rbx
- ; CHECK: $ebx = LEA64_32r killed $rbp, 1, killed $rbp, 0, $noreg
+ ; CHECK: $ebx = LEA64_32r $noreg, 2, killed $rbp, 0, $noreg
; CHECK: RET64 $ebx
$ebx = LEA64_32r killed $rbp, 1, killed $rbp, 0, $noreg
RET64 $ebx
...
---
-name: testleaadd_rbp_index_64_32
+name: test_leabi_rbp_leais_64_32
alignment: 16
exposesReturnsTwice: false
legalized: false
bb.0 (%ir-block.0):
liveins: $rax, $rbp, $rbx
- ; CHECK-LABEL: name: testleaadd_rbp_index_64_32
+ ; CHECK-LABEL: name: test_leabi_rbp_leais_64_32
; CHECK: liveins: $rax, $rbp, $rbx
- ; CHECK: $ebx = LEA64_32r killed $rbp, 1, killed $rbp, 5, $noreg
+ ; CHECK: $ebx = LEA64_32r $noreg, 2, killed $rbp, 5, $noreg
; CHECK: RET64 $ebx
$ebx = LEA64_32r killed $rbp, 1, killed $rbp, 5, $noreg
RET64 $ebx
...
---
-name: test1mov1add_rbp_64
+name: test_leab_rbp_leais_64
alignment: 16
exposesReturnsTwice: false
legalized: false
bb.0 (%ir-block.0):
liveins: $rax, $rbp, $rbx
- ; CHECK-LABEL: name: test1mov1add_rbp_64
+ ; CHECK-LABEL: name: test_leab_rbp_leais_64
; CHECK: liveins: $rax, $rbp, $rbx
- ; CHECK: $rbx = MOV64rr $rbp
- ; CHECK: $rbx = ADD64rr $rbx, $rbp, implicit-def $eflags
+ ; CHECK: $rbx = LEA64r $noreg, 2, $rbp, 0, $noreg
; CHECK: RET64 $ebx
$rbx = LEA64r killed $rbp, 1, $rbp, 0, $noreg
RET64 $ebx
...
---
-name: testleaadd_rbp_index_64
+name: test_leabi_rbp_leais_64
alignment: 16
exposesReturnsTwice: false
legalized: false
bb.0 (%ir-block.0):
liveins: $rax, $rbp, $rbx
- ; CHECK-LABEL: name: testleaadd_rbp_index_64
+ ; CHECK-LABEL: name: test_leabi_rbp_leais_64
; CHECK: liveins: $rax, $rbp, $rbx
- ; CHECK: $rbx = LEA64r $noreg, 1, $rbp, 5, $noreg
- ; CHECK: $rbx = ADD64rr $rbx, $rbp, implicit-def $eflags
+ ; CHECK: $rbx = LEA64r $noreg, 2, $rbp, 5, $noreg
; CHECK: RET64 $ebx
$rbx = LEA64r $rbp, 1, $rbp, 5, $noreg
RET64 $ebx
; SLOWLEA3-NEXT: xorl %eax, %eax
; SLOWLEA3-NEXT: cmpl $1, %edi
; SLOWLEA3-NEXT: sete %al
-; SLOWLEA3-NEXT: addl %eax, %eax
-; SLOWLEA3-NEXT: decl %eax
+; SLOWLEA3-NEXT: leal -1(,%rax,2), %eax
; SLOWLEA3-NEXT: retq
%cmp = icmp eq i32 %x, 1
%sel = select i1 %cmp, i32 1, i32 -1
...
---
-name: test1mov1add_ebp_32
-# CHECK-LABEL: name: test1mov1add_ebp_32
+name: testleais_ebp_32
+# CHECK-LABEL: name: testleais_ebp_32
alignment: 16
tracksRegLiveness: true
debugInstrRef: true
bb.0:
liveins: $eax, $ebp, $ebx
- ; CHECK: $ebx = ADD32rr {{.*}} debug-instr-number 2
+ ; CHECK: $ebx = LEA32r $noreg, 2, $ebp, 0, $noreg, debug-instr-number 2
$ebx = LEA32r killed $ebp, 1, $ebp, 0, $noreg, debug-instr-number 1
RET64 $ebx
...
---
-name: testleaadd_ebp_index_32
-# CHECK-LABEL: name: testleaadd_ebp_index_32
+name: testleabid_ebp_leaisd_32
+# CHECK-LABEL: name: testleabid_ebp_leaisd_32
alignment: 16
tracksRegLiveness: true
debugInstrRef: true
bb.0:
liveins: $eax, $ebp, $ebx
- ; CHECK: $ebx = ADD32rr {{.*}} debug-instr-number 2
+ ; CHECK: $ebx = LEA32r $noreg, 2, $ebp, 5, $noreg, debug-instr-number 2
$ebx = LEA32r $ebp, 1, $ebp, 5, $noreg, debug-instr-number 1
RET64 $ebx