diff options
-rw-r--r-- | clang/include/clang/Basic/DiagnosticGroups.td | 6 | ||||
-rw-r--r-- | clang/include/clang/Basic/DiagnosticSemaKinds.td | 10 | ||||
-rw-r--r-- | clang/include/clang/Basic/TargetInfo.h | 5 | ||||
-rw-r--r-- | clang/lib/Basic/Targets.cpp | 24 | ||||
-rw-r--r-- | clang/lib/Sema/SemaStmtAsm.cpp | 48 | ||||
-rw-r--r-- | clang/test/CodeGen/arm-asm-warn.c | 18 |
6 files changed, 107 insertions, 4 deletions
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index ec4deaafbec..16356336f13 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -481,3 +481,9 @@ def ObjCStringComparison : DiagGroup<"objc-string-compare">; def ObjCLiteralComparison : DiagGroup<"objc-literal-compare", [ ObjCStringComparison ]>; + +// Inline ASM warnings. +def ASMOperandWidths : DiagGroup<"asm-operand-widths">; +def ASM : DiagGroup<"asm", [ + ASMOperandWidths + ]>; diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 56cb2060421..97a31c16838 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -5136,18 +5136,20 @@ let CategoryName = "Inline Assembly Issue" in { "%diff{$ matching output with type $|}0,1">; def err_asm_unknown_register_name : Error<"unknown register name '%0' in asm">; def err_asm_empty : Error<"__asm used with no assembly instructions">; - def warn_asm_label_on_auto_decl : Warning< - "ignored asm label '%0' on automatic variable">; def err_invalid_asm_cast_lvalue : Error< "invalid use of a cast in a inline asm context requiring an l-value: " "remove the cast or build with -fheinous-gnu-extensions">; + def err_inline_ms_asm_parsing : Error<"%0">; + def warn_asm_label_on_auto_decl : Warning< + "ignored asm label '%0' on automatic variable">; def warn_invalid_asm_cast_lvalue : Warning< "invalid use of a cast in a inline asm context requiring an l-value: " "accepted due to -fheinous-gnu-extensions, but clang may remove support " "for this in the future">; - - def err_inline_ms_asm_parsing : Error<"%0">; + def warn_asm_mismatched_size_modifier : Warning< + "the size being stored is truncated, use a modifier to specify the size">, + InGroup<ASMOperandWidths>; } let CategoryName = "Semantic Issue" in { diff --git a/clang/include/clang/Basic/TargetInfo.h b/clang/include/clang/Basic/TargetInfo.h index ea520e8f828..b0e58050d5d 100644 --- a/clang/include/clang/Basic/TargetInfo.h +++ b/clang/include/clang/Basic/TargetInfo.h @@ -517,6 +517,11 @@ public: bool validateInputConstraint(ConstraintInfo *OutputConstraints, unsigned NumOutputs, ConstraintInfo &info) const; + virtual bool validateConstraintModifier(StringRef /*Constraint*/, + const char /*Modifier*/, + unsigned /*Size*/) const { + return true; + } bool resolveSymbolicName(const char *&Name, ConstraintInfo *OutputConstraints, unsigned NumOutputs, unsigned &Index) const; diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp index 9b758d1c212..1ab151e5efd 100644 --- a/clang/lib/Basic/Targets.cpp +++ b/clang/lib/Basic/Targets.cpp @@ -3315,6 +3315,30 @@ public: } return R; } + virtual bool validateConstraintModifier(StringRef Constraint, + const char Modifier, + unsigned Size) const { + // Strip off constraint modifiers. + while (Constraint[0] == '=' || + Constraint[0] == '+' || + Constraint[0] == '&') + Constraint = Constraint.substr(1); + + switch (Constraint[0]) { + default: break; + case 'r': { + switch (Modifier) { + default: + return Size == 32; + case 'q': + // A register of size 32 cannot fit a vector type. + return false; + } + } + } + + return true; + } virtual const char *getClobbers() const { // FIXME: Is this really right? return ""; diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp index 8e6b81472f8..7c2c766e461 100644 --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -209,6 +209,54 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, return StmtError(); } + // Validate constraints and modifiers. + for (unsigned i = 0, e = Pieces.size(); i != e; ++i) { + GCCAsmStmt::AsmStringPiece &Piece = Pieces[i]; + if (!Piece.isOperand()) continue; + + // Look for the correct constraint index. + unsigned Idx = 0; + unsigned ConstraintIdx = 0; + for (unsigned i = 0, e = NS->getNumOutputs(); i != e; ++i, ++ConstraintIdx) { + TargetInfo::ConstraintInfo &Info = OutputConstraintInfos[i]; + if (Idx == Piece.getOperandNo()) + break; + ++Idx; + + if (Info.isReadWrite()) { + if (Idx == Piece.getOperandNo()) + break; + ++Idx; + } + } + + for (unsigned i = 0, e = NS->getNumInputs(); i != e; ++i, ++ConstraintIdx) { + TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i]; + if (Idx == Piece.getOperandNo()) + break; + ++Idx; + + if (Info.isReadWrite()) { + if (Idx == Piece.getOperandNo()) + break; + ++Idx; + } + } + + // Now that we have the right indexes go ahead and check. + StringLiteral *Literal = Constraints[ConstraintIdx]; + const Type *Ty = Exprs[ConstraintIdx]->getType().getTypePtr(); + if (Ty->isDependentType() || Ty->isIncompleteType()) + continue; + + unsigned Size = Context.getTypeSize(Ty); + if (!Context.getTargetInfo() + .validateConstraintModifier(Literal->getString(), Piece.getModifier(), + Size)) + Diag(Exprs[ConstraintIdx]->getLocStart(), + diag::warn_asm_mismatched_size_modifier); + } + // Validate tied input operands for type mismatches. for (unsigned i = 0, e = InputConstraintInfos.size(); i != e; ++i) { TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i]; diff --git a/clang/test/CodeGen/arm-asm-warn.c b/clang/test/CodeGen/arm-asm-warn.c new file mode 100644 index 00000000000..0c4e97aba0d --- /dev/null +++ b/clang/test/CodeGen/arm-asm-warn.c @@ -0,0 +1,18 @@ +// REQUIRES: arm-registered-target +// RUN: %clang_cc1 -triple armv7 %s -emit-llvm -o /dev/null +// <rdar://problem/12284092> + +typedef __attribute__((neon_vector_type(2))) long long int64x2_t; +typedef struct int64x2x4_t { + int64x2_t val[4]; +} int64x2x4_t; +int64x2x4_t t2(const long long a[]) { + int64x2x4_t r; + __asm__("vldm %[a], { %q[r0], %q[r1], %q[r2], %q[r3] }" + : [r0] "=r"(r.val[0]), // expected-warning {{the size being stored is truncated, use a modifier to specify the size}} + [r1] "=r"(r.val[1]), // expected-warning {{the size being stored is truncated, use a modifier to specify the size}} + [r2] "=r"(r.val[2]), // expected-warning {{the size being stored is truncated, use a modifier to specify the size}} + [r3] "=r"(r.val[3]) // expected-warning {{the size being stored is truncated, use a modifier to specify the size}} + : [a] "r"(a)); + return r; +} |