summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/clang/Basic/DiagnosticSemaKinds.td2
-rw-r--r--include/clang/Basic/TargetInfo.h24
-rw-r--r--lib/Basic/TargetInfo.cpp2
-rw-r--r--lib/Basic/Targets.cpp55
-rw-r--r--lib/Sema/SemaStmtAsm.cpp14
-rw-r--r--test/Sema/inline-asm-validate-x86.c105
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
+}
+