aboutsummaryrefslogtreecommitdiff
path: root/lib/Target/Nios2/Nios2AsmPrinter.cpp
blob: 1abf19591774a37381ce5aceca9d335be243d046 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
//===-- Nios2AsmPrinter.cpp - Nios2 LLVM Assembly Printer -----------------===//
//
//                     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 GAS-format NIOS2 assembly language.
//
//===----------------------------------------------------------------------===//

#include "InstPrinter/Nios2InstPrinter.h"
#include "MCTargetDesc/Nios2BaseInfo.h"
#include "Nios2.h"
#include "Nios2TargetMachine.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/Support/TargetRegistry.h"

using namespace llvm;

#define DEBUG_TYPE "nios2-asm-printer"

namespace {

class Nios2AsmPrinter : public AsmPrinter {

public:
  explicit Nios2AsmPrinter(TargetMachine &TM,
                           std::unique_ptr<MCStreamer> Streamer)
      : AsmPrinter(TM, std::move(Streamer)) {}

  StringRef getPassName() const override { return "Nios2 Assembly Printer"; }

  //- EmitInstruction() must exists or will have run time error.
  void EmitInstruction(const MachineInstr *MI) override;
  bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
                       unsigned AsmVariant, const char *ExtraCode,
                       raw_ostream &O) override;
  bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum,
                             unsigned AsmVariant, const char *ExtraCode,
                             raw_ostream &O) override;
  void printOperand(const MachineInstr *MI, int opNum, raw_ostream &O);
  void EmitFunctionEntryLabel() override;
};
} // namespace

//- EmitInstruction() must exists or will have run time error.
void Nios2AsmPrinter::EmitInstruction(const MachineInstr *MI) {

  //  Print out both ordinary instruction and boudle instruction
  MachineBasicBlock::const_instr_iterator I = MI->getIterator();
  MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();

  do {

    if (I->isPseudo()) {
      llvm_unreachable("Pseudo opcode found in EmitInstruction()");
    }

    MCInst TmpInst0;
    LowerNios2MachineInstToMCInst(&*I, TmpInst0, *this);
    EmitToStreamer(*OutStreamer, TmpInst0);
  } while ((++I != E) && I->isInsideBundle()); // Delay slot check
}

//		.type	main,@function
//->		.ent	main                    # @main
//	main:
void Nios2AsmPrinter::EmitFunctionEntryLabel() {
  OutStreamer->EmitLabel(CurrentFnSym);
}

// Print out an operand for an inline asm expression.
bool Nios2AsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
                                      unsigned AsmVariant,
                                      const char *ExtraCode, raw_ostream &O) {
  printOperand(MI, OpNum, O);
  return false;
}

bool Nios2AsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
                                            unsigned OpNum, unsigned AsmVariant,
                                            const char *ExtraCode,
                                            raw_ostream &O) {
  if (ExtraCode && ExtraCode[0])
    return true; // Unknown modifier

  const MachineOperand &MO = MI->getOperand(OpNum);
  assert(MO.isReg() && "unexpected inline asm memory operand");
  O << "($" << Nios2InstPrinter::getRegisterName(MO.getReg()) << ")";

  return false;
}

void Nios2AsmPrinter::printOperand(const MachineInstr *MI, int opNum,
                                   raw_ostream &O) {
  const MachineOperand &MO = MI->getOperand(opNum);
  bool closeP = false;

  if (MO.getTargetFlags())
    closeP = true;

  switch (MO.getTargetFlags()) {
  case Nios2FG::MO_ABS_HI:
    O << "%hiadj(";
    break;
  case Nios2FG::MO_ABS_LO:
    O << "%lo(";
    break;
  }

  switch (MO.getType()) {
  case MachineOperand::MO_Register:
    O << '$'
      << StringRef(Nios2InstPrinter::getRegisterName(MO.getReg())).lower();
    break;

  case MachineOperand::MO_Immediate:
    O << MO.getImm();
    break;

  case MachineOperand::MO_MachineBasicBlock:
    MO.getMBB()->getSymbol()->print(O, MAI);
    return;

  case MachineOperand::MO_GlobalAddress:
    getSymbol(MO.getGlobal())->print(O, MAI);
    break;

  case MachineOperand::MO_BlockAddress:
    O << GetBlockAddressSymbol(MO.getBlockAddress())->getName();
    break;

  case MachineOperand::MO_ExternalSymbol:
    O << MO.getSymbolName();
    break;

  default:
    llvm_unreachable("<unknown operand type>");
  }

  if (closeP)
    O << ")";
}

// Force static initialization.
extern "C" void LLVMInitializeNios2AsmPrinter() {
  RegisterAsmPrinter<Nios2AsmPrinter> X(getTheNios2Target());
}