[MCInstPrinter] Enable MCInstPrinter to change its behavior based on the
[oota-llvm.git] / lib / Target / Sparc / InstPrinter / SparcInstPrinter.cpp
1 //===-- SparcInstPrinter.cpp - Convert Sparc MCInst to assembly syntax -----==//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This class prints an Sparc MCInst to a .s file.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "SparcInstPrinter.h"
15 #include "Sparc.h"
16 #include "llvm/MC/MCExpr.h"
17 #include "llvm/MC/MCInst.h"
18 #include "llvm/MC/MCRegisterInfo.h"
19 #include "llvm/MC/MCSymbol.h"
20 #include "llvm/Support/raw_ostream.h"
21 using namespace llvm;
22
23 #define DEBUG_TYPE "asm-printer"
24
25 // The generated AsmMatcher SparcGenAsmWriter uses "Sparc" as the target
26 // namespace. But SPARC backend uses "SP" as its namespace.
27 namespace llvm {
28 namespace Sparc {
29   using namespace SP;
30 }
31 }
32
33 #define GET_INSTRUCTION_NAME
34 #define PRINT_ALIAS_INSTR
35 #include "SparcGenAsmWriter.inc"
36
37 bool SparcInstPrinter::isV9() const {
38   return (STI.getFeatureBits() & Sparc::FeatureV9) != 0;
39 }
40
41 void SparcInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const
42 {
43   OS << '%' << StringRef(getRegisterName(RegNo)).lower();
44 }
45
46 void SparcInstPrinter::printInst(const MCInst *MI, raw_ostream &O,
47                                  StringRef Annot, const MCSubtargetInfo &STI) {
48   if (!printAliasInstr(MI, O) && !printSparcAliasInstr(MI, O))
49     printInstruction(MI, O);
50   printAnnotation(O, Annot);
51 }
52
53 bool SparcInstPrinter::printSparcAliasInstr(const MCInst *MI, raw_ostream &O)
54 {
55   switch (MI->getOpcode()) {
56   default: return false;
57   case SP::JMPLrr:
58   case SP::JMPLri: {
59     if (MI->getNumOperands() != 3)
60       return false;
61     if (!MI->getOperand(0).isReg())
62       return false;
63     switch (MI->getOperand(0).getReg()) {
64     default: return false;
65     case SP::G0: // jmp $addr | ret | retl
66       if (MI->getOperand(2).isImm() &&
67           MI->getOperand(2).getImm() == 8) {
68         switch(MI->getOperand(1).getReg()) {
69         default: break;
70         case SP::I7: O << "\tret"; return true;
71         case SP::O7: O << "\tretl"; return true;
72         }
73       }
74       O << "\tjmp "; printMemOperand(MI, 1, O);
75       return true;
76     case SP::O7: // call $addr
77       O << "\tcall "; printMemOperand(MI, 1, O);
78       return true;
79     }
80   }
81   case SP::V9FCMPS:  case SP::V9FCMPD:  case SP::V9FCMPQ:
82   case SP::V9FCMPES: case SP::V9FCMPED: case SP::V9FCMPEQ: {
83     if (isV9()
84         || (MI->getNumOperands() != 3)
85         || (!MI->getOperand(0).isReg())
86         || (MI->getOperand(0).getReg() != SP::FCC0))
87       return false;
88     // if V8, skip printing %fcc0.
89     switch(MI->getOpcode()) {
90     default:
91     case SP::V9FCMPS:  O << "\tfcmps "; break;
92     case SP::V9FCMPD:  O << "\tfcmpd "; break;
93     case SP::V9FCMPQ:  O << "\tfcmpq "; break;
94     case SP::V9FCMPES: O << "\tfcmpes "; break;
95     case SP::V9FCMPED: O << "\tfcmped "; break;
96     case SP::V9FCMPEQ: O << "\tfcmpeq "; break;
97     }
98     printOperand(MI, 1, O);
99     O << ", ";
100     printOperand(MI, 2, O);
101     return true;
102   }
103   }
104 }
105
106 void SparcInstPrinter::printOperand(const MCInst *MI, int opNum,
107                                     raw_ostream &O)
108 {
109   const MCOperand &MO = MI->getOperand (opNum);
110
111   if (MO.isReg()) {
112     printRegName(O, MO.getReg());
113     return ;
114   }
115
116   if (MO.isImm()) {
117     O << (int)MO.getImm();
118     return;
119   }
120
121   assert(MO.isExpr() && "Unknown operand kind in printOperand");
122   MO.getExpr()->print(O);
123 }
124
125 void SparcInstPrinter::printMemOperand(const MCInst *MI, int opNum,
126                                       raw_ostream &O, const char *Modifier)
127 {
128   printOperand(MI, opNum, O);
129
130   // If this is an ADD operand, emit it like normal operands.
131   if (Modifier && !strcmp(Modifier, "arith")) {
132     O << ", ";
133     printOperand(MI, opNum+1, O);
134     return;
135   }
136   const MCOperand &MO = MI->getOperand(opNum+1);
137
138   if (MO.isReg() && MO.getReg() == SP::G0)
139     return;   // don't print "+%g0"
140   if (MO.isImm() && MO.getImm() == 0)
141     return;   // don't print "+0"
142
143   O << "+";
144
145   printOperand(MI, opNum+1, O);
146 }
147
148 void SparcInstPrinter::printCCOperand(const MCInst *MI, int opNum,
149                                      raw_ostream &O)
150 {
151   int CC = (int)MI->getOperand(opNum).getImm();
152   switch (MI->getOpcode()) {
153   default: break;
154   case SP::FBCOND:
155   case SP::FBCONDA:
156   case SP::BPFCC:
157   case SP::BPFCCA:
158   case SP::BPFCCNT:
159   case SP::BPFCCANT:
160   case SP::MOVFCCrr:  case SP::V9MOVFCCrr:
161   case SP::MOVFCCri:  case SP::V9MOVFCCri:
162   case SP::FMOVS_FCC: case SP::V9FMOVS_FCC:
163   case SP::FMOVD_FCC: case SP::V9FMOVD_FCC:
164   case SP::FMOVQ_FCC: case SP::V9FMOVQ_FCC:
165     // Make sure CC is a fp conditional flag.
166     CC = (CC < 16) ? (CC + 16) : CC;
167     break;
168   }
169   O << SPARCCondCodeToString((SPCC::CondCodes)CC);
170 }
171
172 bool SparcInstPrinter::printGetPCX(const MCInst *MI, unsigned opNum,
173                                   raw_ostream &O)
174 {
175   llvm_unreachable("FIXME: Implement SparcInstPrinter::printGetPCX.");
176   return true;
177 }