Index: include/clang/AST/Expr.h =================================================================== --- include/clang/AST/Expr.h +++ include/clang/AST/Expr.h @@ -458,6 +458,10 @@ /// \brief Returns whether this expression refers to a vector element. bool refersToVectorElement() const; + /// \brief Returns whether this expression refers to a global register + /// variable. + bool refersToGlobalRegisterVar() const; + /// \brief Returns whether this expression has a placeholder type. bool hasPlaceholderType() const { return getType()->isPlaceholderType(); Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -6365,9 +6365,9 @@ "remove the cast or build with -fheinous-gnu-extensions">; def err_invalid_asm_value_for_constraint : Error <"value '%0' out of range for constraint '%1'">; - def err_asm_bitfield_in_memory_constraint - : Error <"reference to a bit-field in asm " - "%select{input|output}0 with a memory constraint '%1'">; + def err_asm_non_addr_value_in_memory_constraint : Error < + "reference to a %select{bit-field|vector element|global register variable}0" + " in asm %select{input|output}1 with a memory constraint '%2'">; def warn_asm_label_on_auto_decl : Warning< "ignored asm label '%0' on automatic variable">; Index: lib/AST/Expr.cpp =================================================================== --- lib/AST/Expr.cpp +++ lib/AST/Expr.cpp @@ -3429,6 +3429,18 @@ return false; } +bool Expr::refersToGlobalRegisterVar() const { + const Expr *E = this->IgnoreParenImpCasts(); + + if (const DeclRefExpr *DRE = dyn_cast(E)) + if (const auto *VD = dyn_cast(DRE->getDecl())) + if (VD->getStorageClass() == SC_Register && + VD->hasAttr() && !VD->isLocalVarDecl()) + return true; + + return false; +} + /// isArrow - Return true if the base expression is a pointer to vector, /// return false if the base expression is a vector. bool ExtVectorElementExpr::isArrow() const { Index: lib/Sema/SemaStmtAsm.cpp =================================================================== --- lib/Sema/SemaStmtAsm.cpp +++ lib/Sema/SemaStmtAsm.cpp @@ -107,6 +107,37 @@ return false; } +/// \brief Returns true if given expression is not compatible with inline +/// assembly's memory constraint; false otherwise. +static bool checkExprMemoryConstraintCompat(Sema &S, Expr *E, + TargetInfo::ConstraintInfo &Info, + bool is_input_expr) { + enum { + ExprBitfield = 0, + ExprVectorElt, + ExprGlobalRegVar, + ExprSafeType + } EType = ExprSafeType; + + // Bitfields, vector elements and global register variables are not + // compatible. + if (E->refersToBitField()) + EType = ExprBitfield; + else if (E->refersToVectorElement()) + EType = ExprVectorElt; + else if (E->refersToGlobalRegisterVar()) + EType = ExprGlobalRegVar; + + if (EType != ExprSafeType) { + S.Diag(E->getLocStart(), diag::err_asm_non_addr_value_in_memory_constraint) + << EType << is_input_expr << Info.getConstraintStr() + << E->getSourceRange(); + return true; + } + + return false; +} + StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, bool IsVolatile, unsigned NumOutputs, unsigned NumInputs, IdentifierInfo **Names, @@ -154,13 +185,10 @@ if (CheckNakedParmReference(OutputExpr, *this)) return StmtError(); - // Bitfield can't be referenced with a pointer. - if (Info.allowsMemory() && OutputExpr->refersToBitField()) - return StmtError(Diag(OutputExpr->getLocStart(), - diag::err_asm_bitfield_in_memory_constraint) - << 1 - << Info.getConstraintStr() - << OutputExpr->getSourceRange()); + // Check that the output expression is compatible with memory constraint. + if (Info.allowsMemory() && + checkExprMemoryConstraintCompat(*this, OutputExpr, Info, false)) + return StmtError(); OutputConstraintInfos.push_back(Info); @@ -238,13 +266,10 @@ if (CheckNakedParmReference(InputExpr, *this)) return StmtError(); - // Bitfield can't be referenced with a pointer. - if (Info.allowsMemory() && InputExpr->refersToBitField()) - return StmtError(Diag(InputExpr->getLocStart(), - diag::err_asm_bitfield_in_memory_constraint) - << 0 - << Info.getConstraintStr() - << InputExpr->getSourceRange()); + // Check that the input expression is compatible with memory constraint. + if (Info.allowsMemory() && + checkExprMemoryConstraintCompat(*this, InputExpr, Info, true)) + return StmtError(); // Only allow void types for memory constraints. if (Info.allowsMemory() && !Info.allowsRegister()) { Index: test/Sema/asm.c =================================================================== --- test/Sema/asm.c +++ test/Sema/asm.c @@ -211,13 +211,28 @@ unsigned int field2 : 2; unsigned int field3 : 3; } test16_foo; -test16_foo x; +typedef __attribute__((vector_size(16))) int test16_bar; +register int test16_baz asm("rbx"); + void test16() { + test16_foo a; + test16_bar b; + + __asm__("movl $5, %0" + : "=rm" (a.field2)); // expected-error {{reference to a bit-field in asm input with a memory constraint '=rm'}} + __asm__("movl $5, %0" + : + : "m" (a.field3)); // expected-error {{reference to a bit-field in asm output with a memory constraint 'm'}} + __asm__("movl $5, %0" + : "=rm" (b[2])); // expected-error {{reference to a vector element in asm input with a memory constraint '=rm'}} + __asm__("movl $5, %0" + : + : "m" (b[3])); // expected-error {{reference to a vector element in asm output with a memory constraint 'm'}} __asm__("movl $5, %0" - : "=rm" (x.field2)); // expected-error {{reference to a bit-field in asm output with a memory constraint '=rm'}} + : "=rm" (test16_baz)); // expected-error {{reference to a global register variable in asm input with a memory constraint '=rm'}} __asm__("movl $5, %0" : - : "m" (x.field3)); // expected-error {{reference to a bit-field in asm input with a memory constraint 'm'}} + : "m" (test16_baz)); // expected-error {{reference to a global register variable in asm output with a memory constraint 'm'}} }