diff --git a/lib/Target/AVR/AVRInstrInfo.td b/lib/Target/AVR/AVRInstrInfo.td index ec4b6c9a777..5720af7d8df 100644 --- a/lib/Target/AVR/AVRInstrInfo.td +++ b/lib/Target/AVR/AVRInstrInfo.td @@ -1222,7 +1222,7 @@ isReMaterializable = 1 in // ldd Rd, P+q // ldd Rd+1, P+q+1 let Constraints = "@earlyclobber $dst" in - def LDDWRdPtrQ : Pseudo<(outs DREGS:$dst), + def LDDWRdPtrQ : Pseudo<(outs DREGS_WITHOUT_Z_WORKAROUND:$dst), (ins memri:$memri), "lddw\t$dst, $memri", [(set i16:$dst, (load addr:$memri))]>, diff --git a/lib/Target/AVR/AVRRegisterInfo.td b/lib/Target/AVR/AVRRegisterInfo.td index 8162f12052b..d55252bcac4 100644 --- a/lib/Target/AVR/AVRRegisterInfo.td +++ b/lib/Target/AVR/AVRRegisterInfo.td @@ -157,6 +157,26 @@ def DREGS : RegisterClass<"AVR", [i16], 8, R9R8, R7R6, R5R4, R3R2, R1R0 )>; +// The 16-bit DREGS register class, excluding the Z pointer register. +// +// This is used by instructions which cause high pointer register +// contention which leads to an assertion in the register allocator. +// +// There is no technical reason why instructions that use this class +// cannot use Z; it's simply a workaround a regalloc bug. +// +// More information can be found in PR39553. +def DREGS_WITHOUT_Z_WORKAROUND : RegisterClass<"AVR", [i16], 8, + ( + // Return value and arguments. + add R25R24, R19R18, R21R20, R23R22, + // Scratch registers. + R27R26, + // Callee saved registers. + R29R28, R17R16, R15R14, R13R12, R11R10, + R9R8, R7R6, R5R4, R3R2, R1R0 + )>; + // 16-bit register class for immediate instructions. def DLDREGS : RegisterClass<"AVR", [i16], 8, ( diff --git a/test/CodeGen/AVR/pseudo/LDDWRdPtrQ-same-src-dst.mir b/test/CodeGen/AVR/pseudo/LDDWRdPtrQ-same-src-dst.mir index df69f5fffa5..72b20d39d68 100644 --- a/test/CodeGen/AVR/pseudo/LDDWRdPtrQ-same-src-dst.mir +++ b/test/CodeGen/AVR/pseudo/LDDWRdPtrQ-same-src-dst.mir @@ -25,11 +25,11 @@ body: | ; CHECK-LABEL: test_lddwrdptrq - ; CHECK: ldd [[SCRATCH:r[0-9]+]], Z+10 + ; CHECK: ldd [[SCRATCH:r[0-9]+]], Y+10 ; CHECK-NEXT: push [[SCRATCH]] - ; CHECK-NEXT: ldd [[SCRATCH]], Z+11 - ; CHECK-NEXT: mov r31, [[SCRATCH]] - ; CHECK-NEXT: pop r30 + ; CHECK-NEXT: ldd [[SCRATCH]], Y+11 + ; CHECK-NEXT: mov r29, [[SCRATCH]] + ; CHECK-NEXT: pop r28 - early-clobber $r31r30 = LDDWRdPtrQ undef $r31r30, 10 + early-clobber $r29r28 = LDDWRdPtrQ undef $r29r28, 10 ... diff --git a/test/CodeGen/AVR/pseudo/LDDWRdPtrQ.mir b/test/CodeGen/AVR/pseudo/LDDWRdPtrQ.mir index 59b3ce8b602..96d3809ed2d 100644 --- a/test/CodeGen/AVR/pseudo/LDDWRdPtrQ.mir +++ b/test/CodeGen/AVR/pseudo/LDDWRdPtrQ.mir @@ -18,8 +18,8 @@ body: | ; CHECK-LABEL: test_lddwrdptrq - ; CHECK: ldd r30, Y+10 - ; CHECK-NEXT: ldd r31, Y+11 + ; CHECK: ldd r28, Z+10 + ; CHECK-NEXT: ldd r29, Z+11 - early-clobber $r31r30 = LDDWRdPtrQ undef $r29r28, 10 + early-clobber $r29r28 = LDDWRdPtrQ undef $r31r30, 10 ... diff --git a/test/CodeGen/AVR/rust-avr-bug-37.ll b/test/CodeGen/AVR/rust-avr-bug-37.ll new file mode 100644 index 00000000000..9c269d3dab1 --- /dev/null +++ b/test/CodeGen/AVR/rust-avr-bug-37.ll @@ -0,0 +1,25 @@ +; RUN: llc < %s -march=avr | FileCheck %s + +%"fmt::Formatter" = type { i32, { i8*, void (i8*)** } } + +@str.1b = external constant [0 x i8] + +define void @"TryFromIntError::Debug"(%"fmt::Formatter"* dereferenceable(32)) unnamed_addr #0 personality i32 (...)* @rust_eh_personality { +; CHECK-LABEL: "TryFromIntError::Debug" +start: + %builder = alloca i8, align 8 + %1 = getelementptr inbounds %"fmt::Formatter", %"fmt::Formatter"* %0, i16 0, i32 1 + %2 = bitcast { i8*, void (i8*)** }* %1 to {}** + %3 = load {}*, {}** %2, align 2 + %4 = getelementptr inbounds %"fmt::Formatter", %"fmt::Formatter"* %0, i16 0, i32 1, i32 1 + %5 = load void (i8*)**, void (i8*)*** %4, align 2 + %6 = getelementptr inbounds void (i8*)*, void (i8*)** %5, i16 3 + %7 = bitcast void (i8*)** %6 to i8 ({}*, i8*, i16)** + %8 = load i8 ({}*, i8*, i16)*, i8 ({}*, i8*, i16)** %7, align 2 + %9 = tail call i8 %8({}* nonnull %3, i8* noalias nonnull readonly getelementptr inbounds ([0 x i8], [0 x i8]* @str.1b, i16 0, i16 0), i16 15) + unreachable +} + +declare i32 @rust_eh_personality(...) unnamed_addr + +attributes #0 = { uwtable } \ No newline at end of file diff --git a/test/CodeGen/AVR/rust-avr-bug-95.ll b/test/CodeGen/AVR/rust-avr-bug-95.ll new file mode 100644 index 00000000000..9534ceb26e7 --- /dev/null +++ b/test/CodeGen/AVR/rust-avr-bug-95.ll @@ -0,0 +1,37 @@ +; RUN: llc < %s -march=avr | FileCheck %s + +%"fmt::Formatter.1.77.153.229.305.381.1673" = type { [0 x i8], i32, [0 x i8], i32, [0 x i8], i8, [0 x i8], %"option::Option.0.76.152.228.304.380.1672", [0 x i8], %"option::Option.0.76.152.228.304.380.1672", [0 x i8], { {}*, {}* }, [0 x i8], { i8*, i8* }, [0 x i8], { [0 x { i8*, i8* }]*, i16 }, [0 x i8] } +%"option::Option.0.76.152.228.304.380.1672" = type { [0 x i8], i8, [2 x i8] } + +@str.4S = external constant [5 x i8] + +; Function Attrs: uwtable +define void @"_ZN65_$LT$lib..str..Chars$LT$$u27$a$GT$$u20$as$u20$lib..fmt..Debug$GT$3fmt17h76a537e22649f739E"(%"fmt::Formatter.1.77.153.229.305.381.1673"* dereferenceable(27) %__arg_0) unnamed_addr #0 personality i32 (...)* @rust_eh_personality { +; CHECK-LABEL: "_ZN65_$LT$lib..str..Chars$LT$$u27$a$GT$$u20$as$u20$lib..fmt..Debug$GT$3fmt17h76a537e22649f739E" +start: + %0 = getelementptr inbounds %"fmt::Formatter.1.77.153.229.305.381.1673", %"fmt::Formatter.1.77.153.229.305.381.1673"* %__arg_0, i16 0, i32 11, i32 0 + %1 = load {}*, {}** %0, align 1, !noalias !0, !nonnull !9 + %2 = getelementptr inbounds %"fmt::Formatter.1.77.153.229.305.381.1673", %"fmt::Formatter.1.77.153.229.305.381.1673"* %__arg_0, i16 0, i32 11, i32 1 + %3 = bitcast {}** %2 to i1 ({}*, [0 x i8]*, i16)*** + %4 = load i1 ({}*, [0 x i8]*, i16)**, i1 ({}*, [0 x i8]*, i16)*** %3, align 1, !noalias !0, !nonnull !9 + %5 = getelementptr inbounds i1 ({}*, [0 x i8]*, i16)*, i1 ({}*, [0 x i8]*, i16)** %4, i16 3 + %6 = load i1 ({}*, [0 x i8]*, i16)*, i1 ({}*, [0 x i8]*, i16)** %5, align 1, !invariant.load !9, !noalias !0, !nonnull !9 + %7 = tail call zeroext i1 %6({}* nonnull %1, [0 x i8]* noalias nonnull readonly bitcast ([5 x i8]* @str.4S to [0 x i8]*), i16 5), !noalias !10 + unreachable +} + +declare i32 @rust_eh_personality(...) unnamed_addr + +attributes #0 = { uwtable } + +!0 = !{!1, !3, !5, !6, !8} +!1 = distinct !{!1, !2, !"_ZN3lib3fmt9Formatter9write_str17ha1a9656fc66ccbe5E: %data.0"} +!2 = distinct !{!2, !"_ZN3lib3fmt9Formatter9write_str17ha1a9656fc66ccbe5E"} +!3 = distinct !{!3, !4, !"_ZN3lib3fmt8builders16debug_struct_new17h352a1de8f89c2bc3E: argument 0"} +!4 = distinct !{!4, !"_ZN3lib3fmt8builders16debug_struct_new17h352a1de8f89c2bc3E"} +!5 = distinct !{!5, !4, !"_ZN3lib3fmt8builders16debug_struct_new17h352a1de8f89c2bc3E: %name.0"} +!6 = distinct !{!6, !7, !"_ZN3lib3fmt9Formatter12debug_struct17ha1ff79f633171b68E: argument 0"} +!7 = distinct !{!7, !"_ZN3lib3fmt9Formatter12debug_struct17ha1ff79f633171b68E"} +!8 = distinct !{!8, !7, !"_ZN3lib3fmt9Formatter12debug_struct17ha1ff79f633171b68E: %name.0"} +!9 = !{} +!10 = !{!3, !6} \ No newline at end of file