[cfe-commits] r44349 - in /cfe/trunk: Basic/TargetInfo.cpp Driver/Targets.cpp Sema/SemaStmt.cpp include/clang/AST/Stmt.h include/clang/Basic/DiagnosticKinds.def include/clang/Basic/TargetInfo.h
Anders Carlsson
andersca at mac.com
Mon Nov 26 20:11:31 PST 2007
Author: andersca
Date: Mon Nov 26 22:11:28 2007
New Revision: 44349
URL: http://llvm.org/viewvc/llvm-project?rev=44349&view=rev
Log:
Add more semantic analysis for inline asm statements.
Modified:
cfe/trunk/Basic/TargetInfo.cpp
cfe/trunk/Driver/Targets.cpp
cfe/trunk/Sema/SemaStmt.cpp
cfe/trunk/include/clang/AST/Stmt.h
cfe/trunk/include/clang/Basic/DiagnosticKinds.def
cfe/trunk/include/clang/Basic/TargetInfo.h
Modified: cfe/trunk/Basic/TargetInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Basic/TargetInfo.cpp?rev=44349&r1=44348&r2=44349&view=diff
==============================================================================
--- cfe/trunk/Basic/TargetInfo.cpp (original)
+++ cfe/trunk/Basic/TargetInfo.cpp Mon Nov 26 22:11:28 2007
@@ -314,3 +314,127 @@
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();
+}
+
+
Modified: cfe/trunk/Driver/Targets.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Driver/Targets.cpp?rev=44349&r1=44348&r2=44349&view=diff
==============================================================================
--- cfe/trunk/Driver/Targets.cpp (original)
+++ cfe/trunk/Driver/Targets.cpp Mon Nov 26 22:11:28 2007
@@ -397,8 +397,25 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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.
Modified: cfe/trunk/Sema/SemaStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/Sema/SemaStmt.cpp?rev=44349&r1=44348&r2=44349&view=diff
==============================================================================
--- cfe/trunk/Sema/SemaStmt.cpp (original)
+++ cfe/trunk/Sema/SemaStmt.cpp Mon Nov 26 22:11:28 2007
@@ -659,11 +659,26 @@
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 @@
}
}
- // 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);
Modified: cfe/trunk/include/clang/AST/Stmt.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Stmt.h?rev=44349&r1=44348&r2=44349&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Stmt.h (original)
+++ cfe/trunk/include/clang/AST/Stmt.h Mon Nov 26 22:11:28 2007
@@ -735,8 +735,11 @@
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 @@
{ 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);
Modified: cfe/trunk/include/clang/Basic/DiagnosticKinds.def
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticKinds.def?rev=44349&r1=44348&r2=44349&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/DiagnosticKinds.def (original)
+++ cfe/trunk/include/clang/Basic/DiagnosticKinds.def Mon Nov 26 22:11:28 2007
@@ -791,6 +791,10 @@
"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,
Modified: cfe/trunk/include/clang/Basic/TargetInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/TargetInfo.h?rev=44349&r1=44348&r2=44349&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/TargetInfo.h (original)
+++ cfe/trunk/include/clang/Basic/TargetInfo.h Mon Nov 26 22:11:28 2007
@@ -191,7 +191,28 @@
/// 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 @@
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.
};
More information about the cfe-commits
mailing list