[llvm] 5650688 - [AVR] Fix expanding MOVW for overlapping registers
Ben Shi via llvm-commits
llvm-commits at lists.llvm.org
Sun Jun 26 02:32:50 PDT 2022
Author: Patryk Wychowaniec
Date: 2022-06-26T17:20:07+08:00
New Revision: 5650688e7242b31b1447189176493aa12c99f355
URL: https://github.com/llvm/llvm-project/commit/5650688e7242b31b1447189176493aa12c99f355
DIFF: https://github.com/llvm/llvm-project/commit/5650688e7242b31b1447189176493aa12c99f355.diff
LOG: [AVR] Fix expanding MOVW for overlapping registers
When expanding a MOVW (16-bit copy) to two MOVs (8-bit copy), the
lower byte always comes first. This is incorrect for corner cases like
'$r24r23 -> $r25r24', in which the higher byte copy should come first.
Current patch fixes that bug as recorded at
https://github.com/rust-lang/rust/issues/98167
Reviewed By: benshi001
Differential Revision: https://reviews.llvm.org/D128588
Added:
llvm/test/CodeGen/AVR/pseudo/COPY.mir
llvm/test/CodeGen/AVR/rust-bug-98167.ll
Modified:
llvm/lib/Target/AVR/AVRInstrInfo.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Target/AVR/AVRInstrInfo.cpp b/llvm/lib/Target/AVR/AVRInstrInfo.cpp
index 136acb468fbc8..510000f231faa 100644
--- a/llvm/lib/Target/AVR/AVRInstrInfo.cpp
+++ b/llvm/lib/Target/AVR/AVRInstrInfo.cpp
@@ -46,8 +46,9 @@ void AVRInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
const AVRRegisterInfo &TRI = *STI.getRegisterInfo();
unsigned Opc;
- // Not all AVR devices support the 16-bit `MOVW` instruction.
if (AVR::DREGSRegClass.contains(DestReg, SrcReg)) {
+ // If our AVR has `movw`, let's emit that; otherwise let's emit two separate
+ // `mov`s.
if (STI.hasMOVW() && AVR::DREGSMOVWRegClass.contains(DestReg, SrcReg)) {
BuildMI(MBB, MI, DL, get(AVR::MOVWRdRr), DestReg)
.addReg(SrcReg, getKillRegState(KillSrc));
@@ -57,11 +58,17 @@ void AVRInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
TRI.splitReg(DestReg, DestLo, DestHi);
TRI.splitReg(SrcReg, SrcLo, SrcHi);
- // Copy each individual register with the `MOV` instruction.
- BuildMI(MBB, MI, DL, get(AVR::MOVRdRr), DestLo)
- .addReg(SrcLo, getKillRegState(KillSrc));
- BuildMI(MBB, MI, DL, get(AVR::MOVRdRr), DestHi)
- .addReg(SrcHi, getKillRegState(KillSrc));
+ if (DestLo == SrcHi) {
+ BuildMI(MBB, MI, DL, get(AVR::MOVRdRr), DestHi)
+ .addReg(SrcHi, getKillRegState(KillSrc));
+ BuildMI(MBB, MI, DL, get(AVR::MOVRdRr), DestLo)
+ .addReg(SrcLo, getKillRegState(KillSrc));
+ } else {
+ BuildMI(MBB, MI, DL, get(AVR::MOVRdRr), DestLo)
+ .addReg(SrcLo, getKillRegState(KillSrc));
+ BuildMI(MBB, MI, DL, get(AVR::MOVRdRr), DestHi)
+ .addReg(SrcHi, getKillRegState(KillSrc));
+ }
}
} else {
if (AVR::GPR8RegClass.contains(DestReg, SrcReg)) {
diff --git a/llvm/test/CodeGen/AVR/pseudo/COPY.mir b/llvm/test/CodeGen/AVR/pseudo/COPY.mir
new file mode 100644
index 0000000000000..1cd3383425f88
--- /dev/null
+++ b/llvm/test/CodeGen/AVR/pseudo/COPY.mir
@@ -0,0 +1,47 @@
+# RUN: llc -O0 %s -o - | FileCheck %s
+
+--- |
+ target triple = "avr--"
+
+ define void @test_copy_nonoverlapping() {
+ entry:
+ ret void
+ }
+
+ define void @test_copy_overlapping() {
+ entry:
+ ret void
+ }
+
+ declare void @foo(i16 %0)
+...
+
+---
+name: test_copy_nonoverlapping
+tracksRegLiveness: true
+body: |
+ bb.0.entry:
+ liveins: $r25r24
+
+ ; CHECK-LABEL: test_copy_nonoverlapping:
+ ; CHECK: mov r22, r24
+ ; CHECK-NEXT: mov r23, r25
+
+ $r23r22 = COPY $r25r24
+ RCALLk @foo, implicit $r24r23
+...
+
+---
+name: test_copy_overlapping
+tracksRegLiveness: true
+body: |
+ bb.0.entry:
+ liveins: $r24r23
+
+ ; CHECK-LABEL: test_copy_overlapping:
+ ; CHECK: mov r25, r24
+ ; CHECK-NEXT: mov r24, r23
+
+ $r25r24 = COPY $r24r23
+ RCALLk @foo, implicit $r25r24
+...
diff --git a/llvm/test/CodeGen/AVR/rust-bug-98167.ll b/llvm/test/CodeGen/AVR/rust-bug-98167.ll
new file mode 100644
index 0000000000000..134623e838ae7
--- /dev/null
+++ b/llvm/test/CodeGen/AVR/rust-bug-98167.ll
@@ -0,0 +1,22 @@
+; RUN: llc < %s -march=avr | FileCheck %s
+
+; The bug can be found here:
+; https://github.com/rust-lang/rust/issues/98167
+;
+; In this test, `extractvalue` + `call` generate a copy with overlapping
+; registers (`$r25r24 = COPY $r24r23`) that used to be expanded incorrectly.
+
+define void @main() {
+; CHECK-LABEL: main:
+; CHECK: rcall foo
+; CHECK-NEXT: mov r25, r24
+; CHECK-NEXT: mov r24, r23
+; CHECK-NEXT: rcall bar
+ %1 = call { i8, i16 } @foo()
+ %2 = extractvalue { i8, i16 } %1, 1
+ call void @bar(i16 %2)
+ ret void
+}
+
+declare { i8, i16 } @foo()
+declare void @bar(i16 %0)
More information about the llvm-commits
mailing list