diff options
-rw-r--r-- | include/clang/Basic/DiagnosticSemaKinds.td | 2 | ||||
-rw-r--r-- | include/clang/Basic/TargetInfo.h | 24 | ||||
-rw-r--r-- | lib/Basic/TargetInfo.cpp | 2 | ||||
-rw-r--r-- | lib/Basic/Targets.cpp | 55 | ||||
-rw-r--r-- | lib/Sema/SemaStmtAsm.cpp | 14 | ||||
-rw-r--r-- | test/Sema/inline-asm-validate-x86.c | 105 |
6 files changed, 198 insertions, 4 deletions
diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 69f86b9692..d3129bd62e 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -6178,6 +6178,8 @@ let CategoryName = "Inline Assembly Issue" in { 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_invalid_asm_value_for_constraint + : Error <"value '%0' out of range for constraint '%1'">; def warn_asm_label_on_auto_decl : Warning< "ignored asm label '%0' on automatic variable">; diff --git a/include/clang/Basic/TargetInfo.h b/include/clang/Basic/TargetInfo.h index f952d6d1d0..0ebd9c8be7 100644 --- a/include/clang/Basic/TargetInfo.h +++ b/include/clang/Basic/TargetInfo.h @@ -528,18 +528,23 @@ public: CI_None = 0x00, CI_AllowsMemory = 0x01, CI_AllowsRegister = 0x02, - CI_ReadWrite = 0x04, // "+r" output constraint (read and write). - CI_HasMatchingInput = 0x08 // This output operand has a matching input. + CI_ReadWrite = 0x04, // "+r" output constraint (read and write). + CI_HasMatchingInput = 0x08, // This output operand has a matching input. + CI_ImmediateConstant = 0x10, // This operand must be an immediate constant }; unsigned Flags; int TiedOperand; + struct { + int Min; + int Max; + } ImmRange; std::string ConstraintStr; // constraint: "=rm" std::string Name; // Operand name: [foo] with no []'s. public: ConstraintInfo(StringRef ConstraintStr, StringRef Name) - : Flags(0), TiedOperand(-1), ConstraintStr(ConstraintStr.str()), - Name(Name.str()) {} + : Flags(0), TiedOperand(-1), ImmRange({0, 0}), + ConstraintStr(ConstraintStr.str()), Name(Name.str()) {} const std::string &getConstraintStr() const { return ConstraintStr; } const std::string &getName() const { return Name; } @@ -562,10 +567,21 @@ public: return (unsigned)TiedOperand; } + bool requiresImmediateConstant() const { + return (Flags & CI_ImmediateConstant) != 0; + } + int getImmConstantMin() const { return ImmRange.Min; } + int getImmConstantMax() const { return ImmRange.Max; } + void setIsReadWrite() { Flags |= CI_ReadWrite; } void setAllowsMemory() { Flags |= CI_AllowsMemory; } void setAllowsRegister() { Flags |= CI_AllowsRegister; } void setHasMatchingInput() { Flags |= CI_HasMatchingInput; } + void setRequiresImmediate(int Min, int Max) { + Flags |= CI_ImmediateConstant; + ImmRange.Min = Min; + ImmRange.Max = Max; + } /// \brief Indicate that this is an input operand that is tied to /// the specified output operand. diff --git a/lib/Basic/TargetInfo.cpp b/lib/Basic/TargetInfo.cpp index a35298067b..f2dc84fa03 100644 --- a/lib/Basic/TargetInfo.cpp +++ b/lib/Basic/TargetInfo.cpp @@ -588,6 +588,8 @@ bool TargetInfo::validateInputConstraint(ConstraintInfo *OutputConstraints, case 'N': case 'O': case 'P': + if (!validateAsmConstraint(Name, Info)) + return false; break; case 'r': // general register. Info.setAllowsRegister(); diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp index 8c79a18d08..c74bb936e3 100644 --- a/lib/Basic/Targets.cpp +++ b/lib/Basic/Targets.cpp @@ -3102,6 +3102,28 @@ X86TargetInfo::validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &Info) const { switch (*Name) { default: return false; + case 'I': + Info.setRequiresImmediate(0, 31); + return true; + case 'J': + Info.setRequiresImmediate(0, 63); + return true; + case 'K': + Info.setRequiresImmediate(-128, 127); + return true; + case 'L': + // FIXME: properly analyze this constraint: + // must be one of 0xff, 0xffff, or 0xffffffff + return true; + case 'M': + Info.setRequiresImmediate(0, 3); + return true; + case 'N': + Info.setRequiresImmediate(0, 255); + return true; + case 'O': + Info.setRequiresImmediate(0, 127); + return true; case 'Y': // first letter of a pair: switch (*(Name+1)) { default: return false; @@ -4289,6 +4311,13 @@ public: case 'P': // VFP Floating point register double precision Info.setAllowsRegister(); return true; + case 'I': + case 'J': + case 'K': + case 'L': + case 'M': + // FIXME + return true; case 'Q': // A memory address that is a single base register. Info.setAllowsMemory(); return true; @@ -5152,6 +5181,16 @@ public: bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const override { // FIXME: Implement! + switch (*Name) { + case 'I': // Signed 13-bit constant + case 'J': // Zero + case 'K': // 32-bit constant with the low 12 bits clear + case 'L': // A constant in the range supported by movcc (11-bit signed imm) + case 'M': // A constant in the range supported by movrcc (19-bit signed imm) + case 'N': // Same as 'K' but zext (required for SIMode) + case 'O': // The constant 4096 + return true; + } return false; } const char *getClobbers() const override { @@ -5444,6 +5483,13 @@ namespace { bool validateAsmConstraint(const char *&Name, TargetInfo::ConstraintInfo &info) const override { + // FIXME: implement + switch (*Name) { + case 'K': // the constant 1 + case 'L': // constant -1^20 .. 1^19 + case 'M': // constant 1-4: + return true; + } // No target constraints for now. return false; } @@ -5740,6 +5786,15 @@ public: case 'x': // hilo register pair Info.setAllowsRegister(); return true; + case 'I': // Signed 16-bit constant + case 'J': // Integer 0 + case 'K': // Unsigned 16-bit constant + case 'L': // Signed 32-bit constant, lower 16-bit zeros (for lui) + case 'M': // Constants not loadable via lui, addiu, or ori + case 'N': // Constant -1 to -65535 + case 'O': // A signed 15-bit constant + case 'P': // A constant between 1 go 65535 + return true; case 'R': // An address that can be used in a non-macro load or store Info.setAllowsMemory(); return true; diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp index afd785c5df..286c7619ed 100644 --- a/lib/Sema/SemaStmtAsm.cpp +++ b/lib/Sema/SemaStmtAsm.cpp @@ -226,6 +226,20 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, diag::err_asm_invalid_lvalue_in_input) << Info.getConstraintStr() << InputExpr->getSourceRange()); + } else if (Info.requiresImmediateConstant() && !Info.allowsRegister()) { + llvm::APSInt Result; + if (!InputExpr->EvaluateAsInt(Result, Context)) + return StmtError( + Diag(InputExpr->getLocStart(), diag::err_asm_invalid_type_in_input) + << InputExpr->getType() << Info.getConstraintStr() + << InputExpr->getSourceRange()); + if (Result.slt(Info.getImmConstantMin()) || + Result.sgt(Info.getImmConstantMax())) + return StmtError(Diag(InputExpr->getLocStart(), + diag::err_invalid_asm_value_for_constraint) + << Result.toString(10) << Info.getConstraintStr() + << InputExpr->getSourceRange()); + } else { ExprResult Result = DefaultFunctionArrayLvalueConversion(Exprs[i]); if (Result.isInvalid()) diff --git a/test/Sema/inline-asm-validate-x86.c b/test/Sema/inline-asm-validate-x86.c new file mode 100644 index 0000000000..174deca80b --- /dev/null +++ b/test/Sema/inline-asm-validate-x86.c @@ -0,0 +1,105 @@ +// RUN: %clang_cc1 -triple i686 -fsyntax-only -verify %s +// RUN: %clang_cc1 -triple x86_64 -fsyntax-only -verify %s + +void I(int i, int j) { + static const int BelowMin = -1; + static const int AboveMax = 32; + __asm__("xorl %0,%2" + : "=r"(i) + : "0"(i), "I"(j)); // expected-error{{invalid type 'int' in asm input for constraint 'I'}} + __asm__("xorl %0,%2" + : "=r"(i) + : "0"(i), "I"(BelowMin)); // expected-error{{value '-1' out of range for constraint 'I'}} + __asm__("xorl %0,%2" + : "=r"(i) + : "0"(i), "I"(AboveMax)); // expected-error{{value '32' out of range for constraint 'I'}} + __asm__("xorl %0,%2" + : "=r"(i) + : "0"(i), "I"(16)); // expected-no-error +} + +void J(int i, int j) { + static const int BelowMin = -1; + static const int AboveMax = 64; + __asm__("xorl %0,%2" + : "=r"(i) + : "0"(i), "J"(j)); // expected-error{{invalid type 'int' in asm input for constraint 'J'}} + __asm__("xorl %0,%2" + : "=r"(i) + : "0"(i), "J"(BelowMin)); // expected-error{{value '-1' out of range for constraint 'J'}} + __asm__("xorl %0,%2" + : "=r"(i) + : "0"(i), "J"(AboveMax)); // expected-error{{value '64' out of range for constraint 'J'}} + __asm__("xorl %0,%2" + : "=r"(i) + : "0"(i), "J"(32)); // expected-no-error +} + +void K(int i, int j) { + static const int BelowMin = -129; + static const int AboveMax = 128; + __asm__("xorl %0,%2" + : "=r"(i) + : "0"(i), "K"(j)); // expected-error{{invalid type 'int' in asm input for constraint 'K'}} + __asm__("xorl %0,%2" + : "=r"(i) + : "0"(i), "K"(BelowMin)); // expected-error{{value '-129' out of range for constraint 'K'}} + __asm__("xorl %0,%2" + : "=r"(i) + : "0"(i), "K"(AboveMax)); // expected-error{{value '128' out of range for constraint 'K'}} + __asm__("xorl %0,%2" + : "=r"(i) + : "0"(i), "K"(96)); // expected-no-error +} + +void M(int i, int j) { + static const int BelowMin = -1; + static const int AboveMax = 4; + __asm__("xorl %0,%2" + : "=r"(i) + : "0"(i), "M"(j)); // expected-error{{invalid type 'int' in asm input for constraint 'M'}} + __asm__("xorl %0,%2" + : "=r"(i) + : "0"(i), "M"(BelowMin)); // expected-error{{value '-1' out of range for constraint 'M'}} + __asm__("xorl %0,%2" + : "=r"(i) + : "0"(i), "M"(AboveMax)); // expected-error{{value '4' out of range for constraint 'M'}} + __asm__("xorl %0,%2" + : "=r"(i) + : "0"(i), "M"(2)); // expected-no-error +} + +void N(int i, int j) { + static const int BelowMin = -1; + static const int AboveMax = 256; + __asm__("xorl %0,%2" + : "=r"(i) + : "0"(i), "N"(j)); // expected-error{{invalid type 'int' in asm input for constraint 'N'}} + __asm__("xorl %0,%2" + : "=r"(i) + : "0"(i), "N"(BelowMin)); // expected-error{{value '-1' out of range for constraint 'N'}} + __asm__("xorl %0,%2" + : "=r"(i) + : "0"(i), "N"(AboveMax)); // expected-error{{value '256' out of range for constraint 'N'}} + __asm__("xorl %0,%2" + : "=r"(i) + : "0"(i), "N"(128)); // expected-no-error +} + +void O(int i, int j) { + static const int BelowMin = -1; + static const int AboveMax = 128; + __asm__("xorl %0,%2" + : "=r"(i) + : "0"(i), "O"(j)); // expected-error{{invalid type 'int' in asm input for constraint 'O'}} + __asm__("xorl %0,%2" + : "=r"(i) + : "0"(i), "O"(BelowMin)); // expected-error{{value '-1' out of range for constraint 'O'}} + __asm__("xorl %0,%2" + : "=r"(i) + : "0"(i), "O"(AboveMax)); // expected-error{{value '128' out of range for constraint 'O'}} + __asm__("xorl %0,%2" + : "=r"(i) + : "0"(i), "O"(64)); // expected-no-error +} + |