summaryrefslogtreecommitdiff
path: root/lib/Target/Hexagon/HexagonAsmPrinter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Target/Hexagon/HexagonAsmPrinter.cpp')
-rw-r--r--lib/Target/Hexagon/HexagonAsmPrinter.cpp555
1 files changed, 555 insertions, 0 deletions
diff --git a/lib/Target/Hexagon/HexagonAsmPrinter.cpp b/lib/Target/Hexagon/HexagonAsmPrinter.cpp
new file mode 100644
index 0000000000..8f8e804024
--- /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);
+}