diff --git a/clang/lib/Basic/Targets/BPF.h b/clang/lib/Basic/Targets/BPF.h --- a/clang/lib/Basic/Targets/BPF.h +++ b/clang/lib/Basic/Targets/BPF.h @@ -23,6 +23,7 @@ class LLVM_LIBRARY_VISIBILITY BPFTargetInfo : public TargetInfo { static const Builtin::Info BuiltinInfo[]; + bool HasAlu32 = false; public: BPFTargetInfo(const llvm::Triple &Triple, const TargetOptions &) @@ -55,6 +56,8 @@ bool Enabled) const override { Features[Name] = Enabled; } + bool handleTargetFeatures(std::vector &Features, + DiagnosticsEngine &Diags) override; ArrayRef getTargetBuiltins() const override; @@ -68,7 +71,16 @@ ArrayRef getGCCRegNames() const override { return None; } bool validateAsmConstraint(const char *&Name, - TargetInfo::ConstraintInfo &info) const override { + TargetInfo::ConstraintInfo &Info) const override { + switch (*Name) { + default: + break; + case 'w': + if (HasAlu32) { + Info.setAllowsRegister(); + } + break; + } return true; } diff --git a/clang/lib/Basic/Targets/BPF.cpp b/clang/lib/Basic/Targets/BPF.cpp --- a/clang/lib/Basic/Targets/BPF.cpp +++ b/clang/lib/Basic/Targets/BPF.cpp @@ -46,3 +46,14 @@ return llvm::makeArrayRef(BuiltinInfo, clang::BPF::LastTSBuiltin - Builtin::FirstTSBuiltin); } + +bool BPFTargetInfo::handleTargetFeatures(std::vector &Features, + DiagnosticsEngine &Diags) { + for (const auto &Feature : Features) { + if (Feature == "+alu32") { + HasAlu32 = true; + } + } + + return true; +} \ No newline at end of file diff --git a/clang/test/CodeGen/bpf-inline-asm.c b/clang/test/CodeGen/bpf-inline-asm.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/bpf-inline-asm.c @@ -0,0 +1,32 @@ +// REQUIRES: bpf-registered-target +// RUN: %clang -target bpf -emit-llvm -S -Xclang -target-feature -Xclang +alu32 %s -o - | FileCheck %s + +long var; + +void test_generic_constraints(int var32, long var64) { + asm("%0 = %1" + : "=r"(var32) + : "0"(var32)); + // CHECK: [[R32_ARG:%[a-zA-Z0-9]+]] = load i32, i32* + // CHECK: call i32 asm "$0 = $1", "=r,0"(i32 [[R32_ARG]]) + + asm("%0 = %1" + : "=r"(var64) + : "0"(var64)); + // CHECK: [[R64_ARG:%[a-zA-Z0-9]+]] = load i64, i64* + // CHECK: call i64 asm "$0 = $1", "=r,0"(i64 [[R64_ARG]]) + + asm("%0 = %1" + : "=r"(var64) + : "r"(var64)); + // CHECK: [[R64_ARG:%[a-zA-Z0-9]+]] = load i64, i64* + // CHECK: call i64 asm "$0 = $1", "=r,r"(i64 [[R64_ARG]]) +} + +void test_constraint_w(int a) { + asm("%0 = %1" + : "=w"(a) + : "w"(a)); + // CHECK: [[R32_ARG:%[a-zA-Z0-9]+]] = load i32, i32* + // CHECK: call i32 asm "$0 = $1", "=w,w"(i32 [[R32_ARG]]) +} \ No newline at end of file diff --git a/llvm/lib/Target/BPF/BPFISelLowering.h b/llvm/lib/Target/BPF/BPFISelLowering.h --- a/llvm/lib/Target/BPF/BPFISelLowering.h +++ b/llvm/lib/Target/BPF/BPFISelLowering.h @@ -46,6 +46,9 @@ // with the given GlobalAddress is legal. bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override; + BPFTargetLowering::ConstraintType + getConstraintType(StringRef Constraint) const override; + std::pair getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const override; diff --git a/llvm/lib/Target/BPF/BPFISelLowering.cpp b/llvm/lib/Target/BPF/BPFISelLowering.cpp --- a/llvm/lib/Target/BPF/BPFISelLowering.cpp +++ b/llvm/lib/Target/BPF/BPFISelLowering.cpp @@ -220,6 +220,20 @@ return NumBits1 == 32 && NumBits2 == 64; } +BPFTargetLowering::ConstraintType +BPFTargetLowering::getConstraintType(StringRef Constraint) const { + if (Constraint.size() == 1) { + switch (Constraint[0]) { + default: + break; + case 'w': + return C_RegisterClass; + } + } + + return TargetLowering::getConstraintType(Constraint); +} + std::pair BPFTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, StringRef Constraint, @@ -229,6 +243,10 @@ switch (Constraint[0]) { case 'r': // GENERAL_REGS return std::make_pair(0U, &BPF::GPRRegClass); + case 'w': + if (HasAlu32) + return std::make_pair(0U, &BPF::GPR32RegClass); + break; default: break; } diff --git a/llvm/test/CodeGen/BPF/inlineasm-wreg.ll b/llvm/test/CodeGen/BPF/inlineasm-wreg.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/BPF/inlineasm-wreg.ll @@ -0,0 +1,19 @@ + +; RUN: llc < %s -march=bpfel -mattr=+alu32 -verify-machineinstrs | FileCheck %s +; RUN: llc < %s -march=bpfeb -mattr=+alu32 -verify-machineinstrs | FileCheck %s + +; Test that %w works as input constraint +; CHECK-LABEL: test_inlineasm_w_input_constraint +define dso_local i32 @test_inlineasm_w_input_constraint() { + tail call void asm sideeffect "w0 = $0", "w"(i32 42) +; CHECK: w0 = w1 + ret i32 42 +} + +; Test that %w works as output constraint +; CHECK-LABEL: test_inlineasm_w_output_constraint +define dso_local i32 @test_inlineasm_w_output_constraint() { + %1 = tail call i32 asm sideeffect "$0 = $1", "=w,i"(i32 42) +; CHECK: w0 = 42 + ret i32 %1 +} \ No newline at end of file