]> granicus.if.org Git - clang/commitdiff
Sema: analyze I,J,K,M,N,O constraints
authorSaleem Abdulrasool <compnerd@compnerd.org>
Tue, 6 Jan 2015 04:26:34 +0000 (04:26 +0000)
committerSaleem Abdulrasool <compnerd@compnerd.org>
Tue, 6 Jan 2015 04:26:34 +0000 (04:26 +0000)
Add additional constraint checking for target specific behaviour for inline
assembly constraints.  We would previously silently let all arguments through
for these constraints.  In cases where the constraints were violated, we could
end up failing to select instructions and triggering assertions or worse,
silently ignoring instructions.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@225244 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
include/clang/Basic/TargetInfo.h
lib/Basic/TargetInfo.cpp
lib/Basic/Targets.cpp
lib/Sema/SemaStmtAsm.cpp
test/Sema/inline-asm-validate-x86.c [new file with mode: 0644]

index 69f86b9692d48ab2272a97faa4e5d8d9ece8fb15..d3129bd62ecf78434617cb081c868d1368730aff 100644 (file)
@@ -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">;
index f952d6d1d07349581d4fe2038a76cdf25393ae18..0ebd9c8be7df2749b469ee9e03330cca614dba06 100644 (file)
@@ -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. 
index a35298067bd1ccfc610b7e3995a6ed08e761bdc8..f2dc84fa034be9e266f74b1090e743e070eab04c 100644 (file)
@@ -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();
index 8c79a18d08b96e469e4035474e8fc633bebc469a..c74bb936e3a2828fdf9de5dbcd59b16b2caccb17 100644 (file)
@@ -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;
index afd785c5dfb4bb1aec48596e481f4faa13ba47a3..286c7619ed409e5f0c04ba2fe7ce76fda8fcf6c2 100644 (file)
@@ -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 (file)
index 0000000..174deca
--- /dev/null
@@ -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
+}
+