зеркало из https://github.com/microsoft/clang-1.git
Add more semantic analysis for inline asm statements.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@44349 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
427d5af5b6
Коммит
d04c6e23f2
|
@ -314,3 +314,127 @@ bool TargetInfo::isValidGCCRegisterName(const char *Name) const {
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *TargetInfo::getNormalizedGCCRegisterName(const char *Name) const
|
||||
{
|
||||
assert(isValidGCCRegisterName(Name) && "Invalid register passed in");
|
||||
|
||||
const char * const *Names;
|
||||
unsigned NumNames;
|
||||
|
||||
PrimaryTarget->getGCCRegNames(Names, NumNames);
|
||||
|
||||
// First, check if we have a number.
|
||||
if (isdigit(Name[0])) {
|
||||
char *End;
|
||||
int n = (int)strtol(Name, &End, 0);
|
||||
if (*End == 0) {
|
||||
assert(n >= 0 && (unsigned)n < NumNames &&
|
||||
"Out of bounds register number!");
|
||||
return Names[n];
|
||||
}
|
||||
}
|
||||
|
||||
// Now check aliases.
|
||||
const TargetInfoImpl::GCCRegAlias *Aliases;
|
||||
unsigned NumAliases;
|
||||
|
||||
PrimaryTarget->getGCCRegAliases(Aliases, NumAliases);
|
||||
for (unsigned i = 0; i < NumAliases; i++) {
|
||||
for (unsigned j = 0 ; j < llvm::array_lengthof(Aliases[i].Aliases); j++) {
|
||||
if (!Aliases[i].Aliases[j])
|
||||
break;
|
||||
if (strcmp(Aliases[i].Aliases[j], Name) == 0)
|
||||
return Aliases[i].Register;
|
||||
}
|
||||
}
|
||||
|
||||
return Name;
|
||||
}
|
||||
|
||||
bool TargetInfo::validateOutputConstraint(const char *Name,
|
||||
ConstraintInfo &info) const
|
||||
{
|
||||
// An output constraint must start with '=' or '+'
|
||||
if (*Name != '=' && *Name != '+')
|
||||
return false;
|
||||
|
||||
if (*Name == '+')
|
||||
info = CI_ReadWrite;
|
||||
else
|
||||
info = CI_None;
|
||||
|
||||
Name++;
|
||||
while (*Name) {
|
||||
switch (*Name) {
|
||||
default:
|
||||
if (!PrimaryTarget->validateAsmConstraint(*Name, info)) {
|
||||
// FIXME: This assert is in place temporarily
|
||||
// so we can add more constraints as we hit it.
|
||||
// Eventually, an unknown constraint should just be treated as 'g'.
|
||||
assert(0 && "Unknown output constraint type!");
|
||||
}
|
||||
case '&': // early clobber.
|
||||
break;
|
||||
case 'r': // general register.
|
||||
info = (ConstraintInfo)(info|CI_AllowsRegister);
|
||||
break;
|
||||
case 'm': // memory operand.
|
||||
info = (ConstraintInfo)(info|CI_AllowsMemory);
|
||||
break;
|
||||
case 'g': // general register, memory operand or immediate integer.
|
||||
info = (ConstraintInfo)(info|CI_AllowsMemory|CI_AllowsRegister);
|
||||
break;
|
||||
}
|
||||
|
||||
Name++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TargetInfo::validateInputConstraint(const char *Name,
|
||||
unsigned NumOutputs,
|
||||
ConstraintInfo &info) const
|
||||
{
|
||||
while (*Name) {
|
||||
switch (*Name) {
|
||||
default:
|
||||
// Check if we have a matching constraint
|
||||
if (*Name >= '0' && *Name <= '9') {
|
||||
unsigned i = *Name - '0';
|
||||
|
||||
// Check if matching constraint is out of bounds.
|
||||
if (i >= NumOutputs)
|
||||
return false;
|
||||
} else if (!PrimaryTarget->validateAsmConstraint(*Name, info)) {
|
||||
// FIXME: This assert is in place temporarily
|
||||
// so we can add more constraints as we hit it.
|
||||
// Eventually, an unknown constraint should just be treated as 'g'.
|
||||
assert(0 && "Unknown input constraint type!");
|
||||
}
|
||||
case 'i': // immediate integer.
|
||||
break;
|
||||
case 'r': // general register.
|
||||
info = (ConstraintInfo)(info|CI_AllowsRegister);
|
||||
break;
|
||||
case 'm': // memory operand.
|
||||
info = (ConstraintInfo)(info|CI_AllowsMemory);
|
||||
break;
|
||||
case 'g': // general register, memory operand or immediate integer.
|
||||
info = (ConstraintInfo)(info|CI_AllowsMemory|CI_AllowsRegister);
|
||||
break;
|
||||
}
|
||||
|
||||
Name++;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *TargetInfo::getClobbers() const
|
||||
{
|
||||
return PrimaryTarget->getClobbers();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -397,8 +397,25 @@ namespace PPC {
|
|||
unsigned &NumAliases) {
|
||||
Aliases = GCCRegAliases;
|
||||
NumAliases = llvm::array_lengthof(GCCRegAliases);
|
||||
}
|
||||
}
|
||||
|
||||
static bool validateAsmConstraint(char c,
|
||||
TargetInfo::ConstraintInfo &info) {
|
||||
switch (c) {
|
||||
default: return false;
|
||||
case 'O': // Zero
|
||||
return true;
|
||||
case 'b': // Base register
|
||||
case 'f': // Floating point register
|
||||
info = (TargetInfo::ConstraintInfo)(info|TargetInfo::CI_AllowsRegister);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const char *getClobbers() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // End namespace PPC
|
||||
|
||||
|
||||
|
@ -454,6 +471,29 @@ namespace X86 {
|
|||
NumAliases = llvm::array_lengthof(GCCRegAliases);
|
||||
}
|
||||
|
||||
static bool validateAsmConstraint(char c,
|
||||
TargetInfo::ConstraintInfo &info) {
|
||||
switch (c) {
|
||||
default: return false;
|
||||
case 'a': // eax.
|
||||
case 'b': // ebx.
|
||||
case 'c': // ecx.
|
||||
case 'd': // edx.
|
||||
case 'S': // esi.
|
||||
case 'D': // edi.
|
||||
case 'A': // edx:eax.
|
||||
case 't': // top of floating point stack.
|
||||
case 'u': // second from top of floating point stack.
|
||||
case 'q': // a, b, c, d registers or any integer register in 64-bit.
|
||||
info = (TargetInfo::ConstraintInfo)(info|TargetInfo::CI_AllowsRegister);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
const char *getClobbers() {
|
||||
return "~{dirflag},~{fpsr},~{flags}";
|
||||
}
|
||||
|
||||
} // End namespace X86
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -483,6 +523,13 @@ public:
|
|||
unsigned &NumAliases) const {
|
||||
PPC::getGCCRegAliases(Aliases, NumAliases);
|
||||
}
|
||||
virtual bool validateAsmConstraint(char c,
|
||||
TargetInfo::ConstraintInfo &info) const {
|
||||
return PPC::validateAsmConstraint(c, info);
|
||||
}
|
||||
virtual const char *getClobbers() const {
|
||||
return PPC::getClobbers();
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace.
|
||||
|
||||
|
@ -508,6 +555,13 @@ public:
|
|||
unsigned &NumAliases) const {
|
||||
PPC::getGCCRegAliases(Aliases, NumAliases);
|
||||
}
|
||||
virtual bool validateAsmConstraint(char c,
|
||||
TargetInfo::ConstraintInfo &info) const {
|
||||
return PPC::validateAsmConstraint(c, info);
|
||||
}
|
||||
virtual const char *getClobbers() const {
|
||||
return PPC::getClobbers();
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace.
|
||||
|
||||
|
@ -533,6 +587,13 @@ public:
|
|||
unsigned &NumAliases) const {
|
||||
X86::getGCCRegAliases(Aliases, NumAliases);
|
||||
}
|
||||
virtual bool validateAsmConstraint(char c,
|
||||
TargetInfo::ConstraintInfo &info) const {
|
||||
return X86::validateAsmConstraint(c, info);
|
||||
}
|
||||
virtual const char *getClobbers() const {
|
||||
return X86::getClobbers();
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace.
|
||||
|
||||
|
@ -558,6 +619,13 @@ public:
|
|||
unsigned &NumAliases) const {
|
||||
X86::getGCCRegAliases(Aliases, NumAliases);
|
||||
}
|
||||
virtual bool validateAsmConstraint(char c,
|
||||
TargetInfo::ConstraintInfo &info) const {
|
||||
return X86::validateAsmConstraint(c, info);
|
||||
}
|
||||
virtual const char *getClobbers() const {
|
||||
return X86::getClobbers();
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace.
|
||||
|
||||
|
@ -589,6 +657,13 @@ public:
|
|||
unsigned &NumAliases) const {
|
||||
X86::getGCCRegAliases(Aliases, NumAliases);
|
||||
}
|
||||
virtual bool validateAsmConstraint(char c,
|
||||
TargetInfo::ConstraintInfo &info) const {
|
||||
return X86::validateAsmConstraint(c, info);
|
||||
}
|
||||
virtual const char *getClobbers() const {
|
||||
return X86::getClobbers();
|
||||
}
|
||||
};
|
||||
} // end anonymous namespace.
|
||||
|
||||
|
|
|
@ -659,11 +659,26 @@ Sema::StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
|
|||
SourceLocation RParenLoc) {
|
||||
Expr *E = (Expr *)AsmString;
|
||||
|
||||
// Check that the output exprs are valid lvalues.
|
||||
for (unsigned i = 0; i < NumOutputs; i++) {
|
||||
StringLiteral *Literal = cast<StringLiteral>((Expr *)Constraints[i]);
|
||||
assert(!Literal->isWide() &&
|
||||
"Output constraint strings should not be wide!");
|
||||
|
||||
std::string OutputConstraint(Literal->getStrData(),
|
||||
Literal->getByteLength());
|
||||
|
||||
TargetInfo::ConstraintInfo info;
|
||||
if (!Context.Target.validateOutputConstraint(OutputConstraint.c_str(),
|
||||
info)) {
|
||||
// FIXME: We currently leak memory here.
|
||||
Diag(Literal->getLocStart(),
|
||||
diag::err_invalid_output_constraint_in_asm);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check that the output exprs are valid lvalues.
|
||||
Expr *OutputExpr = (Expr *)Exprs[i];
|
||||
Expr::isLvalueResult Result = OutputExpr->isLvalue();
|
||||
|
||||
if (Result != Expr::LV_Valid) {
|
||||
ParenExpr *PE = cast<ParenExpr>(OutputExpr);
|
||||
|
||||
|
@ -676,10 +691,26 @@ Sema::StmtResult Sema::ActOnAsmStmt(SourceLocation AsmLoc,
|
|||
}
|
||||
}
|
||||
|
||||
// Check that the input exprs aren't of type void.
|
||||
for (unsigned i = NumOutputs, e = NumOutputs + NumInputs; i != e; i++) {
|
||||
Expr *InputExpr = (Expr *)Exprs[i];
|
||||
StringLiteral *Literal = cast<StringLiteral>((Expr *)Constraints[i]);
|
||||
assert(!Literal->isWide() &&
|
||||
"Output constraint strings should not be wide!");
|
||||
|
||||
std::string InputConstraint(Literal->getStrData(),
|
||||
Literal->getByteLength());
|
||||
|
||||
TargetInfo::ConstraintInfo info;
|
||||
if (!Context.Target.validateInputConstraint(InputConstraint.c_str(),
|
||||
NumOutputs,
|
||||
info)) {
|
||||
// FIXME: We currently leak memory here.
|
||||
Diag(Literal->getLocStart(),
|
||||
diag::err_invalid_input_constraint_in_asm);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Check that the input exprs aren't of type void.
|
||||
Expr *InputExpr = (Expr *)Exprs[i];
|
||||
if (InputExpr->getType()->isVoidType()) {
|
||||
ParenExpr *PE = cast<ParenExpr>(InputExpr);
|
||||
|
||||
|
|
|
@ -735,8 +735,11 @@ public:
|
|||
unsigned getNumOutputs() const { return NumOutputs; }
|
||||
const std::string &getOutputName(unsigned i) const
|
||||
{ return Names[i]; }
|
||||
const StringLiteral *getOutputConstraint(unsigned i) const
|
||||
{ return Constraints[i]; }
|
||||
StringLiteral *getOutputConstraint(unsigned i)
|
||||
{ return Constraints[i]; }
|
||||
const Expr *getOutputExpr(unsigned i) const { return Exprs[i]; }
|
||||
Expr *getOutputExpr(unsigned i) { return Exprs[i]; }
|
||||
|
||||
unsigned getNumInputs() const { return NumInputs; }
|
||||
|
@ -744,13 +747,17 @@ public:
|
|||
{ return Names[i + NumOutputs]; }
|
||||
StringLiteral *getInputConstraint(unsigned i)
|
||||
{ return Constraints[i + NumOutputs]; }
|
||||
const StringLiteral *getInputConstraint(unsigned i) const
|
||||
{ return Constraints[i + NumOutputs]; }
|
||||
Expr *getInputExpr(unsigned i) { return Exprs[i + NumOutputs]; }
|
||||
|
||||
const Expr *getInputExpr(unsigned i) const { return Exprs[i + NumOutputs]; }
|
||||
|
||||
const StringLiteral *getAsmString() const { return AsmStr; }
|
||||
StringLiteral *getAsmString() { return AsmStr; }
|
||||
|
||||
unsigned getNumClobbers() const { return Clobbers.size(); }
|
||||
StringLiteral *getClobber(unsigned i) { return Clobbers[i]; }
|
||||
const StringLiteral *getClobber(unsigned i) const { return Clobbers[i]; }
|
||||
|
||||
virtual SourceRange getSourceRange() const {
|
||||
return SourceRange(AsmLoc, RParenLoc);
|
||||
|
|
|
@ -791,6 +791,10 @@ DIAG(err_pascal_string_too_long, ERROR,
|
|||
"Pascal string is too long")
|
||||
DIAG(err_invalid_lvalue_in_asm_output, ERROR,
|
||||
"invalid lvalue in asm output")
|
||||
DIAG(err_invalid_output_constraint_in_asm, ERROR,
|
||||
"invalid output constraint in asm")
|
||||
DIAG(err_invalid_input_constraint_in_asm, ERROR,
|
||||
"invalid input constraint in asm")
|
||||
DIAG(err_invalid_type_in_asm_input, ERROR,
|
||||
"invalid type '%0' in asm input")
|
||||
DIAG(err_unknown_register_name_in_asm, ERROR,
|
||||
|
|
|
@ -191,7 +191,28 @@ public:
|
|||
/// is a valid register name according to GCC. This is used by Sema for
|
||||
/// inline asm statements.
|
||||
bool isValidGCCRegisterName(const char *Name) const;
|
||||
|
||||
|
||||
// getNormalizedGCCRegisterName - Returns the "normalized" GCC register name.
|
||||
// For example, on x86 it will return "ax" when "eax" is passed in.
|
||||
const char *getNormalizedGCCRegisterName(const char *Name) const;
|
||||
|
||||
enum ConstraintInfo {
|
||||
CI_None = 0x00,
|
||||
CI_AllowsMemory = 0x01,
|
||||
CI_AllowsRegister = 0x02,
|
||||
CI_ReadWrite = 0x03
|
||||
};
|
||||
|
||||
// validateOutputConstraint, validateInputConstraint - Checks that
|
||||
// a constraint is valid and provides information about it.
|
||||
// FIXME: These should return a real error instead of just true/false.
|
||||
bool validateOutputConstraint(const char *Name, ConstraintInfo &Info) const;
|
||||
bool validateInputConstraint (const char *Name, unsigned NumOutputs,
|
||||
ConstraintInfo &info) const;
|
||||
|
||||
// Returns a string of target-specific clobbers, in LLVM format.
|
||||
const char *getClobbers() const;
|
||||
|
||||
///===---- Some helper methods ------------------------------------------===//
|
||||
|
||||
unsigned getCharWidth(SourceLocation Loc) {
|
||||
|
@ -287,6 +308,10 @@ public:
|
|||
virtual void getGCCRegAliases(const GCCRegAlias *&Aliases,
|
||||
unsigned &NumAliases) const = 0;
|
||||
|
||||
virtual bool validateAsmConstraint(char c,
|
||||
TargetInfo::ConstraintInfo &info) const= 0;
|
||||
|
||||
virtual const char *getClobbers() const = 0;
|
||||
private:
|
||||
virtual void ANCHOR(); // out-of-line virtual method for class.
|
||||
};
|
||||
|
|
Загрузка…
Ссылка в новой задаче