Sema: analyze I,J,K,M,N,O constraints

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.

llvm-svn: 225244
This commit is contained in:
Saleem Abdulrasool 2015-01-06 04:26:34 +00:00
parent 0f2c4ac649
commit a2823578e6
6 changed files with 198 additions and 4 deletions

View 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">;

View 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.

View 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();

View 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;

View 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())

View File

@ -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
}