1 //===-- XCoreAsmPrinter.cpp - XCore LLVM assembly writer ------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file contains a printer that converts from our internal representation
11 // of machine-dependent LLVM code to the XAS-format XCore assembly language.
13 //===----------------------------------------------------------------------===//
15 #define DEBUG_TYPE "asm-printer"
17 #include "XCoreInstrInfo.h"
18 #include "XCoreSubtarget.h"
19 #include "XCoreMCAsmInfo.h"
20 #include "XCoreTargetMachine.h"
21 #include "llvm/Constants.h"
22 #include "llvm/DerivedTypes.h"
23 #include "llvm/Module.h"
24 #include "llvm/CodeGen/AsmPrinter.h"
25 #include "llvm/CodeGen/MachineModuleInfo.h"
26 #include "llvm/CodeGen/MachineFunctionPass.h"
27 #include "llvm/CodeGen/MachineConstantPool.h"
28 #include "llvm/CodeGen/MachineInstr.h"
29 #include "llvm/CodeGen/MachineJumpTableInfo.h"
30 #include "llvm/MC/MCStreamer.h"
31 #include "llvm/MC/MCSymbol.h"
32 #include "llvm/Target/Mangler.h"
33 #include "llvm/Target/TargetData.h"
34 #include "llvm/Target/TargetLoweringObjectFile.h"
35 #include "llvm/Target/TargetRegistry.h"
36 #include "llvm/ADT/SmallString.h"
37 #include "llvm/ADT/StringExtras.h"
38 #include "llvm/Support/CommandLine.h"
39 #include "llvm/Support/ErrorHandling.h"
40 #include "llvm/Support/raw_ostream.h"
45 static cl::opt
<unsigned> MaxThreads("xcore-max-threads", cl::Optional
,
46 cl::desc("Maximum number of threads (for emulation thread-local storage)"),
48 cl::value_desc("number"),
52 class XCoreAsmPrinter
: public AsmPrinter
{
53 const XCoreSubtarget
&Subtarget
;
55 explicit XCoreAsmPrinter(TargetMachine
&TM
, MCStreamer
&Streamer
)
56 : AsmPrinter(TM
, Streamer
), Subtarget(TM
.getSubtarget
<XCoreSubtarget
>()){}
58 virtual const char *getPassName() const {
59 return "XCore Assembly Printer";
62 void printMemOperand(const MachineInstr
*MI
, int opNum
, raw_ostream
&O
);
63 void printInlineJT(const MachineInstr
*MI
, int opNum
, raw_ostream
&O
,
64 const std::string
&directive
= ".jmptable");
65 void printInlineJT32(const MachineInstr
*MI
, int opNum
, raw_ostream
&O
) {
66 printInlineJT(MI
, opNum
, O
, ".jmptable32");
68 void printOperand(const MachineInstr
*MI
, int opNum
, raw_ostream
&O
);
69 bool PrintAsmOperand(const MachineInstr
*MI
, unsigned OpNo
,
70 unsigned AsmVariant
, const char *ExtraCode
,
73 void emitArrayBound(MCSymbol
*Sym
, const GlobalVariable
*GV
);
74 virtual void EmitGlobalVariable(const GlobalVariable
*GV
);
76 void printInstruction(const MachineInstr
*MI
, raw_ostream
&O
); // autogen'd.
77 static const char *getRegisterName(unsigned RegNo
);
79 void EmitFunctionEntryLabel();
80 void EmitInstruction(const MachineInstr
*MI
);
81 void EmitFunctionBodyEnd();
83 } // end of anonymous namespace
85 #include "XCoreGenAsmWriter.inc"
87 void XCoreAsmPrinter::emitArrayBound(MCSymbol
*Sym
, const GlobalVariable
*GV
) {
88 assert(((GV
->hasExternalLinkage() ||
89 GV
->hasWeakLinkage()) ||
90 GV
->hasLinkOnceLinkage()) && "Unexpected linkage");
91 if (const ArrayType
*ATy
= dyn_cast
<ArrayType
>(
92 cast
<PointerType
>(GV
->getType())->getElementType())) {
93 OutStreamer
.EmitSymbolAttribute(Sym
, MCSA_Global
);
94 // FIXME: MCStreamerize.
95 OutStreamer
.EmitRawText(StringRef(".globound"));
96 OutStreamer
.EmitRawText("\t.set\t" + Twine(Sym
->getName()));
97 OutStreamer
.EmitRawText(".globound," + Twine(ATy
->getNumElements()));
98 if (GV
->hasWeakLinkage() || GV
->hasLinkOnceLinkage()) {
99 // TODO Use COMDAT groups for LinkOnceLinkage
100 OutStreamer
.EmitRawText(MAI
->getWeakDefDirective() +Twine(Sym
->getName())+
106 void XCoreAsmPrinter::EmitGlobalVariable(const GlobalVariable
*GV
) {
107 // Check to see if this is a special global used by LLVM, if so, emit it.
108 if (!GV
->hasInitializer() ||
109 EmitSpecialLLVMGlobal(GV
))
112 const TargetData
*TD
= TM
.getTargetData();
113 OutStreamer
.SwitchSection(getObjFileLowering().SectionForGlobal(GV
, Mang
,TM
));
116 MCSymbol
*GVSym
= Mang
->getSymbol(GV
);
117 Constant
*C
= GV
->getInitializer();
118 unsigned Align
= (unsigned)TD
->getPreferredTypeAlignmentShift(C
->getType());
120 // Mark the start of the global
121 OutStreamer
.EmitRawText("\t.cc_top " + Twine(GVSym
->getName()) + ".data," +
124 switch (GV
->getLinkage()) {
125 case GlobalValue::AppendingLinkage
:
126 report_fatal_error("AppendingLinkage is not supported by this target!");
127 case GlobalValue::LinkOnceAnyLinkage
:
128 case GlobalValue::LinkOnceODRLinkage
:
129 case GlobalValue::WeakAnyLinkage
:
130 case GlobalValue::WeakODRLinkage
:
131 case GlobalValue::ExternalLinkage
:
132 emitArrayBound(GVSym
, GV
);
133 OutStreamer
.EmitSymbolAttribute(GVSym
, MCSA_Global
);
135 // TODO Use COMDAT groups for LinkOnceLinkage
136 if (GV
->hasWeakLinkage() || GV
->hasLinkOnceLinkage())
137 OutStreamer
.EmitSymbolAttribute(GVSym
, MCSA_Weak
);
139 case GlobalValue::InternalLinkage
:
140 case GlobalValue::PrivateLinkage
:
142 case GlobalValue::DLLImportLinkage
:
143 llvm_unreachable("DLLImport linkage is not supported by this target!");
144 case GlobalValue::DLLExportLinkage
:
145 llvm_unreachable("DLLExport linkage is not supported by this target!");
147 llvm_unreachable("Unknown linkage type!");
150 EmitAlignment(Align
> 2 ? Align
: 2, GV
);
152 unsigned Size
= TD
->getTypeAllocSize(C
->getType());
153 if (GV
->isThreadLocal()) {
156 if (MAI
->hasDotTypeDotSizeDirective()) {
157 OutStreamer
.EmitSymbolAttribute(GVSym
, MCSA_ELF_TypeObject
);
158 OutStreamer
.EmitRawText("\t.size " + Twine(GVSym
->getName()) + "," +
161 OutStreamer
.EmitLabel(GVSym
);
163 EmitGlobalConstant(C
);
164 if (GV
->isThreadLocal()) {
165 for (unsigned i
= 1; i
< MaxThreads
; ++i
)
166 EmitGlobalConstant(C
);
168 // The ABI requires that unsigned scalar types smaller than 32 bits
169 // are padded to 32 bits.
171 OutStreamer
.EmitZeros(4 - Size
, 0);
173 // Mark the end of the global
174 OutStreamer
.EmitRawText("\t.cc_bottom " + Twine(GVSym
->getName()) + ".data");
177 /// EmitFunctionBodyEnd - Targets can override this to emit stuff after
178 /// the last basic block in the function.
179 void XCoreAsmPrinter::EmitFunctionBodyEnd() {
180 // Emit function end directives
181 OutStreamer
.EmitRawText("\t.cc_bottom " + Twine(CurrentFnSym
->getName()) +
185 void XCoreAsmPrinter::EmitFunctionEntryLabel() {
186 // Mark the start of the function
187 OutStreamer
.EmitRawText("\t.cc_top " + Twine(CurrentFnSym
->getName()) +
188 ".function," + CurrentFnSym
->getName());
189 OutStreamer
.EmitLabel(CurrentFnSym
);
192 void XCoreAsmPrinter::printMemOperand(const MachineInstr
*MI
, int opNum
,
194 printOperand(MI
, opNum
, O
);
196 if (MI
->getOperand(opNum
+1).isImm() && MI
->getOperand(opNum
+1).getImm() == 0)
200 printOperand(MI
, opNum
+1, O
);
203 void XCoreAsmPrinter::
204 printInlineJT(const MachineInstr
*MI
, int opNum
, raw_ostream
&O
,
205 const std::string
&directive
) {
206 unsigned JTI
= MI
->getOperand(opNum
).getIndex();
207 const MachineFunction
*MF
= MI
->getParent()->getParent();
208 const MachineJumpTableInfo
*MJTI
= MF
->getJumpTableInfo();
209 const std::vector
<MachineJumpTableEntry
> &JT
= MJTI
->getJumpTables();
210 const std::vector
<MachineBasicBlock
*> &JTBBs
= JT
[JTI
].MBBs
;
211 O
<< "\t" << directive
<< " ";
212 for (unsigned i
= 0, e
= JTBBs
.size(); i
!= e
; ++i
) {
213 MachineBasicBlock
*MBB
= JTBBs
[i
];
216 O
<< *MBB
->getSymbol();
220 void XCoreAsmPrinter::printOperand(const MachineInstr
*MI
, int opNum
,
222 const MachineOperand
&MO
= MI
->getOperand(opNum
);
223 switch (MO
.getType()) {
224 case MachineOperand::MO_Register
:
225 O
<< getRegisterName(MO
.getReg());
227 case MachineOperand::MO_Immediate
:
230 case MachineOperand::MO_MachineBasicBlock
:
231 O
<< *MO
.getMBB()->getSymbol();
233 case MachineOperand::MO_GlobalAddress
:
234 O
<< *Mang
->getSymbol(MO
.getGlobal());
236 case MachineOperand::MO_ExternalSymbol
:
237 O
<< MO
.getSymbolName();
239 case MachineOperand::MO_ConstantPoolIndex
:
240 O
<< MAI
->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber()
241 << '_' << MO
.getIndex();
243 case MachineOperand::MO_JumpTableIndex
:
244 O
<< MAI
->getPrivateGlobalPrefix() << "JTI" << getFunctionNumber()
245 << '_' << MO
.getIndex();
247 case MachineOperand::MO_BlockAddress
:
248 O
<< *GetBlockAddressSymbol(MO
.getBlockAddress());
251 llvm_unreachable("not implemented");
255 /// PrintAsmOperand - Print out an operand for an inline asm expression.
257 bool XCoreAsmPrinter::PrintAsmOperand(const MachineInstr
*MI
, unsigned OpNo
,
258 unsigned AsmVariant
,const char *ExtraCode
,
260 printOperand(MI
, OpNo
, O
);
264 void XCoreAsmPrinter::EmitInstruction(const MachineInstr
*MI
) {
265 SmallString
<128> Str
;
266 raw_svector_ostream
O(Str
);
268 // Check for mov mnemonic
269 if (MI
->getOpcode() == XCore::ADD_2rus
&& !MI
->getOperand(2).getImm())
270 O
<< "\tmov " << getRegisterName(MI
->getOperand(0).getReg()) << ", "
271 << getRegisterName(MI
->getOperand(1).getReg());
273 printInstruction(MI
, O
);
274 OutStreamer
.EmitRawText(O
.str());
277 // Force static initialization.
278 extern "C" void LLVMInitializeXCoreAsmPrinter() {
279 RegisterAsmPrinter
<XCoreAsmPrinter
> X(TheXCoreTarget
);