[llvm] 2a6e39d - [AVR] Do not emit 'LPM Rd, Z' on devices without FeatureLPMX
Ben Shi via llvm-commits
llvm-commits at lists.llvm.org
Fri Mar 24 02:47:37 PDT 2023
Author: Ben Shi
Date: 2023-03-24T17:47:24+08:00
New Revision: 2a6e39dbf84af4b3f8b31930fed786b3c56287f5
URL: https://github.com/llvm/llvm-project/commit/2a6e39dbf84af4b3f8b31930fed786b3c56287f5
DIFF: https://github.com/llvm/llvm-project/commit/2a6e39dbf84af4b3f8b31930fed786b3c56287f5.diff
LOG: [AVR] Do not emit 'LPM Rd, Z' on devices without FeatureLPMX
The 'LPM' instruction has three forms:
------------------------
| form | feature |
| ---------- | --------|
| LPM | hasLPM |
| LPM Rd, Z | hasLPMX |
| LPM Rd, Z+ | hasLPMX |
------------------------
The second form is always selected in ISelDAGToDAG, even on devices
without FeatureLPMX. This patch emits "LPM + MOV" on devices with
only FeatureLPM.
Reviewed By: jacquesguan
Differential Revision: https://reviews.llvm.org/D141246
Added:
llvm/test/CodeGen/AVR/pseudo/LPMBRdZ.mir
Modified:
llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp
llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp
llvm/lib/Target/AVR/AVRInstrInfo.td
llvm/test/CodeGen/AVR/elpm.ll
Removed:
################################################################################
diff --git a/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp b/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp
index 06dc2b7c5b27b..b29eb87a55a01 100644
--- a/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp
+++ b/llvm/lib/Target/AVR/AVRExpandPseudoInsts.cpp
@@ -98,6 +98,8 @@ class AVRExpandPseudo : public MachineFunctionPass {
// Common implementation of LPMWRdZ and ELPMWRdZ.
bool expandLPMWELPMW(Block &MBB, BlockIt MBBI, bool IsExt);
+ // Common implementation of LPMBRdZ and ELPMBRdZ.
+ bool expandLPMBELPMB(Block &MBB, BlockIt MBBI, bool IsExt);
};
char AVRExpandPseudo::ID = 0;
@@ -858,28 +860,32 @@ bool AVRExpandPseudo::expand<AVR::ELPMWRdZ>(Block &MBB, BlockIt MBBI) {
return expandLPMWELPMW(MBB, MBBI, true);
}
-template <>
-bool AVRExpandPseudo::expand<AVR::ELPMBRdZ>(Block &MBB, BlockIt MBBI) {
+bool AVRExpandPseudo::expandLPMBELPMB(Block &MBB, BlockIt MBBI, bool IsExt) {
MachineInstr &MI = *MBBI;
Register DstReg = MI.getOperand(0).getReg();
Register SrcReg = MI.getOperand(1).getReg();
- Register BankReg = MI.getOperand(2).getReg();
bool SrcIsKill = MI.getOperand(1).isKill();
const AVRSubtarget &STI = MBB.getParent()->getSubtarget<AVRSubtarget>();
+ bool HasX = IsExt ? STI.hasELPMX() : STI.hasLPMX();
// Set the I/O register RAMPZ for ELPM (out RAMPZ, rtmp).
- buildMI(MBB, MBBI, AVR::OUTARr).addImm(STI.getIORegRAMPZ()).addReg(BankReg);
+ if (IsExt) {
+ Register BankReg = MI.getOperand(2).getReg();
+ buildMI(MBB, MBBI, AVR::OUTARr).addImm(STI.getIORegRAMPZ()).addReg(BankReg);
+ }
// Load byte.
- if (STI.hasELPMX()) {
- auto MILB = buildMI(MBB, MBBI, AVR::ELPMRdZ)
+ if (HasX) {
+ unsigned Opc = IsExt ? AVR::ELPMRdZ : AVR::LPMRdZ;
+ auto MILB = buildMI(MBB, MBBI, Opc)
.addReg(DstReg, RegState::Define)
.addReg(SrcReg, getKillRegState(SrcIsKill));
MILB.setMemRefs(MI.memoperands());
} else {
- // For the basic 'ELPM' instruction, its operand[0] is the implicit
+ // For the basic ELPM/LPM instruction, its operand[0] is the implicit
// 'Z' register, and its operand[1] is the implicit 'R0' register.
- auto MILB = buildMI(MBB, MBBI, AVR::ELPM);
+ unsigned Opc = IsExt ? AVR::ELPM : AVR::LPM;
+ auto MILB = buildMI(MBB, MBBI, Opc);
buildMI(MBB, MBBI, AVR::MOVRdRr)
.addReg(DstReg, RegState::Define)
.addReg(AVR::R0, RegState::Kill);
@@ -890,6 +896,16 @@ bool AVRExpandPseudo::expand<AVR::ELPMBRdZ>(Block &MBB, BlockIt MBBI) {
return true;
}
+template <>
+bool AVRExpandPseudo::expand<AVR::ELPMBRdZ>(Block &MBB, BlockIt MBBI) {
+ return expandLPMBELPMB(MBB, MBBI, true);
+}
+
+template <>
+bool AVRExpandPseudo::expand<AVR::LPMBRdZ>(Block &MBB, BlockIt MBBI) {
+ return expandLPMBELPMB(MBB, MBBI, false);
+}
+
template <>
bool AVRExpandPseudo::expand<AVR::LPMWRdZPi>(Block &MBB, BlockIt MBBI) {
llvm_unreachable("16-bit LPMPi is unimplemented");
@@ -2437,6 +2453,7 @@ bool AVRExpandPseudo::expandMI(Block &MBB, BlockIt MBBI) {
EXPAND(AVR::LDWRdPtrPd);
case AVR::LDDWRdYQ: //: FIXME: remove this once PR13375 gets fixed
EXPAND(AVR::LDDWRdPtrQ);
+ EXPAND(AVR::LPMBRdZ);
EXPAND(AVR::LPMWRdZ);
EXPAND(AVR::LPMWRdZPi);
EXPAND(AVR::ELPMBRdZ);
diff --git a/llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp b/llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp
index 6ea8e200bd4e9..8718997b86d07 100644
--- a/llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp
+++ b/llvm/lib/Target/AVR/AVRISelDAGToDAG.cpp
@@ -399,8 +399,9 @@ template <> bool AVRDAGToDAGISel::select<ISD::LOAD>(SDNode *N) {
switch (VT.SimpleTy) {
case MVT::i8:
if (ProgMemBank == 0) {
+ unsigned Opc = Subtarget->hasLPMX() ? AVR::LPMRdZ : AVR::LPMBRdZ;
ResNode =
- CurDAG->getMachineNode(AVR::LPMRdZ, DL, MVT::i8, MVT::Other, Ptr);
+ CurDAG->getMachineNode(Opc, DL, MVT::i8, MVT::Other, Ptr);
} else {
// Do not combine the LDI instruction into the ELPM pseudo instruction,
// since it may be reused by other ELPM pseudo instructions.
diff --git a/llvm/lib/Target/AVR/AVRInstrInfo.td b/llvm/lib/Target/AVR/AVRInstrInfo.td
index c272711bb8663..1e56f9447cb80 100644
--- a/llvm/lib/Target/AVR/AVRInstrInfo.td
+++ b/llvm/lib/Target/AVR/AVRInstrInfo.td
@@ -1690,6 +1690,11 @@ let canFoldAsLoad = 1, isReMaterializable = 1, mayLoad = 1,
: F16<0b1001010111001000, (outs), (ins), "lpm", []>,
Requires<[HasLPM]>;
+ // This pseudo is combination of LPM and MOV instructions.
+ let Defs = [R0] in
+ def LPMBRdZ : Pseudo<(outs GPR8:$dst), (ins ZREG:$z), "lpmb\t$dst, $z", []>,
+ Requires<[HasLPM]>;
+
def LPMRdZ : FLPMX<0, 0,
(outs GPR8
: $rd),
diff --git a/llvm/test/CodeGen/AVR/elpm.ll b/llvm/test/CodeGen/AVR/elpm.ll
index ba28bc814591d..2e989d1442ffd 100644
--- a/llvm/test/CodeGen/AVR/elpm.ll
+++ b/llvm/test/CodeGen/AVR/elpm.ll
@@ -152,6 +152,24 @@ define signext i8 @foob0(i16 %a, i16 %b) {
; CHECK-NEXT: lsl r25
; CHECK-NEXT: sbc r25, r25
; CHECK-NEXT: ret
+;
+; NOX-LABEL: foob0:
+; NOX: ; %bb.0: ; %entry
+; NOX-NEXT: subi r22, lo8(-(arrb1))
+; NOX-NEXT: sbci r23, hi8(-(arrb1))
+; NOX-NEXT: movw r30, r22
+; NOX-NEXT: lpm
+; NOX-NEXT: mov r18, r0
+; NOX-NEXT: subi r24, lo8(-(arrb1))
+; NOX-NEXT: sbci r25, hi8(-(arrb1))
+; NOX-NEXT: movw r30, r24
+; NOX-NEXT: lpm
+; NOX-NEXT: mov r24, r0
+; NOX-NEXT: sub r24, r18
+; NOX-NEXT: mov r25, r24
+; NOX-NEXT: lsl r25
+; NOX-NEXT: sbc r25, r25
+; NOX-NEXT: ret
entry:
%arrayidx = getelementptr inbounds [4 x i8], [4 x i8] addrspace(1)* @arrb1, i16 0, i16 %a
%0 = load i8, i8 addrspace(1)* %arrayidx, align 1
@@ -179,6 +197,26 @@ define signext i8 @foob1(i16 %a, i16 %b) {
; CHECK-NEXT: lsl r25
; CHECK-NEXT: sbc r25, r25
; CHECK-NEXT: ret
+;
+; NOX-LABEL: foob1:
+; NOX: ; %bb.0: ; %entry
+; NOX-NEXT: subi r22, lo8(-(arrb3))
+; NOX-NEXT: sbci r23, hi8(-(arrb3))
+; NOX-NEXT: movw r30, r22
+; NOX-NEXT: ldi r18, 2
+; NOX-NEXT: out 59, r18
+; NOX-NEXT: elpm
+; NOX-NEXT: mov r18, r0
+; NOX-NEXT: subi r24, lo8(-(arrb1))
+; NOX-NEXT: sbci r25, hi8(-(arrb1))
+; NOX-NEXT: movw r30, r24
+; NOX-NEXT: lpm
+; NOX-NEXT: mov r24, r0
+; NOX-NEXT: sub r24, r18
+; NOX-NEXT: mov r25, r24
+; NOX-NEXT: lsl r25
+; NOX-NEXT: sbc r25, r25
+; NOX-NEXT: ret
entry:
%arrayidx = getelementptr inbounds [4 x i8], [4 x i8] addrspace(1)* @arrb1, i16 0, i16 %a
%0 = load i8, i8 addrspace(1)* %arrayidx, align 1
@@ -206,6 +244,26 @@ define signext i8 @foob2(i16 %a, i16 %b) {
; CHECK-NEXT: lsl r25
; CHECK-NEXT: sbc r25, r25
; CHECK-NEXT: ret
+;
+; NOX-LABEL: foob2:
+; NOX: ; %bb.0: ; %entry
+; NOX-NEXT: subi r24, lo8(-(arrb5))
+; NOX-NEXT: sbci r25, hi8(-(arrb5))
+; NOX-NEXT: movw r30, r24
+; NOX-NEXT: ldi r24, 4
+; NOX-NEXT: out 59, r24
+; NOX-NEXT: elpm
+; NOX-NEXT: mov r24, r0
+; NOX-NEXT: subi r22, lo8(-(arrb1))
+; NOX-NEXT: sbci r23, hi8(-(arrb1))
+; NOX-NEXT: movw r30, r22
+; NOX-NEXT: lpm
+; NOX-NEXT: mov r25, r0
+; NOX-NEXT: sub r24, r25
+; NOX-NEXT: mov r25, r24
+; NOX-NEXT: lsl r25
+; NOX-NEXT: sbc r25, r25
+; NOX-NEXT: ret
entry:
%arrayidx = getelementptr inbounds [4 x i8], [4 x i8] addrspace(5)* @arrb5, i16 0, i16 %a
%0 = load i8, i8 addrspace(5)* %arrayidx, align 1
diff --git a/llvm/test/CodeGen/AVR/pseudo/LPMBRdZ.mir b/llvm/test/CodeGen/AVR/pseudo/LPMBRdZ.mir
new file mode 100644
index 0000000000000..6eaa9435220ea
--- /dev/null
+++ b/llvm/test/CodeGen/AVR/pseudo/LPMBRdZ.mir
@@ -0,0 +1,40 @@
+# RUN: llc -mtriple=avr -mattr=+lpm -mattr=+lpmx -start-before=greedy %s -o - \
+# RUN: | FileCheck %s
+# RUN: llc -mtriple=avr -mattr=+lpm -mattr=-lpmx -start-before=greedy %s -o - \
+# RUN: | FileCheck --check-prefix=NOX %s
+
+# This test checks the expansion of the 8-bit LPMBRdZ pseudo instruction and that
+# the register allocator won't use R31R30 as an output register (which would
+# lead to undefined behavior).
+
+--- |
+ target triple = "avr--"
+ define void @test_lpmbrdz() {
+ entry:
+ ret void
+ }
+...
+
+---
+name: test_lpmbrdz
+tracksRegLiveness: true
+body: |
+ bb.0.entry:
+ liveins: $r31r30
+
+ ; CHECK-LABEL: test_lpmbrdz:
+ ; CHECK: ; %bb.0:
+ ; CHECK-NEXT: lpm r30, Z
+ ; CHECK-NEXT: ret
+
+ ; NOX-LABEL: test_lpmbrdz
+ ; NOX: ; %bb.0:
+ ; NOX-NEXT: lpm
+ ; NOX-NEXT: mov r30, r0
+ ; NOX-NEXT: ret
+
+ %1:zreg = COPY killed $r31r30
+ %2:gpr8 = LPMBRdZ %1, implicit-def dead $r0
+ $r30 = COPY %2
+ RET implicit $r30
+...
More information about the llvm-commits
mailing list