diff options
Diffstat (limited to 'clang/lib')
-rw-r--r-- | clang/lib/AST/Stmt.cpp | 46 | ||||
-rw-r--r-- | clang/lib/Basic/Targets.cpp | 19 | ||||
-rw-r--r-- | clang/lib/Sema/SemaStmtAsm.cpp | 17 |
3 files changed, 67 insertions, 15 deletions
diff --git a/clang/lib/AST/Stmt.cpp b/clang/lib/AST/Stmt.cpp index d12642ddfc0..c80e0ef067a 100644 --- a/clang/lib/AST/Stmt.cpp +++ b/clang/lib/AST/Stmt.cpp @@ -357,6 +357,11 @@ unsigned AsmStmt::getNumPlusOperands() const { return Res; } +char GCCAsmStmt::AsmStringPiece::getModifier() const { + assert(isOperand() && "Only Operands can have modifiers."); + return isLetter(Str[0]) ? Str[0] : '\0'; +} + StringRef GCCAsmStmt::getClobber(unsigned i) const { return getClobberStringLiteral(i)->getString(); } @@ -517,17 +522,25 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces, CurStringPiece.clear(); } - // Handle %x4 and %x[foo] by capturing x as the modifier character. - char Modifier = '\0'; + // Handle operands that have asmSymbolicName (e.g., %x[foo]) and those that + // don't (e.g., %x4). 'x' following the '%' is the constraint modifier. + + const char *Begin = CurPtr - 1; // Points to the character following '%'. + const char *Percent = Begin - 1; // Points to '%'. + if (isLetter(EscapedChar)) { if (CurPtr == StrEnd) { // Premature end. DiagOffs = CurPtr-StrStart-1; return diag::err_asm_invalid_escape; } - Modifier = EscapedChar; EscapedChar = *CurPtr++; } + const TargetInfo &TI = C.getTargetInfo(); + const SourceManager &SM = C.getSourceManager(); + const LangOptions &LO = C.getLangOpts(); + + // Handle operands that don't have asmSymbolicName (e.g., %x4). if (isDigit(EscapedChar)) { // %n - Assembler operand n unsigned N = 0; @@ -543,11 +556,21 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces, return diag::err_asm_invalid_operand_number; } - Pieces.push_back(AsmStringPiece(N, Modifier)); + // Str contains "x4" (Operand without the leading %). + std::string Str(Begin, CurPtr - Begin); + + // (BeginLoc, EndLoc) represents the range of the operand we are currently + // processing. Unlike Str, the range includes the leading '%'. + SourceLocation BeginLoc = + getAsmString()->getLocationOfByte(Percent - StrStart, SM, LO, TI); + SourceLocation EndLoc = + getAsmString()->getLocationOfByte(CurPtr - StrStart, SM, LO, TI); + + Pieces.push_back(AsmStringPiece(N, Str, BeginLoc, EndLoc)); continue; } - // Handle %[foo], a symbolic operand reference. + // Handle operands that have asmSymbolicName (e.g., %x[foo]). if (EscapedChar == '[') { DiagOffs = CurPtr-StrStart-1; @@ -566,7 +589,18 @@ unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces, DiagOffs = CurPtr-StrStart; return diag::err_asm_unknown_symbolic_operand_name; } - Pieces.push_back(AsmStringPiece(N, Modifier)); + + // Str contains "x[foo]" (Operand without the leading %). + std::string Str(Begin, NameEnd + 1 - Begin); + + // (BeginLoc, EndLoc) represents the range of the operand we are currently + // processing. Unlike Str, the range includes the leading '%'. + SourceLocation BeginLoc = + getAsmString()->getLocationOfByte(Percent - StrStart, SM, LO, TI); + SourceLocation EndLoc = + getAsmString()->getLocationOfByte(NameEnd + 1 - StrStart, SM, LO, TI); + + Pieces.push_back(AsmStringPiece(N, Str, BeginLoc, EndLoc)); CurPtr = NameEnd+1; continue; diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp index d1eba5af470..2e655897220 100644 --- a/clang/lib/Basic/Targets.cpp +++ b/clang/lib/Basic/Targets.cpp @@ -4145,8 +4145,10 @@ public: } return R; } - bool validateConstraintModifier(StringRef Constraint, const char Modifier, - unsigned Size) const override { + bool + validateConstraintModifier(StringRef Constraint, const char Modifier, + unsigned Size, + std::string &SuggestedModifier) const override { bool isOutput = (Constraint[0] == '='); bool isInOut = (Constraint[0] == '+'); @@ -4592,9 +4594,10 @@ public: return false; } - virtual bool validateConstraintModifier(StringRef Constraint, - const char Modifier, - unsigned Size) const { + bool + validateConstraintModifier(StringRef Constraint, const char Modifier, + unsigned Size, + std::string &SuggestedModifier) const override { // Strip off constraint modifiers. while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&') Constraint = Constraint.substr(1); @@ -4613,7 +4616,11 @@ public: default: // By default an 'r' constraint will be in the 'x' // registers. - return Size == 64; + if (Size == 64) + return true; + + SuggestedModifier = "w"; + return false; } } } diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp index 5d076cac940..47a7672ae19 100644 --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -257,11 +257,22 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, continue; unsigned Size = Context.getTypeSize(Ty); - if (!Context.getTargetInfo() - .validateConstraintModifier(Literal->getString(), Piece.getModifier(), - Size)) + std::string SuggestedModifier; + if (!Context.getTargetInfo().validateConstraintModifier( + Literal->getString(), Piece.getModifier(), Size, + SuggestedModifier)) { Diag(Exprs[ConstraintIdx]->getLocStart(), diag::warn_asm_mismatched_size_modifier); + + if (!SuggestedModifier.empty()) { + auto B = Diag(Piece.getRange().getBegin(), + diag::note_asm_missing_constraint_modifier) + << SuggestedModifier; + SuggestedModifier = "%" + SuggestedModifier + Piece.getString(); + B.AddFixItHint(FixItHint::CreateReplacement(Piece.getRange(), + SuggestedModifier)); + } + } } // Validate tied input operands for type mismatches. |