[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