Skip to content
AsmPrinter.cpp 50.3 KiB
Newer Older
    } else if (CFP->getType() == Type::PPC_FP128Ty) {
      // all long double variants are printed as hex
      // api needed to prevent premature destruction
      APInt api = CFP->getValueAPF().convertToAPInt();
      const uint64_t *p = api.getRawData();
      if (TD->isBigEndian()) {
        O << TAI->getData32bitsDirective() << uint32_t(p[0] >> 32)
          << "\t" << TAI->getCommentString()
          << " long double most significant word\n";
        O << TAI->getData32bitsDirective() << uint32_t(p[0])
          << "\t" << TAI->getCommentString()
          << " long double next word\n";
        O << TAI->getData32bitsDirective() << uint32_t(p[1] >> 32)
          << "\t" << TAI->getCommentString()
          << " long double next word\n";
        O << TAI->getData32bitsDirective() << uint32_t(p[1])
          << "\t" << TAI->getCommentString()
          << " long double least significant word\n";
       } else {
        O << TAI->getData32bitsDirective() << uint32_t(p[1])
          << "\t" << TAI->getCommentString()
          << " long double least significant word\n";
        O << TAI->getData32bitsDirective() << uint32_t(p[1] >> 32)
          << "\t" << TAI->getCommentString()
          << " long double next word\n";
        O << TAI->getData32bitsDirective() << uint32_t(p[0])
          << "\t" << TAI->getCommentString()
          << " long double next word\n";
        O << TAI->getData32bitsDirective() << uint32_t(p[0] >> 32)
          << "\t" << TAI->getCommentString()
          << " long double most significant word\n";
      }
      return;
    } else assert(0 && "Floating point constant type not handled");
Reid Spencer's avatar
Reid Spencer committed
  } else if (CV->getType() == Type::Int64Ty) {
    if (const ConstantInt *CI = dyn_cast<ConstantInt>(CV)) {
Reid Spencer's avatar
Reid Spencer committed
      uint64_t Val = CI->getZExtValue();
      if (TAI->getData64bitsDirective())
        O << TAI->getData64bitsDirective() << Val << "\n";
        O << TAI->getData32bitsDirective() << unsigned(Val >> 32)
          << "\t" << TAI->getCommentString()
          << " Double-word most significant word " << Val << "\n";
        O << TAI->getData32bitsDirective() << unsigned(Val)
          << "\t" << TAI->getCommentString()
          << " Double-word least significant word " << Val << "\n";
      } else {
        O << TAI->getData32bitsDirective() << unsigned(Val)
          << "\t" << TAI->getCommentString()
          << " Double-word least significant word " << Val << "\n";
        O << TAI->getData32bitsDirective() << unsigned(Val >> 32)
          << "\t" << TAI->getCommentString()
          << " Double-word most significant word " << Val << "\n";
Reid Spencer's avatar
Reid Spencer committed
  } else if (const ConstantVector *CP = dyn_cast<ConstantVector>(CV)) {
    const VectorType *PTy = CP->getType();
    
    for (unsigned I = 0, E = PTy->getNumElements(); I < E; ++I)
      EmitGlobalConstant(CP->getOperand(I), false);
  }

  const Type *type = CV->getType();
  EmitConstantValueOnly(CV);
  O << "\n";
}
Chris Lattner's avatar
Chris Lattner committed

void
AsmPrinter::EmitMachineConstantPoolValue(MachineConstantPoolValue *MCPV) {
  // Target doesn't support this yet!
  abort();
}

/// PrintSpecial - Print information related to the specified machine instr
/// that is independent of the operand, and may be independent of the instr
/// itself.  This can be useful for portably encoding the comment character
/// or other bits of target-specific knowledge into the asmstrings.  The
/// syntax used is ${:comment}.  Targets can override this to add support
/// for their own strange codes.
void AsmPrinter::PrintSpecial(const MachineInstr *MI, const char *Code) {
  if (!strcmp(Code, "private")) {
    O << TAI->getPrivateGlobalPrefix();
  } else if (!strcmp(Code, "comment")) {
    O << TAI->getCommentString();
  } else if (!strcmp(Code, "uid")) {
    // Assign a unique ID to this machine instruction.
    static const MachineInstr *LastMI = 0;
Chris Lattner's avatar
Chris Lattner committed
    static const Function *F = 0;
Chris Lattner's avatar
Chris Lattner committed

    // Comparing the address of MI isn't sufficient, because machineinstrs may
    // be allocated to the same address across functions.
    const Function *ThisF = MI->getParent()->getParent()->getFunction();
    
    // If this is a new machine instruction, bump the counter.
Chris Lattner's avatar
Chris Lattner committed
    if (LastMI != MI || F != ThisF) {
      ++Counter;
      LastMI = MI;
Chris Lattner's avatar
Chris Lattner committed
    }
    cerr << "Unknown special formatter '" << Code
         << "' for machine instr: " << *MI;
Chris Lattner's avatar
Chris Lattner committed
/// printInlineAsm - This method formats and prints the specified machine
/// instruction that is an inline asm.
void AsmPrinter::printInlineAsm(const MachineInstr *MI) const {
  unsigned NumOperands = MI->getNumOperands();
  
  // Count the number of register definitions.
  unsigned NumDefs = 0;
  for (; MI->getOperand(NumDefs).isRegister() && MI->getOperand(NumDefs).isDef();
       ++NumDefs)
    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();
  // If this asmstr is empty, just print the #APP/#NOAPP markers.
  // These are useful to see where empty asm's wound up.
  if (AsmStr[0] == 0) {
    O << TAI->getInlineAsmStart() << "\n\t" << TAI->getInlineAsmEnd() << "\n";
  O << TAI->getInlineAsmStart() << "\n\t";
Bill Wendling's avatar
Bill Wendling committed
  // The variant of the current asmprinter.
  int AsmPrinterVariant = TAI->getAssemblerDialect();

  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 != '\n')
        ++LiteralEnd;
      if (CurVariant == -1 || CurVariant == AsmPrinterVariant)
        O.write(LastEmitted, LiteralEnd-LastEmitted);
      LastEmitted = LiteralEnd;
      break;
    }
    case '\n':
      ++LastEmitted;   // Consume newline character.
      O << "\n";       // Indent code with newline.
    case '$': {
      ++LastEmitted;   // Consume '$' character.
      bool Done = true;

      // Handle escapes.
      switch (*LastEmitted) {
      default: Done = false; break;
      case '$':     // $$ -> $
        if (CurVariant == -1 || CurVariant == AsmPrinterVariant)
          O << '$';
        ++LastEmitted;  // Consume second '$' character.
        break;
      case '(':             // $( -> same as GCC's { character.
        ++LastEmitted;      // Consume '(' character.
        if (CurVariant != -1) {
          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) {
          cerr << "Found '|' character outside of variant in inline asm "
               << "string: '" << AsmStr << "'\n";
          exit(1);
        }
        ++CurVariant;   // We're in the next variant.
        break;
      case ')':         // $) -> same as GCC's } char.
        ++LastEmitted;  // consume ')' character.
        if (CurVariant == -1) {
          cerr << "Found '}' character outside of variant in inline asm "
               << "string: '" << AsmStr << "'\n";
      
      bool HasCurlyBraces = false;
      if (*LastEmitted == '{') {     // ${variable}
        ++LastEmitted;               // Consume '{' character.
        HasCurlyBraces = true;
      }
      
      const char *IDStart = LastEmitted;
      char *IDEnd;
      errno = 0;
      long Val = strtol(IDStart, &IDEnd, 10); // We only accept numbers for IDs.
      if (!isdigit(*IDStart) || (Val == 0 && errno == EINVAL)) {
        cerr << "Bad $ operand number in inline asm string: '" 
             << AsmStr << "'\n";
        // If we have curly braces, check for a modifier character.  This
        // supports syntax like ${0:u}, which correspond to "%u0" in GCC asm.
        if (*LastEmitted == ':') {
          ++LastEmitted;    // Consume ':' character.
          if (*LastEmitted == 0) {
            cerr << "Bad ${:} expression in inline asm string: '" 
                 << AsmStr << "'\n";
            exit(1);
          }
          
          Modifier[0] = *LastEmitted;
          ++LastEmitted;    // Consume modifier character.
        }
        
          cerr << "Bad ${} expression in inline asm string: '" 
               << AsmStr << "'\n";
          exit(1);
        }
        ++LastEmitted;    // Consume '}' character.
      }
      
      if ((unsigned)Val >= NumOperands-1) {
        cerr << "Invalid $ operand number in inline asm string: '" 
             << AsmStr << "'\n";
      // Okay, we finally have a value number.  Ask the target to print this
      if (CurVariant == -1 || CurVariant == AsmPrinterVariant) {
        unsigned OpNo = 1;
        // Scan to find the machine operand number for the operand.
          if (OpNo >= MI->getNumOperands()) break;
          unsigned OpFlags = MI->getOperand(OpNo).getImm();

        if (OpNo >= MI->getNumOperands()) {
          Error = true;
          unsigned OpFlags = MI->getOperand(OpNo).getImm();
          ++OpNo;  // Skip over the ID number.

          if (Modifier[0]=='l')  // labels are target independent
            printBasicBlockLabel(MI->getOperand(OpNo).getMBB(), 
          else {
            AsmPrinter *AP = const_cast<AsmPrinter*>(this);
            if ((OpFlags & 7) == 4 /*ADDR MODE*/) {
              Error = AP->PrintAsmMemoryOperand(MI, OpNo, AsmPrinterVariant,
                                                Modifier[0] ? Modifier : 0);
            } else {
              Error = AP->PrintAsmOperand(MI, OpNo, AsmPrinterVariant,
                                          Modifier[0] ? Modifier : 0);
            }
          cerr << "Invalid operand found in inline asm: '"
               << AsmStr << "'\n";
  O << "\n\t" << TAI->getInlineAsmEnd() << "\n";
/// printImplicitDef - This method prints the specified machine instruction
/// that is an implicit def.
void AsmPrinter::printImplicitDef(const MachineInstr *MI) const {
  O << "\t" << TAI->getCommentString() << " implicit-def: "
    << TRI->getAsmName(MI->getOperand(0).getReg()) << "\n";
}

Jim Laskey's avatar
Jim Laskey committed
/// printLabel - This method prints a local label used by debug and
/// exception handling tables.
void AsmPrinter::printLabel(const MachineInstr *MI) const {
  O << TAI->getPrivateGlobalPrefix()
    << "label" << MI->getOperand(0).getImm() << ":\n";
void AsmPrinter::printLabel(unsigned Id) const {
  O << TAI->getPrivateGlobalPrefix() << "label" << Id << ":\n";
/// printDeclare - This method prints a local variable declaration used by
/// debug tables.
/// FIXME: It doesn't really print anything rather it inserts a DebugVariable
/// entry into dwarf table.
void AsmPrinter::printDeclare(const MachineInstr *MI) const {
  int FI = MI->getOperand(0).getIndex();
  GlobalValue *GV = MI->getOperand(1).getGlobal();
  MMI->RecordVariable(GV, FI);
/// 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, const char *ExtraCode) {
  // Target doesn't support this yet!
  return true;
Chris Lattner's avatar
Chris Lattner committed
}

bool AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
                                       unsigned AsmVariant,
                                       const char *ExtraCode) {
  // Target doesn't support this yet!
  return true;
}

/// printBasicBlockLabel - This method prints the label for the specified
/// MachineBasicBlock
void AsmPrinter::printBasicBlockLabel(const MachineBasicBlock *MBB,
                                      bool printColon,
                                      bool printComment) const {
  if (printAlign) {
    unsigned Align = MBB->getAlignment();
    if (Align)
      EmitAlignment(Log2_32(Align));
  }

Evan Cheng's avatar
Evan Cheng committed
  O << TAI->getPrivateGlobalPrefix() << "BB" << getFunctionNumber() << "_"
    << MBB->getNumber();
  if (printComment && MBB->getBasicBlock())
    O << '\t' << TAI->getCommentString() << ' '
      << MBB->getBasicBlock()->getName();
/// printPICJumpTableSetLabel - This method prints a set label for the
/// specified MachineBasicBlock for a jumptable entry.
void AsmPrinter::printPICJumpTableSetLabel(unsigned uid, 
                                           const MachineBasicBlock *MBB) const {
  if (!TAI->getSetDirective())
  O << TAI->getSetDirective() << ' ' << TAI->getPrivateGlobalPrefix()
Evan Cheng's avatar
Evan Cheng committed
    << getFunctionNumber() << '_' << uid << "_set_" << MBB->getNumber() << ',';
Evan Cheng's avatar
Evan Cheng committed
  O << '-' << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() 
    << '_' << uid << '\n';
void AsmPrinter::printPICJumpTableSetLabel(unsigned uid, unsigned uid2,
                                           const MachineBasicBlock *MBB) const {
  if (!TAI->getSetDirective())
    return;
  
  O << TAI->getSetDirective() << ' ' << TAI->getPrivateGlobalPrefix()
Evan Cheng's avatar
Evan Cheng committed
    << getFunctionNumber() << '_' << uid << '_' << uid2
    << "_set_" << MBB->getNumber() << ',';
Evan Cheng's avatar
Evan Cheng committed
  O << '-' << TAI->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber() 
    << '_' << uid << '_' << uid2 << '\n';
/// printDataDirective - This method prints the asm directive for the
/// specified type.
void AsmPrinter::printDataDirective(const Type *type) {
  const TargetData *TD = TM.getTargetData();
  switch (type->getTypeID()) {
Reid Spencer's avatar
Reid Spencer committed
  case Type::IntegerTyID: {
    unsigned BitWidth = cast<IntegerType>(type)->getBitWidth();
    if (BitWidth <= 8)
      O << TAI->getData8bitsDirective();
    else if (BitWidth <= 16)
      O << TAI->getData16bitsDirective();
    else if (BitWidth <= 32)
      O << TAI->getData32bitsDirective();
    else if (BitWidth <= 64) {
      assert(TAI->getData64bitsDirective() &&
             "Target cannot handle 64-bit constant exprs!");
      O << TAI->getData64bitsDirective();
    }
Reid Spencer's avatar
Reid Spencer committed
  }
  case Type::PointerTyID:
    if (TD->getPointerSize() == 8) {
      assert(TAI->getData64bitsDirective() &&
             "Target cannot handle 64-bit pointer exprs!");
      O << TAI->getData64bitsDirective();
Reid Spencer's avatar
Reid Spencer committed
    } else {
      O << TAI->getData32bitsDirective();
    }
    break;
  case Type::FloatTyID: case Type::DoubleTyID:
  case Type::X86_FP80TyID: case Type::FP128TyID: case Type::PPC_FP128TyID:
    assert (0 && "Should have already output floating point constant.");
  default:
    assert (0 && "Can't handle printing this type of thing");
    break;
  }
}