[llvm] 1e9fa0b - Fix the side effect of outlined function when the register is implicit use and implicit-def in the same instruction.
Jin Lin via llvm-commits
llvm-commits at lists.llvm.org
Wed Nov 17 09:44:18 PST 2021
Author: DianQK
Date: 2021-11-17T09:44:10-08:00
New Revision: 1e9fa0b12a7619add4a259f80315f984b5f7e2ce
URL: https://github.com/llvm/llvm-project/commit/1e9fa0b12a7619add4a259f80315f984b5f7e2ce
DIFF: https://github.com/llvm/llvm-project/commit/1e9fa0b12a7619add4a259f80315f984b5f7e2ce.diff
LOG: Fix the side effect of outlined function when the register is implicit use and implicit-def in the same instruction.
This is the diff associated with {D95267}, and we need to mark $x0 as live whether or not $x0 is dead.
The compiler also needs to mark register $x0 as live in for the following case.
```
$x1 = ADDXri $sp, 16, 0
BL @spam, csr_darwin_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit $x0, implicit killed $x1, implicit-def $sp, implicit-def $x0
```
This change fixes an issue where the wrong registers were used when -machine-outliner-reruns>0.
As an example:
```
lang=c
typedef struct {
double v1;
double v2;
} D16;
typedef struct {
D16 v1;
D16 v2;
} D32;
typedef long long LL8;
typedef struct {
long long v1;
long long v2;
} LL16;
typedef struct {
LL16 v1;
LL16 v2;
} LL32;
typedef struct {
LL32 v1;
LL32 v2;
} LL64;
LL8 needx0(LL8 v0, LL8 v1);
void bar(LL64 v1, LL32 v2, LL16 v3, LL32 v4, LL8 v5, D16 v6, D16 v7, D16 v8);
LL8 foo(LL8 v0, LL64 v1, LL32 v2, LL16 v3, LL32 v4, LL8 v5, D16 v6, D16 v7, D16 v8)
{
LL8 result = needx0(v0, 0);
bar(v1, v2, v3, v4, v5, v6, v7, v8);
return result + 1;
}
```
As you can see from the `foo` function, we should not modify the value of `x0` until we call `needx0`.
This code is compiled to give the following instruction MIR code.
```
$sp = frame-setup SUBXri $sp, 256, 0
frame-setup STPDi killed $d13, killed $d12, $sp, 16
frame-setup STPDi killed $d11, killed $d10, $sp, 18
frame-setup STPDi killed $d9, killed $d8, $sp, 20
frame-setup STPXi killed $x26, killed $x25, $sp, 22
frame-setup STPXi killed $x24, killed $x23, $sp, 24
frame-setup STPXi killed $x22, killed $x21, $sp, 26
frame-setup STPXi killed $x20, killed $x19, $sp, 28
...
$x1 = MOVZXi 0, 0
BL @needx0, csr_darwin_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit $x0, implicit $x1, implicit-def $sp, implicit-def $x0
...
```
Since there are some other instruction sequences that duplicate `foo`, after the first execution of Machine Outliner you will get:
```
$sp = frame-setup SUBXri $sp, 256, 0
frame-setup STPDi killed $d13, killed $d12, $sp, 16
frame-setup STPDi killed $d11, killed $d10, $sp, 18
frame-setup STPDi killed $d9, killed $d8, $sp, 20
$x7 = ORRXrs $xzr, $lr, 0
BL @OUTLINED_FUNCTION_0, implicit-def $lr, implicit $sp, implicit-def $lr, implicit $sp, implicit $xzr, implicit $x7, implicit $x19, implicit $x20, implicit $x21, implicit $x22, implicit $x23, implicit $x24, implicit $x25, implicit $x26
$lr = ORRXrs $xzr, $x7, 0
...
BL @OUTLINED_FUNCTION_1, implicit-def $lr, implicit $sp, implicit-def $lr, implicit-def $sp, implicit-def $x0, implicit-def $x1, implicit $sp
...
```
For the first time we outlined the following sequence:
```
frame-setup STPXi killed $x26, killed $x25, $sp, 22
frame-setup STPXi killed $x24, killed $x23, $sp, 24
frame-setup STPXi killed $x22, killed $x21, $sp, 26
frame-setup STPXi killed $x20, killed $x19, $sp, 28
```
and
```
$x1 = MOVZXi 0, 0
BL @needx0, csr_darwin_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit $x0, implicit $x1, implicit-def $sp, implicit-def $x0
```
When we execute the outline again, we will get:
```
$x0 = ORRXrs $xzr, $lr, 0 <---- here
BL @OUTLINED_FUNCTION_2_0, implicit-def $lr, implicit $sp, implicit-def $sp, implicit-def $lr, implicit $sp, implicit $xzr, implicit $d8, implicit $d9, implicit $d10, implicit $d11, implicit $d12, implicit $d13, implicit $x0
$lr = ORRXrs $xzr, $x0, 0
$x7 = ORRXrs $xzr, $lr, 0
BL @OUTLINED_FUNCTION_0, implicit-def $lr, implicit $sp, implicit-def $lr, implicit $sp, implicit $xzr, implicit $x7, implicit $x19, implicit $x20, implicit $x21, implicit $x22, implicit $x23, implicit $x24, implicit $x25, implicit $x26
$lr = ORRXrs $xzr, $x7, 0
...
BL @OUTLINED_FUNCTION_1, implicit-def $lr, implicit $sp, implicit-def $lr, implicit-def $sp, implicit-def $x0, implicit-def $x1, implicit $sp
```
When calling `OUTLINED_FUNCTION_2_0`, we used `x0` to save the `lr` register.
The reason for the above error appears to be that:
```
BL @OUTLINED_FUNCTION_1, implicit-def $lr, implicit $sp, implicit-def $lr, implicit-def $sp, implicit-def $x0, implicit-def $x1, implicit $sp
```
should be:
```
BL @OUTLINED_FUNCTION_1, implicit-def $lr, implicit $sp, implicit-def $lr, implicit-def $sp, implicit-def $x0, implicit-def $x1, implicit $sp, implicit $x0
```
When processing the same instruction with both `implicit-def $x0` and `implicit $x0` we should keep `implicit $x0`.
A reproducible demo is available at: [https://github.com/DianQK/reproduce_outlined_function_use_live_x0](https://github.com/DianQK/reproduce_outlined_function_use_live_x0).
Reviewed By: jinlin
Differential Revision: https://reviews.llvm.org/D112911
Added:
Modified:
llvm/lib/CodeGen/MachineOutliner.cpp
llvm/test/CodeGen/AArch64/machine-outliner-side-effect-2.mir
llvm/test/CodeGen/AArch64/machine-outliner-side-effect.mir
Removed:
################################################################################
diff --git a/llvm/lib/CodeGen/MachineOutliner.cpp b/llvm/lib/CodeGen/MachineOutliner.cpp
index 1d55bd00e0337..cfbccebaff3ec 100644
--- a/llvm/lib/CodeGen/MachineOutliner.cpp
+++ b/llvm/lib/CodeGen/MachineOutliner.cpp
@@ -798,6 +798,7 @@ bool MachineOutliner::outline(Module &M,
Last = std::next(CallInst.getReverse());
Iter != Last; Iter++) {
MachineInstr *MI = &*Iter;
+ SmallSet<Register, 2> InstrUseRegs;
for (MachineOperand &MOP : MI->operands()) {
// Skip over anything that isn't a register.
if (!MOP.isReg())
@@ -806,7 +807,8 @@ bool MachineOutliner::outline(Module &M,
if (MOP.isDef()) {
// Introduce DefRegs set to skip the redundant register.
DefRegs.insert(MOP.getReg());
- if (!MOP.isDead() && UseRegs.count(MOP.getReg()))
+ if (UseRegs.count(MOP.getReg()) &&
+ !InstrUseRegs.count(MOP.getReg()))
// Since the regiester is modeled as defined,
// it is not necessary to be put in use register set.
UseRegs.erase(MOP.getReg());
@@ -814,6 +816,7 @@ bool MachineOutliner::outline(Module &M,
// Any register which is not undefined should
// be put in the use register set.
UseRegs.insert(MOP.getReg());
+ InstrUseRegs.insert(MOP.getReg());
}
}
if (MI->isCandidateForCallSiteEntry())
diff --git a/llvm/test/CodeGen/AArch64/machine-outliner-side-effect-2.mir b/llvm/test/CodeGen/AArch64/machine-outliner-side-effect-2.mir
index d95565b663a8f..b2d4a16217f33 100644
--- a/llvm/test/CodeGen/AArch64/machine-outliner-side-effect-2.mir
+++ b/llvm/test/CodeGen/AArch64/machine-outliner-side-effect-2.mir
@@ -1,6 +1,7 @@
# RUN: llc -mtriple=aarch64 -run-pass=machine-outliner -verify-machineinstrs %s -o - | FileCheck %s
-# The test checks whether the compiler updates the side effect of function @OUTLINED_FUNCTION_0 by adding the use of register x0.
+# The test checks whether the compiler updates the side effect of function @OUTLINED_FUNCTION_0
+# when implict-def and implict use of $x0 in the same instruction.
--- |
declare void @spam() local_unnamed_addr
@@ -16,7 +17,8 @@ body: |
liveins: $x0, $lr
$x1 = ADDXri $sp, 16, 0
- BL @spam, csr_darwin_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit $x0, implicit killed $x1, implicit-def $sp, implicit-def dead $x0
+ BL @spam, csr_darwin_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit $x0, implicit killed $x1, implicit-def $sp, implicit-def $x0
+ renamable $x1 = COPY $x0
RET_ReallyLR
@@ -29,7 +31,8 @@ body: |
liveins: $x0, $lr
$x1 = ADDXri $sp, 16, 0
- BL @spam, csr_darwin_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit $x0, implicit killed $x1, implicit-def $sp, implicit-def dead $x0
+ BL @spam, csr_darwin_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit $x0, implicit killed $x1, implicit-def $sp, implicit-def $x0
+ renamable $x2 = COPY $x0
RET_ReallyLR
@@ -42,10 +45,11 @@ body: |
liveins: $x0, $lr
$x1 = ADDXri $sp, 16, 0
- BL @spam, csr_darwin_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit $x0, implicit killed $x1, implicit-def $sp, implicit-def dead $x0
+ BL @spam, csr_darwin_aarch64_aapcs, implicit-def dead $lr, implicit $sp, implicit $x0, implicit killed $x1, implicit-def $sp, implicit-def $x0
+ renamable $x3 = COPY $x0
RET_ReallyLR
...
-# CHECK: BL @OUTLINED_FUNCTION_0, {{.*}}, implicit $x0
+# CHECK: BL @OUTLINED_FUNCTION_0, {{.*}}, implicit $x0{{.*}}
diff --git a/llvm/test/CodeGen/AArch64/machine-outliner-side-effect.mir b/llvm/test/CodeGen/AArch64/machine-outliner-side-effect.mir
index 40c54679dfae0..2c22257156f51 100644
--- a/llvm/test/CodeGen/AArch64/machine-outliner-side-effect.mir
+++ b/llvm/test/CodeGen/AArch64/machine-outliner-side-effect.mir
@@ -29,4 +29,4 @@ body: |
...
-# CHECK: BL @OUTLINED_FUNCTION_0, {{.*}}, implicit $x20, {{.*}}
+# CHECK: BL @OUTLINED_FUNCTION_0, {{.*}}, implicit $x20{{.*}}
More information about the llvm-commits
mailing list