LLVM: lib/Target/AVR/AVRAsmPrinter.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
21
40
41#define DEBUG_TYPE "avr-asm-printer"
42
43using namespace llvm;
44
45namespace {
46
47
48class AVRAsmPrinter : public AsmPrinter {
49public:
50 AVRAsmPrinter(TargetMachine &TM, std::unique_ptr Streamer)
52
53 StringRef getPassName() const override { return "AVR Assembly Printer"; }
54
56
57 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
58 const char *ExtraCode, raw_ostream &O) override;
59
60 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum,
61 const char *ExtraCode, raw_ostream &O) override;
62
63 void emitInstruction(const MachineInstr *MI) override;
64
67
69
70 bool doFinalization(Module &M) override;
71
72 void emitStartOfAsmFile(Module &M) override;
73
74 static char ID;
75
76private:
78 bool EmittedStructorSymbolAttrs = false;
79};
80
81}
82
83void AVRAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo,
85 const MachineOperand &MO = MI->getOperand(OpNo);
86
90 break;
93 break;
96 break;
99 break;
102 break;
103 default:
105 }
106}
107
108bool AVRAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
109 const char *ExtraCode, raw_ostream &O) {
110
111
113 return false;
114
115 const MachineOperand &MO = MI->getOperand(OpNum);
116
117 if (ExtraCode && ExtraCode[0]) {
118
119 if (ExtraCode[1] != 0 || ExtraCode[0] < 'A' || ExtraCode[0] > 'Z')
120 return true;
121
122
124 return true;
125
127
128 unsigned ByteNumber = ExtraCode[0] - 'A';
129 const InlineAsm::Flag OpFlags(MI->getOperand(OpNum - 1).getImm());
130 const unsigned NumOpRegs = OpFlags.getNumOperandRegisters();
131
132 const AVRSubtarget &STI = MF->getSubtarget();
134
135 const TargetRegisterClass *RC = TRI.getMinimalPhysRegClass(Reg);
136 unsigned BytesPerReg = TRI.getRegSizeInBits(*RC) / 8;
137 assert(BytesPerReg <= 2 && "Only 8 and 16 bit regs are supported.");
138
139 unsigned RegIdx = ByteNumber / BytesPerReg;
140 if (RegIdx >= NumOpRegs)
141 return true;
142 Reg = MI->getOperand(OpNum + RegIdx).getReg();
143
144 if (BytesPerReg == 2) {
145 Reg = TRI.getSubReg(Reg, (ByteNumber % BytesPerReg) ? AVR::sub_hi
146 : AVR::sub_lo);
147 }
148
150 return false;
151 }
152
154 PrintSymbolOperand(MO, O);
155 else
156 printOperand(MI, OpNum, O);
157
158 return false;
159}
160
161bool AVRAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
162 unsigned OpNum, const char *ExtraCode,
163 raw_ostream &O) {
164 if (ExtraCode && ExtraCode[0])
165 return true;
166
167 const MachineOperand &MO = MI->getOperand(OpNum);
168 (void)MO;
169 assert(MO.isReg() && "Unexpected inline asm memory operand");
170
171
172
173
174
175 if (MI->getOperand(OpNum).getReg() == AVR::R31R30) {
176 O << "Z";
177 } else if (MI->getOperand(OpNum).getReg() == AVR::R29R28) {
178 O << "Y";
179 } else if (MI->getOperand(OpNum).getReg() == AVR::R27R26) {
180 O << "X";
181 } else {
182 assert(false && "Wrong register class for memory operand.");
183 }
184
185
186
187 const InlineAsm::Flag OpFlags(MI->getOperand(OpNum - 1).getImm());
188 const unsigned NumOpRegs = OpFlags.getNumOperandRegisters();
189
190 if (NumOpRegs == 2) {
191 assert(MI->getOperand(OpNum).getReg() != AVR::R27R26 &&
192 "Base register X can not have offset/displacement.");
193 O << '+' << MI->getOperand(OpNum + 1).getImm();
194 }
195
196 return false;
197}
198
199void AVRAsmPrinter::emitInstruction(const MachineInstr *MI) {
200 AVR_MC::verifyInstructionPredicates(MI->getOpcode(),
201 getSubtargetInfo().getFeatureBits());
202
203 AVRMCInstLower MCInstLowering(OutContext, *this);
204
205 MCInst I;
206 MCInstLowering.lowerInstruction(*MI, I);
207 EmitToStreamer(*OutStreamer, I);
208}
209
210const MCExpr *AVRAsmPrinter::lowerConstant(const Constant *CV,
211 const Constant *BaseCV,
213 MCContext &Ctx = OutContext;
214
217 if (IsProgMem) {
220 }
221 }
222
224}
225
226void AVRAsmPrinter::emitXXStructor(const DataLayout &DL, const Constant *CV) {
227 if (!EmittedStructorSymbolAttrs) {
228 OutStreamer->emitRawComment(
229 " Emitting these undefined symbol references causes us to link the"
230 " libgcc code that runs our constructors/destructors");
231 OutStreamer->emitRawComment(" This matches GCC's behavior");
232
233 MCSymbol *CtorsSym = OutContext.getOrCreateSymbol("__do_global_ctors");
234 OutStreamer->emitSymbolAttribute(CtorsSym, MCSA_Global);
235
236 MCSymbol *DtorsSym = OutContext.getOrCreateSymbol("__do_global_dtors");
237 OutStreamer->emitSymbolAttribute(DtorsSym, MCSA_Global);
238
239 EmittedStructorSymbolAttrs = true;
240 }
241
243}
244
245bool AVRAsmPrinter::doFinalization(Module &M) {
246 const TargetLoweringObjectFile &TLOF = getObjFileLowering();
247 const AVRTargetMachine &TM = (const AVRTargetMachine &)MMI->getTarget();
249
250 bool NeedsCopyData = false;
251 bool NeedsClearBSS = false;
252 for (const auto &GO : M.globals()) {
253 if (!GO.hasInitializer() || GO.hasAvailableExternallyLinkage())
254
255 continue;
256
257 if (GO.hasCommonLinkage()) {
258
259 NeedsClearBSS = true;
260 continue;
261 }
262
264 if (Section->getName().starts_with(".data"))
265 NeedsCopyData = true;
266 else if (Section->getName().starts_with(".rodata") && SubTM->hasLPM())
267
268
269 NeedsCopyData = true;
270 else if (Section->getName().starts_with(".bss"))
271 NeedsClearBSS = true;
272 }
273
274 MCSymbol *DoCopyData = OutContext.getOrCreateSymbol("__do_copy_data");
275 MCSymbol *DoClearBss = OutContext.getOrCreateSymbol("__do_clear_bss");
276
277 if (NeedsCopyData) {
278 OutStreamer->emitRawComment(
279 " Declaring this symbol tells the CRT that it should");
280 OutStreamer->emitRawComment(
281 "copy all variables from program memory to RAM on startup");
282 OutStreamer->emitSymbolAttribute(DoCopyData, MCSA_Global);
283 }
284
285 if (NeedsClearBSS) {
286 OutStreamer->emitRawComment(
287 " Declaring this symbol tells the CRT that it should");
288 OutStreamer->emitRawComment("clear the zeroed data section on startup");
289 OutStreamer->emitSymbolAttribute(DoClearBss, MCSA_Global);
290 }
291
293}
294
295void AVRAsmPrinter::emitStartOfAsmFile(Module &M) {
296 const AVRTargetMachine &TM = (const AVRTargetMachine &)MMI->getTarget();
298 if (!SubTM)
299 return;
300
301
302 OutStreamer->emitAssignment(
303 MMI->getContext().getOrCreateSymbol(StringRef("__tmp_reg__")),
305
306 OutStreamer->emitAssignment(
307 MMI->getContext().getOrCreateSymbol(StringRef("__zero_reg__")),
309
310 OutStreamer->emitAssignment(
311 MMI->getContext().getOrCreateSymbol(StringRef("__SREG__")),
313
314 if (!SubTM->hasSmallStack())
315 OutStreamer->emitAssignment(
316 MMI->getContext().getOrCreateSymbol(StringRef("__SP_H__")),
318
319 OutStreamer->emitAssignment(
320 MMI->getContext().getOrCreateSymbol(StringRef("__SP_L__")),
322
323 if (SubTM->hasEIJMPCALL())
324 OutStreamer->emitAssignment(
325 MMI->getContext().getOrCreateSymbol(StringRef("__EIND__")),
327
328 if (SubTM->hasELPM())
329 OutStreamer->emitAssignment(
330 MMI->getContext().getOrCreateSymbol(StringRef("__RAMPZ__")),
332}
333
334char AVRAsmPrinter::ID = 0;
335
336INITIALIZE_PASS(AVRAsmPrinter, "avr-asm-printer", "AVR Assembly Printer", false,
337 false)
338
340LLVMInitializeAVRAsmPrinter() {
342}
unsigned const MachineRegisterInfo * MRI
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
#define LLVM_EXTERNAL_VISIBILITY
Module.h This file contains the declarations for the Module class.
Machine Check Debug Module
Register const TargetRegisterInfo * TRI
Promote Memory to Register
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
static SDValue lowerConstant(SDValue Op, SelectionDAG &DAG, const RISCVSubtarget &Subtarget)
static bool printOperand(raw_ostream &OS, const SelectionDAG *G, const SDValue Value)
static TableGen::Emitter::OptClass< SkeletonEmitter > X("gen-skeleton-class", "Generate example skeleton class")
static const char * getPrettyRegisterName(MCRegister Reg, MCRegisterInfo const &MRI)
static const AVRMCExpr * create(Specifier S, const MCExpr *Expr, bool isNegated, MCContext &Ctx)
Specifies the type of an expression.
int getIORegRAMPZ() const
Get I/O register addresses.
int getRegTmpIndex() const
Get GPR aliases.
int getRegZeroIndex() const
const AVRRegisterInfo * getRegisterInfo() const override
const AVRSubtarget * getSubtargetImpl() const
This class is intended to be used as a driving class for all asm writers.
virtual const MCExpr * lowerConstant(const Constant *CV, const Constant *BaseCV=nullptr, uint64_t Offset=0)
Lower the specified LLVM Constant to an MCExpr.
bool doFinalization(Module &M) override
Shut down the asmprinter.
virtual void emitXXStructor(const DataLayout &DL, const Constant *CV)
Targets can override this to change how global constants that are part of a C++ static/global constru...
virtual bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, const char *ExtraCode, raw_ostream &OS)
Print the specified operand of MI, an INLINEASM instruction, using the specified assembler variant.
This is an important base class in LLVM.
A parsed version of the target data layout string in and methods for querying it.
static LLVM_ABI const MCConstantExpr * create(int64_t Value, MCContext &Ctx, bool PrintInHex=false, unsigned SizeInBytes=0)
Base class for the full range of assembler expressions which are needed for parsing.
MCRegisterInfo base class - We assume that the target defines a static array of MCRegisterDesc object...
static const MCSymbolRefExpr * create(const MCSymbol *Symbol, MCContext &Ctx, SMLoc Loc=SMLoc())
LLVM_ABI MCSymbol * getSymbol() const
Return the MCSymbol for this basic block.
Representation of each machine instruction.
const GlobalValue * getGlobal() const
bool isReg() const
isReg - Tests if this is a MO_Register operand.
MachineBasicBlock * getMBB() const
MachineOperandType getType() const
getType - Returns the MachineOperandType for this operand.
const char * getSymbolName() const
Register getReg() const
getReg - Returns the register number.
@ MO_Immediate
Immediate operand.
@ MO_GlobalAddress
Address of a global value.
@ MO_MachineBasicBlock
MachineBasicBlock reference.
@ MO_Register
Register operand.
@ MO_ExternalSymbol
Name of external global symbol.
A Module instance is used to store all the information related to an LLVM module.
StringRef - Represent a constant reference to a string, i.e.
MCSection * SectionForGlobal(const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const
This method computes the appropriate section to emit the specified global variable or function defini...
Primary interface to the complete machine description for the target machine.
const Target & getTarget() const
const MCRegisterInfo * getMCRegisterInfo() const
This class implements an extremely fast bulk output stream that can only output to a stream.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
@ S_PM
Corresponds to pm(), reference to program memory.
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
This is an optimization pass for GlobalISel generic memory operations.
decltype(auto) dyn_cast(const From &Val)
dyn_cast - Return the argument parameter cast to the specified type.
Target & getTheAVRTarget()
@ MCSA_Global
.type _foo, @gnu_unique_object
RegisterAsmPrinter - Helper template for registering a target specific assembly printer,...