From: Bill Wendling Date: Thu, 25 Oct 2012 23:28:48 +0000 (+0000) Subject: Recommit Eric's code to validate ASM string's constraints and modifiers. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=50d46caf00c743312e0ea1f87a693d504b12ef51;p=clang Recommit Eric's code to validate ASM string's constraints and modifiers. This code checks the ASM string to see if the output size is able to fit within the variable specified as the output. For instance, scalar-to-vector conversions may not really work. It's on by default, but can be turned off with a flag if you think you know what you're doing. This is placed under a flag ('-Wasm-operand-widths') and flag group ('-Wasm'). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@166737 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index ec4deaafbe..16356336f1 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/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/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 56cb206042..97a31c1683 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/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; } let CategoryName = "Semantic Issue" in { diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h index ea520e8f82..b0e58050d5 100644 --- a/include/clang/Basic/TargetInfo.h +++ b/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/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 9b758d1c21..1ab151e5ef 100644 --- a/lib/Basic/Targets.cpp +++ b/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/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp index 8e6b81472f..7c2c766e46 100644 --- a/lib/Sema/SemaStmtAsm.cpp +++ b/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/test/CodeGen/arm-asm-warn.c b/test/CodeGen/arm-asm-warn.c new file mode 100644 index 0000000000..0c4e97aba0 --- /dev/null +++ b/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 +// + +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; +}