diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 4696836b3a00ca..afe7e2e79c2d08 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -738,6 +738,8 @@ Arm and AArch64 Support This affects C++ functions with SVE ACLE parameters. Clang will use the old manglings if ``-fclang-abi-compat=17`` or lower is specified. +- New AArch64 asm constraints have been added for r8-r11(Uci) and r12-r15(Ucj). + Android Support ^^^^^^^^^^^^^^^ diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp index fe5a7af97b7753..c71af71eba60ce 100644 --- a/clang/lib/Basic/Targets/AArch64.cpp +++ b/clang/lib/Basic/Targets/AArch64.cpp @@ -1306,6 +1306,12 @@ bool AArch64TargetInfo::validateAsmConstraint( Name += 2; return true; } + if (Name[1] == 'c' && (Name[2] == 'i' || Name[2] == 'j')) { + // Gpr registers ("Uci"=w8-11, "Ucj"=w12-15) + Info.setAllowsRegister(); + Name += 2; + return true; + } // Ump: A memory address suitable for ldp/stp in SI, DI, SF and DF modes. // Utf: A memory address suitable for ldp/stp in TF mode. // Usa: An absolute symbolic address. diff --git a/clang/test/CodeGen/aarch64-inline-asm.c b/clang/test/CodeGen/aarch64-inline-asm.c index 439fb9e33f9ae1..75e9a8c46b8769 100644 --- a/clang/test/CodeGen/aarch64-inline-asm.c +++ b/clang/test/CodeGen/aarch64-inline-asm.c @@ -80,3 +80,18 @@ void test_tied_earlyclobber(void) { asm("" : "+&r"(a)); // CHECK: call i32 asm "", "=&{x1},0"(i32 %0) } + +void test_reduced_gpr_constraints(int var32, long var64) { + asm("add w0, w0, %0" : : "Uci"(var32) : "w0"); +// CHECK: [[ARG1:%.+]] = load i32, ptr +// CHECK: call void asm sideeffect "add w0, w0, $0", "@3Uci,~{w0}"(i32 [[ARG1]]) + asm("add x0, x0, %0" : : "Uci"(var64) : "x0"); +// CHECK: [[ARG1:%.+]] = load i64, ptr +// CHECK: call void asm sideeffect "add x0, x0, $0", "@3Uci,~{x0}"(i64 [[ARG1]]) + asm("add w0, w0, %0" : : "Ucj"(var32) : "w0"); +// CHECK: [[ARG2:%.+]] = load i32, ptr +// CHECK: call void asm sideeffect "add w0, w0, $0", "@3Ucj,~{w0}"(i32 [[ARG2]]) + asm("add x0, x0, %0" : : "Ucj"(var64) : "x0"); +// CHECK: [[ARG2:%.+]] = load i64, ptr +// CHECK: call void asm sideeffect "add x0, x0, $0", "@3Ucj,~{x0}"(i64 [[ARG2]]) +} diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 6fd483276a301c..1e9d42ed0a0607 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -5094,6 +5094,8 @@ AArch64: offsets). (However, LLVM currently does this for the ``m`` constraint as well.) - ``r``: A 32 or 64-bit integer register (W* or X*). +- ``Uci``: Like r, but restricted to registers 8 to 11 inclusive. +- ``Ucj``: Like r, but restricted to registers 12 to 15 inclusive. - ``w``: A 32, 64, or 128-bit floating-point, SIMD or SVE vector register. - ``x``: Like w, but restricted to registers 0 to 15 inclusive. - ``y``: Like w, but restricted to SVE vector registers Z0 to Z7 inclusive. diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index 94901c2d1a6568..f5193a9f2adf30 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -10195,6 +10195,31 @@ getPredicateRegisterClass(PredicateConstraint Constraint, EVT VT) { llvm_unreachable("Missing PredicateConstraint!"); } +enum class ReducedGprConstraint { Uci, Ucj }; + +static std::optional +parseReducedGprConstraint(StringRef Constraint) { + return StringSwitch>(Constraint) + .Case("Uci", ReducedGprConstraint::Uci) + .Case("Ucj", ReducedGprConstraint::Ucj) + .Default(std::nullopt); +} + +static const TargetRegisterClass * +getReducedGprRegisterClass(ReducedGprConstraint Constraint, EVT VT) { + if (!VT.isScalarInteger() || VT.getFixedSizeInBits() > 64) + return nullptr; + + switch (Constraint) { + case ReducedGprConstraint::Uci: + return &AArch64::MatrixIndexGPR32_8_11RegClass; + case ReducedGprConstraint::Ucj: + return &AArch64::MatrixIndexGPR32_12_15RegClass; + } + + llvm_unreachable("Missing ReducedGprConstraint!"); +} + // The set of cc code supported is from // https://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html#Flag-Output-Operands static AArch64CC::CondCode parseConstraintCode(llvm::StringRef Constraint) { @@ -10292,6 +10317,8 @@ AArch64TargetLowering::getConstraintType(StringRef Constraint) const { } } else if (parsePredicateConstraint(Constraint)) return C_RegisterClass; + else if (parseReducedGprConstraint(Constraint)) + return C_RegisterClass; else if (parseConstraintCode(Constraint) != AArch64CC::Invalid) return C_Other; return TargetLowering::getConstraintType(Constraint); @@ -10325,7 +10352,8 @@ AArch64TargetLowering::getSingleConstraintMatchWeight( weight = CW_Constant; break; case 'U': - if (parsePredicateConstraint(constraint)) + if (parsePredicateConstraint(constraint) || + parseReducedGprConstraint(constraint)) weight = CW_Register; break; } @@ -10385,6 +10413,10 @@ AArch64TargetLowering::getRegForInlineAsmConstraint( if (const auto PC = parsePredicateConstraint(Constraint)) if (const auto *RegClass = getPredicateRegisterClass(*PC, VT)) return std::make_pair(0U, RegClass); + + if (const auto RGC = parseReducedGprConstraint(Constraint)) + if (const auto *RegClass = getReducedGprRegisterClass(*RGC, VT)) + return std::make_pair(0U, RegClass); } if (StringRef("{cc}").equals_insensitive(Constraint) || parseConstraintCode(Constraint) != AArch64CC::Invalid) diff --git a/llvm/test/CodeGen/AArch64/inlineasm-Uc-constraint.ll b/llvm/test/CodeGen/AArch64/inlineasm-Uc-constraint.ll new file mode 100644 index 00000000000000..0bee7ea40cc1ae --- /dev/null +++ b/llvm/test/CodeGen/AArch64/inlineasm-Uc-constraint.ll @@ -0,0 +1,78 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 3 +; RUN: llc < %s -o - | FileCheck %s + +target triple = "arm64-none-linux-gnu" + +define void @test_constraints_Uci_w(i32 %a) { +; CHECK-LABEL: test_constraints_Uci_w: +; CHECK: // %bb.0: +; CHECK-NEXT: mov w8, w0 +; CHECK-NEXT: //APP +; CHECK-NEXT: add x0, x0, x8 +; CHECK-NEXT: //NO_APP +; CHECK-NEXT: ret + call void asm sideeffect "add x0, x0, $0", "@3Uci,~{x0}"(i32 %a) + ret void +} + +; As test_constraints_Uci_w but ensures non-legal types are also covered. +define void @test_constraints_Uci_w_i8(i8 %a) { +; CHECK-LABEL: test_constraints_Uci_w_i8: +; CHECK: // %bb.0: +; CHECK-NEXT: mov w8, w0 +; CHECK-NEXT: //APP +; CHECK-NEXT: add x0, x0, x8 +; CHECK-NEXT: //NO_APP +; CHECK-NEXT: ret + call void asm sideeffect "add x0, x0, $0", "@3Uci,~{x0}"(i8 %a) + ret void +} + +define void @test_constraints_Uci_x(i64 %a) { +; CHECK-LABEL: test_constraints_Uci_x: +; CHECK: // %bb.0: +; CHECK-NEXT: mov x8, x0 +; CHECK-NEXT: //APP +; CHECK-NEXT: add x0, x0, x8 +; CHECK-NEXT: //NO_APP +; CHECK-NEXT: ret + call void asm sideeffect "add x0, x0, $0", "@3Uci,~{x0}"(i64 %a) + ret void +} + +define void @test_constraint_Ucj_w(i32 %a) { +; CHECK-LABEL: test_constraint_Ucj_w: +; CHECK: // %bb.0: +; CHECK-NEXT: mov w12, w0 +; CHECK-NEXT: //APP +; CHECK-NEXT: add x0, x0, x12 +; CHECK-NEXT: //NO_APP +; CHECK-NEXT: ret + call void asm sideeffect "add x0, x0, $0", "@3Ucj,~{x0}"(i32 %a) + ret void +} + +; As test_constraints_Ucj_w but ensures non-legal types are also covered. +define void @test_constraint_Ucj_w_i8(i8 %a) { +; CHECK-LABEL: test_constraint_Ucj_w_i8: +; CHECK: // %bb.0: +; CHECK-NEXT: mov w12, w0 +; CHECK-NEXT: //APP +; CHECK-NEXT: add x0, x0, x12 +; CHECK-NEXT: //NO_APP +; CHECK-NEXT: ret + call void asm sideeffect "add x0, x0, $0", "@3Ucj,~{x0}"(i8 %a) + ret void +} + +define void @test_constraint_Ucj_x(i64 %a) { +; CHECK-LABEL: test_constraint_Ucj_x: +; CHECK: // %bb.0: +; CHECK-NEXT: mov x12, x0 +; CHECK-NEXT: //APP +; CHECK-NEXT: add x0, x0, x12 +; CHECK-NEXT: //NO_APP +; CHECK-NEXT: ret + call void asm sideeffect "add x0, x0, $0", "@3Ucj,~{x0}"(i64 %a) + ret void +}