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:
Anders Carlsson 2007-11-27 04:11:28 +00:00
Родитель 427d5af5b6
Коммит d04c6e23f2
6 изменённых файлов: 273 добавлений и 7 удалений

Просмотреть файл

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