41#define DEBUG_TYPE "avr-asm-printer"
50 AVRAsmPrinter(
TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
51 :
AsmPrinter(TM, std::move(Streamer),
ID),
MRI(*TM.getMCRegisterInfo()) {}
53 StringRef getPassName()
const override {
return "AVR Assembly Printer"; }
70 bool doFinalization(
Module &M)
override;
72 void emitStartOfAsmFile(
Module &M)
override;
78 bool EmittedStructorSymbolAttrs =
false;
83void AVRAsmPrinter::printOperand(
const MachineInstr *
MI,
unsigned OpNo,
85 const MachineOperand &MO =
MI->getOperand(OpNo);
108bool AVRAsmPrinter::PrintAsmOperand(
const MachineInstr *
MI,
unsigned OpNum,
109 const char *ExtraCode, raw_ostream &O) {
115 const MachineOperand &MO =
MI->getOperand(OpNum);
117 if (ExtraCode && ExtraCode[0]) {
119 if (ExtraCode[1] != 0 || ExtraCode[0] <
'A' || ExtraCode[0] >
'Z')
128 unsigned ByteNumber = ExtraCode[0] -
'A';
129 const InlineAsm::Flag OpFlags(
MI->getOperand(OpNum - 1).getImm());
130 const unsigned NumOpRegs = OpFlags.getNumOperandRegisters();
132 const AVRSubtarget &STI = MF->getSubtarget<AVRSubtarget>();
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.");
139 unsigned RegIdx = ByteNumber / BytesPerReg;
140 if (RegIdx >= NumOpRegs)
142 Reg =
MI->getOperand(OpNum + RegIdx).getReg();
144 if (BytesPerReg == 2) {
145 Reg =
TRI.getSubReg(
Reg, (ByteNumber % BytesPerReg) ? AVR::sub_hi
154 PrintSymbolOperand(MO, O);
161bool AVRAsmPrinter::PrintAsmMemoryOperand(
const MachineInstr *
MI,
162 unsigned OpNum,
const char *ExtraCode,
164 if (ExtraCode && ExtraCode[0])
167 const MachineOperand &MO =
MI->getOperand(OpNum);
169 assert(MO.
isReg() &&
"Unexpected inline asm memory operand");
175 if (
MI->getOperand(OpNum).getReg() == AVR::R31R30) {
177 }
else if (
MI->getOperand(OpNum).getReg() == AVR::R29R28) {
179 }
else if (
MI->getOperand(OpNum).getReg() == AVR::R27R26) {
182 assert(
false &&
"Wrong register class for memory operand.");
187 const InlineAsm::Flag OpFlags(
MI->getOperand(OpNum - 1).getImm());
188 const unsigned NumOpRegs = OpFlags.getNumOperandRegisters();
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();
199void AVRAsmPrinter::emitInstruction(
const MachineInstr *
MI) {
200 AVR_MC::verifyInstructionPredicates(
MI->getOpcode(),
201 getSubtargetInfo().getFeatureBits());
203 AVRMCInstLower MCInstLowering(OutContext, *
this);
206 MCInstLowering.lowerInstruction(*
MI,
I);
207 EmitToStreamer(*OutStreamer,
I);
210const MCExpr *AVRAsmPrinter::lowerConstant(
const Constant *CV,
211 const Constant *BaseCV,
213 MCContext &Ctx = OutContext;
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");
233 MCSymbol *CtorsSym = OutContext.getOrCreateSymbol(
"__do_global_ctors");
234 OutStreamer->emitSymbolAttribute(CtorsSym,
MCSA_Global);
236 MCSymbol *DtorsSym = OutContext.getOrCreateSymbol(
"__do_global_dtors");
237 OutStreamer->emitSymbolAttribute(DtorsSym,
MCSA_Global);
239 EmittedStructorSymbolAttrs =
true;
245bool AVRAsmPrinter::doFinalization(
Module &M) {
246 const TargetLoweringObjectFile &TLOF = getObjFileLowering();
247 const AVRTargetMachine &
TM = (
const AVRTargetMachine &)MMI->getTarget();
248 const AVRSubtarget *SubTM =
TM.getSubtargetImpl();
250 bool NeedsCopyData =
false;
251 bool NeedsClearBSS =
false;
252 for (
const auto &GO :
M.globals()) {
253 if (!GO.hasInitializer() || GO.hasAvailableExternallyLinkage())
257 if (GO.hasCommonLinkage()) {
259 NeedsClearBSS =
true;
264 if (
Section->getName().starts_with(
".data"))
265 NeedsCopyData =
true;
266 else if (
Section->getName().starts_with(
".rodata") && SubTM->hasLPM())
269 NeedsCopyData =
true;
270 else if (
Section->getName().starts_with(
".bss"))
271 NeedsClearBSS =
true;
274 MCSymbol *DoCopyData = OutContext.getOrCreateSymbol(
"__do_copy_data");
275 MCSymbol *DoClearBss = OutContext.getOrCreateSymbol(
"__do_clear_bss");
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);
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);
295void AVRAsmPrinter::emitStartOfAsmFile(
Module &M) {
296 const AVRTargetMachine &
TM = (
const AVRTargetMachine &)MMI->getTarget();
297 const AVRSubtarget *SubTM =
TM.getSubtargetImpl();
302 OutStreamer->emitAssignment(
303 MMI->getContext().getOrCreateSymbol(StringRef(
"__tmp_reg__")),
306 OutStreamer->emitAssignment(
307 MMI->getContext().getOrCreateSymbol(StringRef(
"__zero_reg__")),
310 OutStreamer->emitAssignment(
311 MMI->getContext().getOrCreateSymbol(StringRef(
"__SREG__")),
314 if (!SubTM->hasSmallStack())
315 OutStreamer->emitAssignment(
316 MMI->getContext().getOrCreateSymbol(StringRef(
"__SP_H__")),
319 OutStreamer->emitAssignment(
320 MMI->getContext().getOrCreateSymbol(StringRef(
"__SP_L__")),
323 if (SubTM->hasEIJMPCALL())
324 OutStreamer->emitAssignment(
325 MMI->getContext().getOrCreateSymbol(StringRef(
"__EIND__")),
328 if (SubTM->hasELPM())
329 OutStreamer->emitAssignment(
330 MMI->getContext().getOrCreateSymbol(StringRef(
"__RAMPZ__")),
334char AVRAsmPrinter::ID = 0;
340LLVMInitializeAVRAsmPrinter() {
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
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.
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<X> - 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,...