diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index 8fbda351ff39..ddf737c7449a 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -629,6 +629,12 @@ public: StringRef getNormalizedGCCRegisterName(StringRef Name, bool ReturnCanonical = false) const; + /// \brief Extracts a register from the passed constraint (if it is a + /// single-register constraint) and the asm label expression related to a + /// variable in the input or output list of an inline asm statement. + /// + /// This function is used by Sema in order to diagnose conflicts between + /// the clobber list and the input/output lists. virtual StringRef getConstraintRegister(StringRef Constraint, StringRef Expression) const { return ""; diff --git a/clang/lib/Basic/Targets/AArch64.h b/clang/lib/Basic/Targets/AArch64.h index 0634565bc78f..f493ff28d31d 100644 --- a/clang/lib/Basic/Targets/AArch64.h +++ b/clang/lib/Basic/Targets/AArch64.h @@ -82,6 +82,11 @@ public: std::string &SuggestedModifier) const override; const char *getClobbers() const override; + StringRef getConstraintRegister(StringRef Constraint, + StringRef Expression) const override { + return Expression; + } + int getEHDataRegisterNumber(unsigned RegNo) const override; }; diff --git a/clang/lib/Basic/Targets/ARM.h b/clang/lib/Basic/Targets/ARM.h index 4e8e514d4188..9c72c3387f7a 100644 --- a/clang/lib/Basic/Targets/ARM.h +++ b/clang/lib/Basic/Targets/ARM.h @@ -156,6 +156,11 @@ public: std::string &SuggestedModifier) const override; const char *getClobbers() const override; + StringRef getConstraintRegister(StringRef Constraint, + StringRef Expression) const override { + return Expression; + } + CallingConvCheckResult checkCallingConvention(CallingConv CC) const override; int getEHDataRegisterNumber(unsigned RegNo) const override; diff --git a/clang/test/Sema/arm-asm.c b/clang/test/Sema/arm-asm.c index e48718b0a2ac..24fb5a7ecd82 100644 --- a/clang/test/Sema/arm-asm.c +++ b/clang/test/Sema/arm-asm.c @@ -10,3 +10,10 @@ void test_64bit_r(void) { long long foo = 0, bar = 0; asm volatile("INST %0, %1" : "=r"(foo) : "r"(bar)); } + +void test_clobber_conflict(void) { + register int x asm("r1"); + asm volatile("nop" :: "r"(x) : "%r1"); // expected-error {{conflicts with asm clobber list}} + asm volatile("nop" :: "l"(x) : "%r1"); // expected-error {{conflicts with asm clobber list}} + asm volatile("nop" : "=r"(x) :: "%r1"); // expected-error {{conflicts with asm clobber list}} +} diff --git a/clang/test/Sema/arm64-inline-asm.c b/clang/test/Sema/arm64-inline-asm.c index d8e16a6872cc..541c190e6116 100644 --- a/clang/test/Sema/arm64-inline-asm.c +++ b/clang/test/Sema/arm64-inline-asm.c @@ -7,3 +7,9 @@ void foo() { asm volatile("USE(%0)" :: "z"(0)); // expected-warning {{value size does not match register size specified by the constraint and modifier}} expected-note {{use constraint modifier "w"}} } + +void test_clobber_conflict(void) { + register long x asm("x1"); + asm volatile("nop" :: "r"(x) : "%x1"); // expected-error {{conflicts with asm clobber list}} + asm volatile("nop" : "=r"(x) :: "%x1"); // expected-error {{conflicts with asm clobber list}} +}