diff options
Diffstat (limited to 'clang/lib/Sema/SemaStmtAsm.cpp')
-rw-r--r-- | clang/lib/Sema/SemaStmtAsm.cpp | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp index 9a182449845..50366222093 100644 --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -22,6 +22,7 @@ #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringSet.h" #include "llvm/MC/MCParser/MCAsmParser.h" using namespace clang; using namespace sema; @@ -137,6 +138,57 @@ static bool checkExprMemoryConstraintCompat(Sema &S, Expr *E, return false; } +// Extracting the register name from the Expression value, +// if there is no register name to extract, returns "" +static StringRef extractRegisterName(const Expr *Expression, + const TargetInfo &Target) { + Expression = Expression->IgnoreImpCasts(); + if (const DeclRefExpr *AsmDeclRef = dyn_cast<DeclRefExpr>(Expression)) { + // Handle cases where the expression is a variable + const VarDecl *Variable = dyn_cast<VarDecl>(AsmDeclRef->getDecl()); + if (Variable && Variable->getStorageClass() == SC_Register) { + if (AsmLabelAttr *Attr = Variable->getAttr<AsmLabelAttr>()) + if (Target.isValidGCCRegisterName(Attr->getLabel())) + return Target.getNormalizedGCCRegisterName(Attr->getLabel(), true); + } + } + return ""; +} + +// Checks if there is a conflict between the input and output lists with the +// clobbers list. If there's a conflict, returns the location of the +// conflicted clobber, else returns nullptr +static SourceLocation +getClobberConflictLocation(MultiExprArg Exprs, StringLiteral **Constraints, + StringLiteral **Clobbers, int NumClobbers, + const TargetInfo &Target, ASTContext &Cont) { + llvm::StringSet<> InOutVars; + // Collect all the input and output registers from the extended asm + // statement + // in order to check for conflicts with the clobber list + for (int i = 0; i < Exprs.size(); ++i) { + StringRef Constraint = Constraints[i]->getString(); + StringRef InOutReg = Target.getConstraintRegister( + Constraint, extractRegisterName(Exprs[i], Target)); + if (InOutReg != "") + InOutVars.insert(InOutReg); + } + // Check for each item in the clobber list if it conflicts with the input + // or output + for (int i = 0; i < NumClobbers; ++i) { + StringRef Clobber = Clobbers[i]->getString(); + // We only check registers, therefore we don't check cc and memory + // clobbers + if (Clobber == "cc" || Clobber == "memory") + continue; + Clobber = Target.getNormalizedGCCRegisterName(Clobber, true); + // Go over the output's registers we collected + if (InOutVars.count(Clobber)) + return Clobbers[i]->getLocStart(); + } + return SourceLocation(); +} + StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, bool IsVolatile, unsigned NumOutputs, unsigned NumInputs, IdentifierInfo **Names, @@ -543,6 +595,13 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, return StmtError(); } + // Check for conflicts between clobber list and input or output lists + SourceLocation ConstraintLoc = + getClobberConflictLocation(Exprs, Constraints, Clobbers, NumClobbers, + Context.getTargetInfo(), Context); + if (ConstraintLoc.isValid()) + return Diag(ConstraintLoc, diag::error_inoutput_conflict_with_clobber); + return NS; } |