Author: Jonas Paulsson Date: 2020-10-21T10:53:40+02:00 New Revision: 42a82862b625279028130e62846d057425bca691
URL: https://github.com/llvm/llvm-project/commit/42a82862b625279028130e62846d057425bca691 DIFF: https://github.com/llvm/llvm-project/commit/42a82862b625279028130e62846d057425bca691.diff LOG: Reapply "[clang] Improve handling of physical registers in inline assembly operands." Earlyclobbers are now excepted from this change (original commit: c78da03). Review: Ulrich Weigand, Nick Desaulniers Differential Revision: https://reviews.llvm.org/D87279 Added: clang/test/CodeGen/systemz-inline-asm-02.c Modified: clang/lib/CodeGen/CGStmt.cpp clang/test/CodeGen/aarch64-inline-asm.c clang/test/CodeGen/systemz-inline-asm.c Removed: ################################################################################ diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index 4b813be086e1..3f8f77654f6d 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -21,6 +21,7 @@ #include "clang/Basic/PrettyStackTrace.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/StringExtras.h" #include "llvm/IR/DataLayout.h" #include "llvm/IR/InlineAsm.h" @@ -1953,7 +1954,8 @@ SimplifyConstraint(const char *Constraint, const TargetInfo &Target, static std::string AddVariableConstraints(const std::string &Constraint, const Expr &AsmExpr, const TargetInfo &Target, CodeGenModule &CGM, - const AsmStmt &Stmt, const bool EarlyClobber) { + const AsmStmt &Stmt, const bool EarlyClobber, + std::string *GCCReg = nullptr) { const DeclRefExpr *AsmDeclRef = dyn_cast<DeclRefExpr>(&AsmExpr); if (!AsmDeclRef) return Constraint; @@ -1978,6 +1980,8 @@ AddVariableConstraints(const std::string &Constraint, const Expr &AsmExpr, } // Canonicalize the register here before returning it. Register = Target.getNormalizedGCCRegisterName(Register); + if (GCCReg != nullptr) + *GCCReg = Register.str(); return (EarlyClobber ? "&{" : "{") + Register.str() + "}"; } @@ -2176,6 +2180,9 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { // Keep track of out constraints for tied input operand. std::vector<std::string> OutputConstraints; + // Keep track of defined physregs. + llvm::SmallSet<std::string, 8> PhysRegOutputs; + // An inline asm can be marked readonly if it meets the following conditions: // - it doesn't have any sideeffects // - it doesn't clobber memory @@ -2195,9 +2202,15 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { const Expr *OutExpr = S.getOutputExpr(i); OutExpr = OutExpr->IgnoreParenNoopCasts(getContext()); + std::string GCCReg; OutputConstraint = AddVariableConstraints(OutputConstraint, *OutExpr, getTarget(), CGM, S, - Info.earlyClobber()); + Info.earlyClobber(), + &GCCReg); + // Give an error on multiple outputs to same physreg. + if (!GCCReg.empty() && !PhysRegOutputs.insert(GCCReg).second) + CGM.Error(S.getAsmLoc(), "multiple outputs to hard register: " + GCCReg); + OutputConstraints.push_back(OutputConstraint); LValue Dest = EmitLValue(OutExpr); if (!Constraints.empty()) @@ -2284,7 +2297,8 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) { LargestVectorWidth = std::max((uint64_t)LargestVectorWidth, VT->getPrimitiveSizeInBits().getKnownMinSize()); - if (Info.allowsRegister()) + // Only tie earlyclobber physregs. + if (Info.allowsRegister() && (GCCReg.empty() || Info.earlyClobber())) InOutConstraints += llvm::utostr(i); else InOutConstraints += OutputConstraint; diff --git a/clang/test/CodeGen/aarch64-inline-asm.c b/clang/test/CodeGen/aarch64-inline-asm.c index 0889a7157f0b..a6e8faef8b9e 100644 --- a/clang/test/CodeGen/aarch64-inline-asm.c +++ b/clang/test/CodeGen/aarch64-inline-asm.c @@ -74,3 +74,9 @@ void test_gcc_registers(void) { asm volatile("mov r0, r1\n"); // CHECK: call void asm sideeffect "mov r0, r1\0A", ""() } + +void test_tied_earlyclobber(void) { + register int a asm("x1"); + asm("" : "+&r"(a)); + // CHECK: call i32 asm "", "=&{x1},0"(i32 %0) +} diff --git a/clang/test/CodeGen/systemz-inline-asm-02.c b/clang/test/CodeGen/systemz-inline-asm-02.c new file mode 100644 index 000000000000..754d7e66f04b --- /dev/null +++ b/clang/test/CodeGen/systemz-inline-asm-02.c @@ -0,0 +1,13 @@ +// RUN: not %clang_cc1 -triple s390x-linux-gnu -O2 -emit-llvm -o - %s 2>&1 \ +// RUN: | FileCheck %s +// REQUIRES: systemz-registered-target + +// Test that an error is given if a physreg is defined by multiple operands. +int test_physreg_defs(void) { + register int l __asm__("r7") = 0; + + // CHECK: error: multiple outputs to hard register: r7 + __asm__("" : "+r"(l), "=r"(l)); + + return l; +} diff --git a/clang/test/CodeGen/systemz-inline-asm.c b/clang/test/CodeGen/systemz-inline-asm.c index c5497655f505..357fd4c184e7 100644 --- a/clang/test/CodeGen/systemz-inline-asm.c +++ b/clang/test/CodeGen/systemz-inline-asm.c @@ -129,3 +129,17 @@ long double test_f128(long double f, long double g) { // CHECK: [[RESULT:%.*]] = tail call fp128 asm "axbr $0, $2", "=f,0,f"(fp128 %f, fp128 %g) // CHECK: store fp128 [[RESULT]], fp128* [[DEST]] } + +// Test that there are no tied physreg uses. TwoAddress pass cannot deal with them. +int test_physregs(void) { + // CHECK-LABEL: define signext i32 @test_physregs() + register int l __asm__("r7") = 0; + + // CHECK: call i32 asm "lr $0, $1", "={r7},{r7}" + __asm__("lr %0, %1" : "+r"(l)); + + // CHECK: call i32 asm "$0 $1 $2", "={r7},{r7},{r7}" + __asm__("%0 %1 %2" : "+r"(l) : "r"(l)); + + return l; +} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits