[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