Hexagon backend support

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@146412 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Target/Hexagon/HexagonAsmPrinter.cpp b/lib/Target/Hexagon/HexagonAsmPrinter.cpp
new file mode 100644
index 0000000..8f8e804
--- /dev/null
+++ b/lib/Target/Hexagon/HexagonAsmPrinter.cpp
@@ -0,0 +1,555 @@
+//===-- HexagonAsmPrinter.cpp - Print machine instrs to Hexagon assembly ----=//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains a printer that converts from our internal representation
+// of machine-dependent LLVM code to Hexagon assembly language. This printer is
+// the output mechanism used by `llc'.
+//
+// Documentation at http://developer.apple.com/documentation/DeveloperTools/
+// Reference/Assembler/ASMIntroduction/chapter_1_section_1.html
+//
+//===----------------------------------------------------------------------===//
+
+
+#define DEBUG_TYPE "asm-printer"
+#include "Hexagon.h"
+#include "HexagonTargetMachine.h"
+#include "HexagonSubtarget.h"
+#include "HexagonMachineFunctionInfo.h"
+#include "llvm/Constants.h"
+#include "llvm/DerivedTypes.h"
+#include "llvm/Module.h"
+#include "llvm/Assembly/Writer.h"
+#include "llvm/CodeGen/AsmPrinter.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstr.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/Mangler.h"
+#include "llvm/Target/TargetData.h"
+#include "llvm/Target/TargetLoweringObjectFile.h"
+#include "llvm/Target/TargetRegisterInfo.h"
+#include "llvm/Target/TargetInstrInfo.h"
+#include "llvm/Target/TargetOptions.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+static cl::opt<bool> AlignCalls(
+         "hexagon-align-calls", cl::Hidden, cl::init(true),
+          cl::desc("Insert falign after call instruction for Hexagon target"));
+
+
+namespace {
+  class HexagonAsmPrinter : public AsmPrinter {
+    const HexagonSubtarget *Subtarget;
+
+  public:
+    explicit HexagonAsmPrinter(TargetMachine &TM, MCStreamer &Streamer)
+      : AsmPrinter(TM, Streamer) {
+      Subtarget = &TM.getSubtarget<HexagonSubtarget>();
+    }
+
+    virtual const char *getPassName() const {
+      return "Hexagon Assembly Printer";
+    }
+
+    /// printInstruction - This method is automatically generated by tablegen
+    /// from the instruction set description.  This method returns true if the
+    /// machine instruction was sufficiently described to print it, otherwise it
+    void printInstruction(const MachineInstr *MI, raw_ostream &O);
+    virtual void EmitInstruction(const MachineInstr *MI);
+
+    void printOp(const MachineOperand &MO, raw_ostream &O);
+
+    /// printRegister - Print register according to target requirements.
+    ///
+    void printRegister(const MachineOperand &MO, bool R0AsZero,
+                       raw_ostream &O) {
+      unsigned RegNo = MO.getReg();
+      assert(TargetRegisterInfo::isPhysicalRegister(RegNo) && "Not physreg??");
+      O << getRegisterName(RegNo);
+    }
+
+    void printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &OS) {
+      const MachineOperand &MO = MI->getOperand(OpNo);
+      if (MO.isReg()) {
+        printRegister(MO, false, OS);
+      } else if (MO.isImm()) {
+        OS << MO.getImm();
+      } else {
+        printOp(MO, OS);
+      }
+    }
+
+
+    bool isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) const;
+
+    bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
+                         unsigned AsmVariant, const char *ExtraCode,
+                         raw_ostream &OS);
+    bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
+                               unsigned AsmVariant, const char *ExtraCode,
+                               raw_ostream &OS);
+
+
+    void printHexagonImmOperand(const MachineInstr *MI, unsigned OpNo,
+                                raw_ostream &O) {
+      int value = MI->getOperand(OpNo).getImm();
+      O << value;
+    }
+
+
+    void printHexagonNegImmOperand(const MachineInstr *MI, unsigned OpNo,
+                                   raw_ostream &O) {
+      int value = MI->getOperand(OpNo).getImm();
+      O << -value;
+    }
+
+    void printHexagonMEMriOperand(const MachineInstr *MI, unsigned OpNo,
+                                  raw_ostream &O) {
+      const MachineOperand &MO1 = MI->getOperand(OpNo);
+      const MachineOperand &MO2 = MI->getOperand(OpNo+1);
+
+      O << getRegisterName(MO1.getReg())
+        << " + #"
+        << (int) MO2.getImm();
+    }
+
+
+    void printHexagonFrameIndexOperand(const MachineInstr *MI, unsigned OpNo,
+                                       raw_ostream &O) {
+      const MachineOperand &MO1 = MI->getOperand(OpNo);
+      const MachineOperand &MO2 = MI->getOperand(OpNo+1);
+
+      O << getRegisterName(MO1.getReg())
+        << ", #"
+        << MO2.getImm();
+    }
+
+    void printBranchOperand(const MachineInstr *MI, unsigned OpNo,
+                            raw_ostream &O) {
+      // Branches can take an immediate operand.  This is used by the branch
+      // selection pass to print $+8, an eight byte displacement from the PC.
+      if (MI->getOperand(OpNo).isImm()) {
+        O << "$+" << MI->getOperand(OpNo).getImm()*4;
+      } else {
+        printOp(MI->getOperand(OpNo), O);
+      }
+    }
+
+    void printCallOperand(const MachineInstr *MI, unsigned OpNo,
+                          raw_ostream &O) {
+    }
+
+    void printAbsAddrOperand(const MachineInstr *MI, unsigned OpNo,
+                            raw_ostream &O) {
+    }
+
+
+    void printSymbolHi(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
+      O << "#HI(";
+      if (MI->getOperand(OpNo).isImm()) {
+        printHexagonImmOperand(MI, OpNo, O);
+      } else {
+        printOp(MI->getOperand(OpNo), O);
+      }
+      O << ")";
+    }
+
+    void printSymbolLo(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
+      O << "#HI(";
+      if (MI->getOperand(OpNo).isImm()) {
+        printHexagonImmOperand(MI, OpNo, O);
+      } else {
+        printOp(MI->getOperand(OpNo), O);
+      }
+      O << ")";
+    }
+
+    void printPredicateOperand(const MachineInstr *MI, unsigned OpNo,
+                               raw_ostream &O);
+
+    void printAddrModeBasePlusOffset(const MachineInstr *MI, int OpNo,
+                                     raw_ostream &O);
+
+    void printGlobalOperand(const MachineInstr *MI, int OpNo, raw_ostream &O);
+    void printJumpTable(const MachineInstr *MI, int OpNo, raw_ostream &O);
+
+    void EmitAlignment(unsigned NumBits, const GlobalValue *GV = 0) const;
+
+    static const char *getRegisterName(unsigned RegNo);
+  };
+
+} // end of anonymous namespace
+
+// Include the auto-generated portion of the assembly writer.
+#include "HexagonGenAsmWriter.inc"
+
+
+void HexagonAsmPrinter::EmitAlignment(unsigned NumBits,
+                                      const GlobalValue *GV) const {
+
+  // For basic block level alignment, use falign.
+  if (!GV) {
+    OutStreamer.EmitRawText(StringRef("\t.falign"));
+    return;
+  }
+
+  AsmPrinter::EmitAlignment(NumBits, GV);
+}
+
+void HexagonAsmPrinter::printOp(const MachineOperand &MO, raw_ostream &O) {
+  switch (MO.getType()) {
+  case MachineOperand::MO_Immediate:
+    dbgs() << "printOp() does not handle immediate values\n";
+    abort();
+    return;
+
+  case MachineOperand::MO_MachineBasicBlock:
+    O << *MO.getMBB()->getSymbol();
+    return;
+  case MachineOperand::MO_JumpTableIndex:
+    O << *GetJTISymbol(MO.getIndex());
+    // FIXME: PIC relocation model.
+    return;
+  case MachineOperand::MO_ConstantPoolIndex:
+    O << *GetCPISymbol(MO.getIndex());
+    return;
+  case MachineOperand::MO_ExternalSymbol:
+    O << *GetExternalSymbolSymbol(MO.getSymbolName());
+    return;
+  case MachineOperand::MO_GlobalAddress: {
+    // Computing the address of a global symbol, not calling it.
+    O << *Mang->getSymbol(MO.getGlobal());
+    printOffset(MO.getOffset(), O);
+    return;
+  }
+
+  default:
+    O << "<unknown operand type: " << MO.getType() << ">";
+    return;
+  }
+}
+
+
+//
+// isBlockOnlyReachableByFallthrough - We need to override this since the
+// default AsmPrinter does not print labels for any basic block that
+// is only reachable by a fall through. That works for all cases except
+// for the case in which the basic block is reachable by a fall through but
+// through an indirect from a jump table. In this case, the jump table
+// will contain a label not defined by AsmPrinter.
+//
+bool HexagonAsmPrinter::
+isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) const {
+  if (MBB->hasAddressTaken()) {
+    return false;
+  }
+  return AsmPrinter::isBlockOnlyReachableByFallthrough(MBB);
+}
+
+
+/// PrintAsmOperand - Print out an operand for an inline asm expression.
+///
+bool HexagonAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
+                                        unsigned AsmVariant,
+                                        const char *ExtraCode,
+                                      raw_ostream &OS) {
+  // Does this asm operand have a single letter operand modifier?
+  if (ExtraCode && ExtraCode[0]) {
+    if (ExtraCode[1] != 0) return true; // Unknown modifier.
+
+    switch (ExtraCode[0]) {
+    default: return true;  // Unknown modifier.
+    case 'c': // Don't print "$" before a global var name or constant.
+      // Hexagon never has a prefix.
+      printOperand(MI, OpNo, OS);
+      return false;
+    case 'L': // Write second word of DImode reference.
+      // Verify that this operand has two consecutive registers.
+      if (!MI->getOperand(OpNo).isReg() ||
+          OpNo+1 == MI->getNumOperands() ||
+          !MI->getOperand(OpNo+1).isReg())
+        return true;
+      ++OpNo;   // Return the high-part.
+      break;
+    case 'I':
+      // Write 'i' if an integer constant, otherwise nothing.  Used to print
+      // addi vs add, etc.
+      if (MI->getOperand(OpNo).isImm())
+        OS << "i";
+      return false;
+    }
+  }
+
+  printOperand(MI, OpNo, OS);
+  return false;
+}
+
+bool HexagonAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
+                                            unsigned OpNo, unsigned AsmVariant,
+                                            const char *ExtraCode,
+                                            raw_ostream &O) {
+  if (ExtraCode && ExtraCode[0])
+    return true; // Unknown modifier.
+
+  const MachineOperand &Base  = MI->getOperand(OpNo);
+  const MachineOperand &Offset = MI->getOperand(OpNo+1);
+
+  if (Base.isReg())
+    printOperand(MI, OpNo, O);
+  else
+    assert(0 && "Unimplemented");
+
+  if (Offset.isImm()) {
+    if (Offset.getImm())
+      O << " + #" << Offset.getImm();
+  }
+  else
+    assert(0 && "Unimplemented");
+
+  return false;
+}
+
+void HexagonAsmPrinter::printPredicateOperand(const MachineInstr *MI,
+                                              unsigned OpNo,
+                                              raw_ostream &O) {
+  assert(0 && "Unimplemented");
+}
+
+
+/// printMachineInstruction -- Print out a single Hexagon MI in Darwin syntax to
+/// the current output stream.
+///
+void HexagonAsmPrinter::EmitInstruction(const MachineInstr *MI) {
+  SmallString<128> Str;
+  raw_svector_ostream O(Str);
+
+  const MachineFunction* MF = MI->getParent()->getParent();
+  const HexagonMachineFunctionInfo* MFI =
+    (const HexagonMachineFunctionInfo*)
+    MF->getInfo<HexagonMachineFunctionInfo>();
+
+
+
+  // Print a brace for the beginning of the packet.
+  if (MFI->isStartPacket(MI)) {
+    O << "\t{" << '\n';
+  }
+
+  DEBUG( O << "// MI = " << *MI << '\n';);
+
+  // Indent
+  O << "\t";
+
+
+  if (MI->getOpcode() == Hexagon::ENDLOOP0) {
+    if (MFI->isEndPacket(MI) && MFI->isStartPacket(MI)) {
+      O << "\t{ nop }";
+    } else {
+    O << "}";
+    }
+    printInstruction(MI, O);
+  } else if (MI->getOpcode() == Hexagon::STriwt) {
+    //
+    // Handle truncated store on Hexagon.
+    //
+    O << "\tmemw(";
+    printHexagonMEMriOperand(MI, 0, O);
+
+    O << ") = ";
+    unsigned SubRegNum =
+      TM.getRegisterInfo()->getSubReg(MI->getOperand(2)
+                                      .getReg(), Hexagon::subreg_loreg);
+    const char *SubRegName = getRegisterName(SubRegNum);
+    O << SubRegName << '\n';
+  } else if (MI->getOpcode() == Hexagon::MPYI_rin) {
+    // Handle multipy with -ve constant on Hexagon:
+    // "$dst =- mpyi($src1, #$src2)"
+      printOperand(MI, 0, O);
+    O << " =- mpyi(";
+    printOperand(MI, 1, O);
+    O << ", #";
+    printHexagonNegImmOperand(MI, 2, O);
+    O << ")";
+  } else if (MI->getOpcode() == Hexagon::MEMw_ADDSUBi_indexed_MEM_V4) {
+    //
+    // Handle memw(Rs+u6:2) [+-]= #U5
+    //
+    O << "\tmemw("; printHexagonMEMriOperand(MI, 0, O); O << ") ";
+    int addend = MI->getOperand(2).getImm();
+    if (addend < 0)
+      O << "-= " << "#" << -addend << '\n';
+    else
+      O << "+= " << "#" << addend << '\n';
+  } else if (MI->getOpcode() == Hexagon::MEMw_ADDSUBi_MEM_V4) {
+    //
+    // Handle memw(Rs+u6:2) [+-]= #U5
+    //
+    O << "\tmemw("; printHexagonMEMriOperand(MI, 0, O); O << ") ";
+    int addend = MI->getOperand(2).getImm();
+    if (addend < 0)
+      O << "-= " << "#" << -addend << '\n';
+    else
+      O << "+= " << "#" << addend << '\n';
+  } else if (MI->getOpcode() == Hexagon::MEMh_ADDSUBi_indexed_MEM_V4) {
+    //
+    // Handle memh(Rs+u6:1) [+-]= #U5
+    //
+    O << "\tmemh("; printHexagonMEMriOperand(MI, 0, O); O << ") ";
+    int addend = MI->getOperand(2).getImm();
+    if (addend < 0)
+      O << "-= " << "#" << -addend << '\n';
+    else
+      O << "+= " << "#" << addend << '\n';
+  } else if (MI->getOpcode() == Hexagon::MEMh_ADDSUBi_MEM_V4) {
+    //
+    // Handle memh(Rs+u6:1) [+-]= #U5
+    //
+    O << "\tmemh("; printHexagonMEMriOperand(MI, 0, O); O << ") ";
+    int addend = MI->getOperand(2).getImm();
+    if (addend < 0)
+      O << "-= " << "#" << -addend << '\n';
+    else
+      O << "+= " << "#" << addend << '\n';
+  } else if (MI->getOpcode() == Hexagon::MEMb_ADDSUBi_indexed_MEM_V4) {
+    //
+    // Handle memb(Rs+u6:1) [+-]= #U5
+    //
+    O << "\tmemb("; printHexagonMEMriOperand(MI, 0, O); O << ") ";
+    int addend = MI->getOperand(2).getImm();
+    if (addend < 0)
+      O << "-= " << "#" << -addend << '\n';
+    else
+      O << "+= " << "#" << addend << '\n';
+  } else if (MI->getOpcode() == Hexagon::MEMb_ADDSUBi_MEM_V4) {
+    //
+    // Handle memb(Rs+u6:1) [+-]= #U5
+    //
+    O << "\tmemb("; printHexagonMEMriOperand(MI, 0, O); O << ") ";
+    int addend = MI->getOperand(2).getImm();
+    if (addend < 0)
+      O << "-= " << "#" << -addend << '\n';
+    else
+      O << "+= " << "#" << addend << '\n';
+  } else if (MI->getOpcode() == Hexagon::CMPbGTri_V4) {
+    //
+    // Handle Pd=cmpb.gt(Rs,#s8)
+    //
+    O << "\t";
+    printRegister(MI->getOperand(0), false, O);
+    O << " = cmpb.gt(";
+    printRegister(MI->getOperand(1), false, O);
+    O << ", ";
+    int val = MI->getOperand(2).getImm() >> 24;
+    O << "#" << val << ")" << '\n';
+  } else if (MI->getOpcode() == Hexagon::CMPhEQri_V4) {
+    //
+    // Handle Pd=cmph.eq(Rs,#8)
+    //
+    O << "\t";
+    printRegister(MI->getOperand(0), false, O);
+    O << " = cmph.eq(";
+    printRegister(MI->getOperand(1), false, O);
+    O << ", ";
+    int val = MI->getOperand(2).getImm();
+    assert((((0 <= val) && (val <= 127)) ||
+            ((65408 <= val) && (val <= 65535))) &&
+           "Not in correct range!");
+    if (val >= 65408) val -= 65536;
+    O << "#" << val << ")" << '\n';
+  } else if (MI->getOpcode() == Hexagon::CMPhGTri_V4) {
+    //
+    // Handle Pd=cmph.gt(Rs,#8)
+    //
+    O << "\t";
+    printRegister(MI->getOperand(0), false, O);
+    O << " = cmph.gt(";
+    printRegister(MI->getOperand(1), false, O);
+    O << ", ";
+    int val = MI->getOperand(2).getImm() >> 16;
+    O << "#" << val << ")" << '\n';
+  } else {
+    printInstruction(MI, O);
+  }
+
+  // Print a brace for the end of the packet.
+  if (MFI->isEndPacket(MI) && MI->getOpcode() != Hexagon::ENDLOOP0) {
+    O << "\n\t}" << '\n';
+  }
+
+  if (AlignCalls && MI->getDesc().isCall()) {
+    O << "\n\t.falign" << "\n";
+  }
+
+  OutStreamer.EmitRawText(O.str());
+  return;
+}
+
+/// PrintUnmangledNameSafely - Print out the printable characters in the name.
+/// Don't print things like \n or \0.
+// static void PrintUnmangledNameSafely(const Value *V, raw_ostream &OS) {
+//   for (const char *Name = V->getNameStart(), *E = Name+V->getNameLen();
+//        Name != E; ++Name)
+//     if (isprint(*Name))
+//       OS << *Name;
+// }
+
+
+void HexagonAsmPrinter::printAddrModeBasePlusOffset(const MachineInstr *MI,
+                                                    int OpNo, raw_ostream &O) {
+  const MachineOperand &MO1 = MI->getOperand(OpNo);
+  const MachineOperand &MO2 = MI->getOperand(OpNo+1);
+
+  O << getRegisterName(MO1.getReg())
+    << " + #"
+    << MO2.getImm();
+}
+
+
+void HexagonAsmPrinter::printGlobalOperand(const MachineInstr *MI, int OpNo,
+                                           raw_ostream &O) {
+  const MachineOperand &MO = MI->getOperand(OpNo);
+  assert( (MO.getType() == MachineOperand::MO_GlobalAddress) &&
+         "Expecting global address");
+
+  O << *Mang->getSymbol(MO.getGlobal());
+  if (MO.getOffset() != 0) {
+    O << " + ";
+    O << MO.getOffset();
+  }
+}
+
+void HexagonAsmPrinter::printJumpTable(const MachineInstr *MI, int OpNo,
+                                       raw_ostream &O) {
+  const MachineOperand &MO = MI->getOperand(OpNo);
+  assert( (MO.getType() == MachineOperand::MO_JumpTableIndex) &&
+	  "Expecting jump table index");
+
+  // Hexagon_TODO: Do we need name mangling?
+  O << *GetJTISymbol(MO.getIndex());
+}
+
+extern "C" void LLVMInitializeHexagonAsmPrinter() {
+  RegisterAsmPrinter<HexagonAsmPrinter> X(TheHexagonTarget);
+}