[llvm-commits] CVS: llvm/lib/CodeGen/AsmPrinter.cpp

Chris Lattner lattner at cs.uiuc.edu
Wed Feb 1 14:41:23 PST 2006



Changes in directory llvm/lib/CodeGen:

AsmPrinter.cpp updated: 1.44 -> 1.45
---
Log message:

Implement smart printing of inline asm strings, handling variants and 
substituted operands.  For this testcase:

int %test(int %A, int %B) {
  %C = call int asm "xyz $0, $1, $2", "=r,r,r"(int %A, int %B)
  ret int %C
}

we now emit:

_test:
        or r2, r3, r3
        or r3, r4, r4
        xyz r2, r2, r3  ;; look here
        or r3, r2, r2
        blr

... note the substituted operands. :)



---
Diffs of the changes:  (+112 -5)

 AsmPrinter.cpp |  117 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 112 insertions(+), 5 deletions(-)


Index: llvm/lib/CodeGen/AsmPrinter.cpp
diff -u llvm/lib/CodeGen/AsmPrinter.cpp:1.44 llvm/lib/CodeGen/AsmPrinter.cpp:1.45
--- llvm/lib/CodeGen/AsmPrinter.cpp:1.44	Tue Jan 31 19:28:23 2006
+++ llvm/lib/CodeGen/AsmPrinter.cpp	Wed Feb  1 16:41:11 2006
@@ -20,6 +20,7 @@
 #include "llvm/Support/MathExtras.h"
 #include "llvm/Target/TargetMachine.h"
 #include <iostream>
+#include <cerrno>
 using namespace llvm;
 
 AsmPrinter::AsmPrinter(std::ostream &o, TargetMachine &tm)
@@ -468,12 +469,118 @@
     assert(NumDefs != NumOperands-1 && "No asm string?");
   
   assert(MI->getOperand(NumDefs).isExternalSymbol() && "No asm string?");
-  
+
+  // Disassemble the AsmStr, printing out the literal pieces, the operands, etc.
   const char *AsmStr = MI->getOperand(NumDefs).getSymbolName();
+
+  // The variant of the current asmprinter: FIXME: change.
+  int AsmPrinterVariant = 0;
   
-  O << AsmStr << "\n";
-  
-  // Use a virtual "printAsmOperand" method, which takes the constraint
-  // string?  Must pass the constraint string to here if needed.
+  int CurVariant = -1;            // The number of the {.|.|.} region we are in.
+  const char *LastEmitted = AsmStr; // One past the last character emitted.
   
+  while (*LastEmitted) {
+    switch (*LastEmitted) {
+    default: {
+      // Not a special case, emit the string section literally.
+      const char *LiteralEnd = LastEmitted+1;
+      while (*LiteralEnd && *LiteralEnd != '{' && *LiteralEnd != '|' &&
+             *LiteralEnd != '}' && *LiteralEnd != '$')
+        ++LiteralEnd;
+      if (CurVariant == -1 || CurVariant == AsmPrinterVariant)
+        O.write(LastEmitted, LiteralEnd-LastEmitted);
+      LastEmitted = LiteralEnd;
+      break;
+    }
+    case '$': {
+      ++LastEmitted;   // Consume '$' character.
+      if (*LastEmitted == '$') { // $$ -> $
+        if (CurVariant == -1 || CurVariant == AsmPrinterVariant)
+          O << '$';
+        ++LastEmitted;  // Consume second '$' character.
+        break;
+      }
+      
+      bool HasCurlyBraces = false;
+      if (*LastEmitted == '{') {     // ${variable}
+        ++LastEmitted;               // Consume '{' character.
+        HasCurlyBraces = true;
+      }
+      
+      const char *IDStart = LastEmitted;
+      char *IDEnd;
+      long Val = strtol(IDStart, &IDEnd, 10); // We only accept numbers for IDs.
+      if (!isdigit(*IDStart) || (Val == 0 && errno == EINVAL)) {
+        std::cerr << "Bad $ operand number in inline asm string: '" 
+                  << AsmStr << "'\n";
+        exit(1);
+      }
+      LastEmitted = IDEnd;
+      
+      if (HasCurlyBraces) {
+        if (*LastEmitted != '}') {
+          std::cerr << "Bad ${} expression in inline asm string: '" 
+                    << AsmStr << "'\n";
+          exit(1);
+        }
+        ++LastEmitted;    // Consume '}' character.
+      }
+      
+      if ((unsigned)Val >= NumOperands-1) {
+        std::cerr << "Invalid $ operand number in inline asm string: '" 
+                  << AsmStr << "'\n";
+        exit(1);
+      }
+      
+      // Okay, we finally have an operand number.  Ask the target to print this
+      // operand!
+      if (CurVariant == -1 || CurVariant == AsmPrinterVariant)
+        if (const_cast<AsmPrinter*>(this)->
+                PrintAsmOperand(MI, Val+1, AsmPrinterVariant)) {
+          std::cerr << "Invalid operand found in inline asm: '"
+                    << AsmStr << "'\n";
+          MI->dump();
+          exit(1);
+        }
+      break;
+    }
+    case '{':
+      ++LastEmitted;      // Consume '{' character.
+      if (CurVariant != -1) {
+        std::cerr << "Nested variants found in inline asm string: '"
+                  << AsmStr << "'\n";
+        exit(1);
+      }
+      CurVariant = 0;     // We're in the first variant now.
+      break;
+    case '|':
+      ++LastEmitted;  // consume '|' character.
+      if (CurVariant == -1) {
+        std::cerr << "Found '|' character outside of variant in inline asm "
+                  << "string: '" << AsmStr << "'\n";
+        exit(1);
+      }
+      ++CurVariant;   // We're in the next variant.
+      break;
+    case '}':
+      ++LastEmitted;  // consume '}' character.
+      if (CurVariant == -1) {
+        std::cerr << "Found '}' character outside of variant in inline asm "
+                  << "string: '" << AsmStr << "'\n";
+        exit(1);
+      }
+      CurVariant = -1;
+      break;
+    }
+  }
+  O << "\n";
+}
+
+/// PrintAsmOperand - Print the specified operand of MI, an INLINEASM
+/// instruction, using the specified assembler variant.  Targets should
+/// overried this to format as appropriate.
+bool AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
+                                 unsigned AsmVariant) {
+  // Target doesn't support this yet!
+  return true;
 }






More information about the llvm-commits mailing list