https://github.com/paulwalker-arm created https://github.com/llvm/llvm-project/pull/70970
[LLVM][AArch64] Add ASM constraints for reduced GPR register ranges. The patch adds the follow ASM constraints: Uci => w8-w11 Ucj => w12-w15 These constraints are required for SME load/store instructions where a reduced set of GPRs are used to specify ZA array vectors. NOTE: GCC has agreed to use the same constraint syntax. >From 7a772d1ad2c9bcdddefccaa25a73f708ab4fe50e Mon Sep 17 00:00:00 2001 From: Paul Walker <paul.wal...@arm.com> Date: Wed, 1 Nov 2023 16:27:29 +0000 Subject: [PATCH 1/2] [NFC][LLVM][SVE] Refactor predicate register ASM constraint parsing to use std::optional. --- .../Target/AArch64/AArch64ISelLowering.cpp | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index d00db82c9e49ac2..44183a1fa48abab 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -10161,14 +10161,15 @@ const char *AArch64TargetLowering::LowerXConstraint(EVT ConstraintVT) const { return "r"; } -enum PredicateConstraint { Uph, Upl, Upa, Invalid }; +enum class PredicateConstraint { Uph, Upl, Upa }; -static PredicateConstraint parsePredicateConstraint(StringRef Constraint) { - return StringSwitch<PredicateConstraint>(Constraint) +static std::optional<PredicateConstraint> +parsePredicateConstraint(StringRef Constraint) { + return StringSwitch<std::optional<PredicateConstraint>>(Constraint) .Case("Uph", PredicateConstraint::Uph) .Case("Upl", PredicateConstraint::Upl) .Case("Upa", PredicateConstraint::Upa) - .Default(PredicateConstraint::Invalid); + .Default(std::nullopt); } static const TargetRegisterClass * @@ -10178,8 +10179,6 @@ getPredicateRegisterClass(PredicateConstraint Constraint, EVT VT) { return nullptr; switch (Constraint) { - default: - return nullptr; case PredicateConstraint::Uph: return VT == MVT::aarch64svcount ? &AArch64::PNR_p8to15RegClass : &AArch64::PPR_p8to15RegClass; @@ -10190,6 +10189,8 @@ getPredicateRegisterClass(PredicateConstraint Constraint, EVT VT) { return VT == MVT::aarch64svcount ? &AArch64::PNRRegClass : &AArch64::PPRRegClass; } + + llvm_unreachable("Missing PredicateConstraint!"); } // The set of cc code supported is from @@ -10287,9 +10288,8 @@ AArch64TargetLowering::getConstraintType(StringRef Constraint) const { case 'S': // A symbolic address return C_Other; } - } else if (parsePredicateConstraint(Constraint) != - PredicateConstraint::Invalid) - return C_RegisterClass; + } else if (parsePredicateConstraint(Constraint)) + return C_RegisterClass; else if (parseConstraintCode(Constraint) != AArch64CC::Invalid) return C_Other; return TargetLowering::getConstraintType(Constraint); @@ -10323,7 +10323,7 @@ AArch64TargetLowering::getSingleConstraintMatchWeight( weight = CW_Constant; break; case 'U': - if (parsePredicateConstraint(constraint) != PredicateConstraint::Invalid) + if (parsePredicateConstraint(constraint)) weight = CW_Register; break; } @@ -10380,9 +10380,9 @@ AArch64TargetLowering::getRegForInlineAsmConstraint( break; } } else { - PredicateConstraint PC = parsePredicateConstraint(Constraint); - if (const TargetRegisterClass *RegClass = getPredicateRegisterClass(PC, VT)) - return std::make_pair(0U, RegClass); + if (const auto PC = parsePredicateConstraint(Constraint)) + if (const auto *RegClass = getPredicateRegisterClass(*PC, VT)) + return std::make_pair(0U, RegClass); } if (StringRef("{cc}").equals_insensitive(Constraint) || parseConstraintCode(Constraint) != AArch64CC::Invalid) >From 50c72be6e4c8ff508d8ceaacc7aa37ff2aef1cca Mon Sep 17 00:00:00 2001 From: Paul Walker <paul.wal...@arm.com> Date: Wed, 1 Nov 2023 17:33:10 +0000 Subject: [PATCH 2/2] [LLVM][AArch64] Add ASM constraints for reduced GPR register ranges. The patch adds the follow ASM constraints: Uci => w8-w11 Ucj => w12-w15 These constraints are required for SME load/store instructions where a reduced set of GPRs are used to specify ZA array vectors. NOTE: GCC has agreed to use the same constraint syntax. --- clang/lib/Basic/Targets/AArch64.cpp | 6 ++++ clang/test/CodeGen/aarch64-inline-asm.c | 9 +++++ .../Target/AArch64/AArch64ISelLowering.cpp | 34 ++++++++++++++++++- .../AArch64/inlineasm-Uc-constraint.ll | 28 +++++++++++++++ 4 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 llvm/test/CodeGen/AArch64/inlineasm-Uc-constraint.ll diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp index fe5a7af97b7753c..d5834368e8970db 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, "Upj"=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 439fb9e33f9ae15..0374671e1ab576c 100644 --- a/clang/test/CodeGen/aarch64-inline-asm.c +++ b/clang/test/CodeGen/aarch64-inline-asm.c @@ -80,3 +80,12 @@ void test_tied_earlyclobber(void) { asm("" : "+&r"(a)); // CHECK: call i32 asm "", "=&{x1},0"(i32 %0) } + +void test_reduced_gpr_constraints(unsigned int var) { + asm("add x0, x0, %0" : : "Uci"(var) : "x0"); +// CHECK: [[ARG1:%.+]] = load i32, ptr +// CHECK: call void asm sideeffect "add x0, x0, $0", "@3Uci,~{x0}"(i32 [[ARG1]]) + asm("add x0, x0, %0" : : "Ucj"(var) : "x0"); +// CHECK: [[ARG2:%.+]] = load i32, ptr +// CHECK: call void asm sideeffect "add x0, x0, $0", "@3Ucj,~{x0}"(i32 [[ARG2]]) +} diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index 44183a1fa48abab..daa97fe73599e35 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -10193,6 +10193,31 @@ getPredicateRegisterClass(PredicateConstraint Constraint, EVT VT) { llvm_unreachable("Missing PredicateConstraint!"); } +enum class ReducedGprConstraint { Uci, Ucj }; + +static std::optional<ReducedGprConstraint> +parseReducedGprConstraint(StringRef Constraint) { + return StringSwitch<std::optional<ReducedGprConstraint>>(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() != 32) + 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) { @@ -10290,6 +10315,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); @@ -10323,7 +10350,8 @@ AArch64TargetLowering::getSingleConstraintMatchWeight( weight = CW_Constant; break; case 'U': - if (parsePredicateConstraint(constraint)) + if (parsePredicateConstraint(constraint) || + parseReducedGprConstraint(constraint)) weight = CW_Register; break; } @@ -10383,6 +10411,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 000000000000000..68c1b4a7177b395 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/inlineasm-Uc-constraint.ll @@ -0,0 +1,28 @@ +; 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(i32 %a) { +; CHECK-LABEL: test_constraints_Uci: +; 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 +} + +define void @test_constraint_Ucj(i32 %a) { +; CHECK-LABEL: test_constraint_Ucj: +; 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 +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits