Skip to content

Commit

Permalink
Additional fix for PR14269: Crash on vector elements / global registe…
Browse files Browse the repository at this point in the history
…r vars in inline assembler.

Compiler crashed when vector elements / global register vars were used in inline assembler with "m" restriction. This patch fixes this.

Differential Revision: http://reviews.llvm.org/D10476

llvm-svn: 243870
  • Loading branch information
andreybokhanko committed Aug 3, 2015
1 parent 6967e5e commit d9eab9c
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 20 deletions.
4 changes: 4 additions & 0 deletions clang/include/clang/AST/Expr.h
Expand Up @@ -459,6 +459,10 @@ class Expr : public Stmt {
/// \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();
Expand Down
6 changes: 3 additions & 3 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Expand Up @@ -6385,9 +6385,9 @@ let CategoryName = "Inline Assembly Issue" in {
"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">;
Expand Down
12 changes: 12 additions & 0 deletions clang/lib/AST/Expr.cpp
Expand Up @@ -3437,6 +3437,18 @@ bool Expr::refersToVectorElement() const {
return false;
}

bool Expr::refersToGlobalRegisterVar() const {
const Expr *E = this->IgnoreParenImpCasts();

if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E))
if (const auto *VD = dyn_cast<VarDecl>(DRE->getDecl()))
if (VD->getStorageClass() == SC_Register &&
VD->hasAttr<AsmLabelAttr>() && !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 {
Expand Down
53 changes: 39 additions & 14 deletions clang/lib/Sema/SemaStmtAsm.cpp
Expand Up @@ -107,6 +107,37 @@ static bool CheckNakedParmReference(Expr *E, Sema &S) {
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,
Expand Down Expand Up @@ -154,13 +185,10 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
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);

Expand Down Expand Up @@ -238,13 +266,10 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple,
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()) {
Expand Down
21 changes: 18 additions & 3 deletions clang/test/Sema/asm.c
Expand Up @@ -211,13 +211,28 @@ typedef struct test16_foo {
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'}}
}

0 comments on commit d9eab9c

Please sign in to comment.