diff --git a/llvm/lib/Target/AVR/AVRFrameLowering.cpp b/llvm/lib/Target/AVR/AVRFrameLowering.cpp --- a/llvm/lib/Target/AVR/AVRFrameLowering.cpp +++ b/llvm/lib/Target/AVR/AVRFrameLowering.cpp @@ -260,6 +260,16 @@ Register Reg = I.getReg(); bool IsNotLiveIn = !MBB.isLiveIn(Reg); + // Check if Reg is a sub register of a 16-bit livein register, and then + // add it to the livein list. + if (IsNotLiveIn) + for (const auto &LiveIn : MBB.liveins()) + if (STI.getRegisterInfo()->isSubRegister(LiveIn.PhysReg, Reg)) { + IsNotLiveIn = false; + MBB.addLiveIn(Reg); + break; + } + assert(TRI->getRegSizeInBits(*TRI->getMinimalPhysRegClass(Reg)) == 8 && "Invalid register size"); diff --git a/llvm/test/CodeGen/AVR/bug-56423.ll b/llvm/test/CodeGen/AVR/bug-56423.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AVR/bug-56423.ll @@ -0,0 +1,135 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=avr -mcpu=atmega328 | FileCheck %s --check-prefix=AVR51 +; RUN: llc < %s -mtriple=avr -mcpu=at90s8515 | FileCheck %s --check-prefix=AVR2 + +; Test for bug https://github.com/llvm/llvm-project/issues/56423 + +define i32 @foo(i32 %x, i32 %in_min, i32 %in_max, i32 %out_min, i32 %out_max) { +; AVR51-LABEL: foo: +; AVR51: ; %bb.0: ; %entry +; AVR51-NEXT: push r6 +; AVR51-NEXT: push r7 +; AVR51-NEXT: push r8 +; AVR51-NEXT: push r9 +; AVR51-NEXT: push r14 +; AVR51-NEXT: push r15 +; AVR51-NEXT: push r16 +; AVR51-NEXT: push r17 +; AVR51-NEXT: push r28 +; AVR51-NEXT: push r29 +; AVR51-NEXT: in r28, 61 +; AVR51-NEXT: in r29, 62 +; AVR51-NEXT: movw r8, r20 +; AVR51-NEXT: movw r6, r18 +; AVR51-NEXT: movw r20, r24 +; AVR51-NEXT: movw r18, r22 +; AVR51-NEXT: ldd r22, Y+13 +; AVR51-NEXT: ldd r23, Y+14 +; AVR51-NEXT: ldd r24, Y+15 +; AVR51-NEXT: ldd r25, Y+16 +; AVR51-NEXT: sub r22, r10 +; AVR51-NEXT: sbc r23, r11 +; AVR51-NEXT: sbc r24, r12 +; AVR51-NEXT: sbc r25, r13 +; AVR51-NEXT: sub r18, r6 +; AVR51-NEXT: sbc r19, r7 +; AVR51-NEXT: sbc r20, r8 +; AVR51-NEXT: sbc r21, r9 +; AVR51-NEXT: call __mulsi3 +; AVR51-NEXT: sub r14, r6 +; AVR51-NEXT: sbc r15, r7 +; AVR51-NEXT: sbc r16, r8 +; AVR51-NEXT: sbc r17, r9 +; AVR51-NEXT: movw r18, r14 +; AVR51-NEXT: movw r20, r16 +; AVR51-NEXT: call __divmodsi4 +; AVR51-NEXT: add r18, r10 +; AVR51-NEXT: adc r19, r11 +; AVR51-NEXT: adc r20, r12 +; AVR51-NEXT: adc r21, r13 +; AVR51-NEXT: movw r22, r18 +; AVR51-NEXT: movw r24, r20 +; AVR51-NEXT: pop r29 +; AVR51-NEXT: pop r28 +; AVR51-NEXT: pop r17 +; AVR51-NEXT: pop r16 +; AVR51-NEXT: pop r15 +; AVR51-NEXT: pop r14 +; AVR51-NEXT: pop r9 +; AVR51-NEXT: pop r8 +; AVR51-NEXT: pop r7 +; AVR51-NEXT: pop r6 +; AVR51-NEXT: ret +; +; AVR2-LABEL: foo: +; AVR2: ; %bb.0: ; %entry +; AVR2-NEXT: push r6 +; AVR2-NEXT: push r7 +; AVR2-NEXT: push r8 +; AVR2-NEXT: push r9 +; AVR2-NEXT: push r14 +; AVR2-NEXT: push r15 +; AVR2-NEXT: push r16 +; AVR2-NEXT: push r17 +; AVR2-NEXT: push r28 +; AVR2-NEXT: push r29 +; AVR2-NEXT: in r28, 61 +; AVR2-NEXT: in r29, 62 +; AVR2-NEXT: mov r8, r20 +; AVR2-NEXT: mov r9, r21 +; AVR2-NEXT: mov r6, r18 +; AVR2-NEXT: mov r7, r19 +; AVR2-NEXT: mov r20, r24 +; AVR2-NEXT: mov r21, r25 +; AVR2-NEXT: mov r18, r22 +; AVR2-NEXT: mov r19, r23 +; AVR2-NEXT: ldd r22, Y+13 +; AVR2-NEXT: ldd r23, Y+14 +; AVR2-NEXT: ldd r24, Y+15 +; AVR2-NEXT: ldd r25, Y+16 +; AVR2-NEXT: sub r22, r10 +; AVR2-NEXT: sbc r23, r11 +; AVR2-NEXT: sbc r24, r12 +; AVR2-NEXT: sbc r25, r13 +; AVR2-NEXT: sub r18, r6 +; AVR2-NEXT: sbc r19, r7 +; AVR2-NEXT: sbc r20, r8 +; AVR2-NEXT: sbc r21, r9 +; AVR2-NEXT: rcall __mulsi3 +; AVR2-NEXT: sub r14, r6 +; AVR2-NEXT: sbc r15, r7 +; AVR2-NEXT: sbc r16, r8 +; AVR2-NEXT: sbc r17, r9 +; AVR2-NEXT: mov r18, r14 +; AVR2-NEXT: mov r19, r15 +; AVR2-NEXT: mov r20, r16 +; AVR2-NEXT: mov r21, r17 +; AVR2-NEXT: rcall __divmodsi4 +; AVR2-NEXT: add r18, r10 +; AVR2-NEXT: adc r19, r11 +; AVR2-NEXT: adc r20, r12 +; AVR2-NEXT: adc r21, r13 +; AVR2-NEXT: mov r22, r18 +; AVR2-NEXT: mov r23, r19 +; AVR2-NEXT: mov r24, r20 +; AVR2-NEXT: mov r25, r21 +; AVR2-NEXT: pop r29 +; AVR2-NEXT: pop r28 +; AVR2-NEXT: pop r17 +; AVR2-NEXT: pop r16 +; AVR2-NEXT: pop r15 +; AVR2-NEXT: pop r14 +; AVR2-NEXT: pop r9 +; AVR2-NEXT: pop r8 +; AVR2-NEXT: pop r7 +; AVR2-NEXT: pop r6 +; AVR2-NEXT: ret +entry: + %sub = sub nsw i32 %x, %in_min + %sub1 = sub nsw i32 %out_max, %out_min + %mul = mul nsw i32 %sub1, %sub + %sub2 = sub nsw i32 %in_max, %in_min + %div = sdiv i32 %mul, %sub2 + %add = add nsw i32 %div, %out_min + ret i32 %add +}