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. :)
llvm-svn: 25886
			
			
This commit is contained in:
		
							parent
							
								
									ae8863849b
								
							
						
					
					
						commit
						aa23fa9f43
					
				| 
						 | 
				
			
			@ -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)
 | 
			
		||||
| 
						 | 
				
			
			@ -469,11 +470,117 @@ void AsmPrinter::printInlineAsm(const MachineInstr *MI) const {
 | 
			
		|||
  
 | 
			
		||||
  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();
 | 
			
		||||
 | 
			
		||||
  O << AsmStr << "\n";
 | 
			
		||||
  // The variant of the current asmprinter: FIXME: change.
 | 
			
		||||
  int AsmPrinterVariant = 0;
 | 
			
		||||
  
 | 
			
		||||
  // 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;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue