41#define DEBUG_TYPE "avr-asm-printer"
50 AVRAsmPrinter(
TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
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);
118 if (ExtraCode && ExtraCode[0] && MO.
isReg()) {
120 if (ExtraCode[1] != 0 || ExtraCode[0] <
'A' || ExtraCode[0] >
'Z')
125 unsigned ByteNumber = ExtraCode[0] -
'A';
126 const InlineAsm::Flag OpFlags(
MI->getOperand(OpNum - 1).getImm());
127 const unsigned NumOpRegs = OpFlags.getNumOperandRegisters();
129 const AVRSubtarget &STI = MF->getSubtarget<AVRSubtarget>();
132 const TargetRegisterClass *RC =
TRI.getMinimalPhysRegClass(
Reg);
133 unsigned BytesPerReg =
TRI.getRegSizeInBits(*RC) / 8;
134 assert(BytesPerReg <= 2 &&
"Only 8 and 16 bit regs are supported.");
136 unsigned RegIdx = ByteNumber / BytesPerReg;
137 if (RegIdx >= NumOpRegs)
139 Reg =
MI->getOperand(OpNum + RegIdx).getReg();
141 if (BytesPerReg == 2) {
142 Reg =
TRI.getSubReg(
Reg, (ByteNumber % BytesPerReg) ? AVR::sub_hi
151 PrintSymbolOperand(MO, O);
158bool AVRAsmPrinter::PrintAsmMemoryOperand(
const MachineInstr *
MI,
159 unsigned OpNum,
const char *ExtraCode,
161 if (ExtraCode && ExtraCode[0])
164 const MachineOperand &MO =
MI->getOperand(OpNum);
168 PrintSymbolOperand(MO, O);
172 assert(MO.
isReg() &&
"Unexpected inline asm memory operand");
178 if (
MI->getOperand(OpNum).getReg() == AVR::R31R30) {
180 }
else if (
MI->getOperand(OpNum).getReg() == AVR::R29R28) {
182 }
else if (
MI->getOperand(OpNum).getReg() == AVR::R27R26) {
185 assert(
false &&
"Wrong register class for memory operand.");
190 const InlineAsm::Flag OpFlags(
MI->getOperand(OpNum - 1).getImm());
191 const unsigned NumOpRegs = OpFlags.getNumOperandRegisters();
193 if (NumOpRegs == 2) {
194 assert(
MI->getOperand(OpNum).getReg() != AVR::R27R26 &&
195 "Base register X can not have offset/displacement.");
196 O <<
'+' <<
MI->getOperand(OpNum + 1).getImm();
202void AVRAsmPrinter::emitInstruction(
const MachineInstr *
MI) {
203 AVR_MC::verifyInstructionPredicates(
MI->getOpcode(),
204 getSubtargetInfo().getFeatureBits());
206 AVRMCInstLower MCInstLowering(OutContext, *
this);
209 MCInstLowering.lowerInstruction(*
MI,
I);
210 EmitToStreamer(*OutStreamer,
I);
213const MCExpr *AVRAsmPrinter::lowerConstant(
const Constant *CV,
214 const Constant *BaseCV,
216 MCContext &Ctx = OutContext;
229void AVRAsmPrinter::emitXXStructor(
const DataLayout &
DL,
const Constant *CV) {
230 if (!EmittedStructorSymbolAttrs) {
231 OutStreamer->emitRawComment(
232 " Emitting these undefined symbol references causes us to link the"
233 " libgcc code that runs our constructors/destructors");
234 OutStreamer->emitRawComment(
" This matches GCC's behavior");
236 MCSymbol *CtorsSym = OutContext.getOrCreateSymbol(
"__do_global_ctors");
237 OutStreamer->emitSymbolAttribute(CtorsSym,
MCSA_Global);
239 MCSymbol *DtorsSym = OutContext.getOrCreateSymbol(
"__do_global_dtors");
240 OutStreamer->emitSymbolAttribute(DtorsSym,
MCSA_Global);
242 EmittedStructorSymbolAttrs =
true;
248bool AVRAsmPrinter::doFinalization(
Module &M) {
249 const TargetLoweringObjectFile &TLOF = getObjFileLowering();
250 const AVRTargetMachine &TM = (
const AVRTargetMachine &)MMI->getTarget();
253 bool NeedsCopyData =
false;
254 bool NeedsClearBSS =
false;
255 for (
const auto &GO :
M.globals()) {
256 if (!GO.hasInitializer() || GO.hasAvailableExternallyLinkage())
260 if (GO.hasCommonLinkage()) {
262 NeedsClearBSS =
true;
267 if (
Section->getName().starts_with(
".data"))
268 NeedsCopyData =
true;
269 else if (
Section->getName().starts_with(
".rodata") && SubTM->hasLPM())
272 NeedsCopyData =
true;
273 else if (
Section->getName().starts_with(
".bss"))
274 NeedsClearBSS =
true;
277 MCSymbol *DoCopyData = OutContext.getOrCreateSymbol(
"__do_copy_data");
278 MCSymbol *DoClearBss = OutContext.getOrCreateSymbol(
"__do_clear_bss");
281 OutStreamer->emitRawComment(
282 " Declaring this symbol tells the CRT that it should");
283 OutStreamer->emitRawComment(
284 "copy all variables from program memory to RAM on startup");
285 OutStreamer->emitSymbolAttribute(DoCopyData,
MCSA_Global);
289 OutStreamer->emitRawComment(
290 " Declaring this symbol tells the CRT that it should");
291 OutStreamer->emitRawComment(
"clear the zeroed data section on startup");
292 OutStreamer->emitSymbolAttribute(DoClearBss,
MCSA_Global);
298void AVRAsmPrinter::emitStartOfAsmFile(
Module &M) {
299 const AVRTargetMachine &TM = (
const AVRTargetMachine &)MMI->
getTarget();
305 OutStreamer->emitAssignment(
306 MMI->getContext().getOrCreateSymbol(StringRef(
"__tmp_reg__")),
309 OutStreamer->emitAssignment(
310 MMI->getContext().getOrCreateSymbol(StringRef(
"__zero_reg__")),
313 OutStreamer->emitAssignment(
314 MMI->getContext().getOrCreateSymbol(StringRef(
"__SREG__")),
317 if (!SubTM->hasSmallStack())
318 OutStreamer->emitAssignment(
319 MMI->getContext().getOrCreateSymbol(StringRef(
"__SP_H__")),
322 OutStreamer->emitAssignment(
323 MMI->getContext().getOrCreateSymbol(StringRef(
"__SP_L__")),
326 if (SubTM->hasEIJMPCALL())
327 OutStreamer->emitAssignment(
328 MMI->getContext().getOrCreateSymbol(StringRef(
"__EIND__")),
331 if (SubTM->hasELPM())
332 OutStreamer->emitAssignment(
333 MMI->getContext().getOrCreateSymbol(StringRef(
"__RAMPZ__")),
337char AVRAsmPrinter::ID = 0;
343LLVMInitializeAVRAsmPrinter() {
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 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
bool isSymbol() const
isSymbol - Tests if this is a MO_ExternalSymbol operand.
bool isGlobal() const
isGlobal - Tests if this is a MO_GlobalAddress operand.
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.
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<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,...