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);
166 assert(MO.
isReg() &&
"Unexpected inline asm memory operand");
172 if (
MI->getOperand(OpNum).getReg() == AVR::R31R30) {
174 }
else if (
MI->getOperand(OpNum).getReg() == AVR::R29R28) {
176 }
else if (
MI->getOperand(OpNum).getReg() == AVR::R27R26) {
179 assert(
false &&
"Wrong register class for memory operand.");
184 const InlineAsm::Flag OpFlags(
MI->getOperand(OpNum - 1).getImm());
185 const unsigned NumOpRegs = OpFlags.getNumOperandRegisters();
187 if (NumOpRegs == 2) {
188 assert(
MI->getOperand(OpNum).getReg() != AVR::R27R26 &&
189 "Base register X can not have offset/displacement.");
190 O <<
'+' <<
MI->getOperand(OpNum + 1).getImm();
196void AVRAsmPrinter::emitInstruction(
const MachineInstr *
MI) {
197 AVR_MC::verifyInstructionPredicates(
MI->getOpcode(),
198 getSubtargetInfo().getFeatureBits());
200 AVRMCInstLower MCInstLowering(OutContext, *
this);
203 MCInstLowering.lowerInstruction(*
MI,
I);
204 EmitToStreamer(*OutStreamer,
I);
207const MCExpr *AVRAsmPrinter::lowerConstant(
const Constant *CV,
208 const Constant *BaseCV,
210 MCContext &Ctx = OutContext;
223void AVRAsmPrinter::emitXXStructor(
const DataLayout &
DL,
const Constant *CV) {
224 if (!EmittedStructorSymbolAttrs) {
225 OutStreamer->emitRawComment(
226 " Emitting these undefined symbol references causes us to link the"
227 " libgcc code that runs our constructors/destructors");
228 OutStreamer->emitRawComment(
" This matches GCC's behavior");
230 MCSymbol *CtorsSym = OutContext.getOrCreateSymbol(
"__do_global_ctors");
231 OutStreamer->emitSymbolAttribute(CtorsSym,
MCSA_Global);
233 MCSymbol *DtorsSym = OutContext.getOrCreateSymbol(
"__do_global_dtors");
234 OutStreamer->emitSymbolAttribute(DtorsSym,
MCSA_Global);
236 EmittedStructorSymbolAttrs =
true;
242bool AVRAsmPrinter::doFinalization(
Module &M) {
243 const TargetLoweringObjectFile &TLOF = getObjFileLowering();
244 const AVRTargetMachine &TM = (
const AVRTargetMachine &)MMI->getTarget();
247 bool NeedsCopyData =
false;
248 bool NeedsClearBSS =
false;
249 for (
const auto &GO :
M.globals()) {
250 if (!GO.hasInitializer() || GO.hasAvailableExternallyLinkage())
254 if (GO.hasCommonLinkage()) {
256 NeedsClearBSS =
true;
261 if (
Section->getName().starts_with(
".data"))
262 NeedsCopyData =
true;
263 else if (
Section->getName().starts_with(
".rodata") && SubTM->hasLPM())
266 NeedsCopyData =
true;
267 else if (
Section->getName().starts_with(
".bss"))
268 NeedsClearBSS =
true;
271 MCSymbol *DoCopyData = OutContext.getOrCreateSymbol(
"__do_copy_data");
272 MCSymbol *DoClearBss = OutContext.getOrCreateSymbol(
"__do_clear_bss");
275 OutStreamer->emitRawComment(
276 " Declaring this symbol tells the CRT that it should");
277 OutStreamer->emitRawComment(
278 "copy all variables from program memory to RAM on startup");
279 OutStreamer->emitSymbolAttribute(DoCopyData,
MCSA_Global);
283 OutStreamer->emitRawComment(
284 " Declaring this symbol tells the CRT that it should");
285 OutStreamer->emitRawComment(
"clear the zeroed data section on startup");
286 OutStreamer->emitSymbolAttribute(DoClearBss,
MCSA_Global);
292void AVRAsmPrinter::emitStartOfAsmFile(
Module &M) {
293 const AVRTargetMachine &TM = (
const AVRTargetMachine &)MMI->
getTarget();
299 OutStreamer->emitAssignment(
300 MMI->getContext().getOrCreateSymbol(StringRef(
"__tmp_reg__")),
303 OutStreamer->emitAssignment(
304 MMI->getContext().getOrCreateSymbol(StringRef(
"__zero_reg__")),
307 OutStreamer->emitAssignment(
308 MMI->getContext().getOrCreateSymbol(StringRef(
"__SREG__")),
311 if (!SubTM->hasSmallStack())
312 OutStreamer->emitAssignment(
313 MMI->getContext().getOrCreateSymbol(StringRef(
"__SP_H__")),
316 OutStreamer->emitAssignment(
317 MMI->getContext().getOrCreateSymbol(StringRef(
"__SP_L__")),
320 if (SubTM->hasEIJMPCALL())
321 OutStreamer->emitAssignment(
322 MMI->getContext().getOrCreateSymbol(StringRef(
"__EIND__")),
325 if (SubTM->hasELPM())
326 OutStreamer->emitAssignment(
327 MMI->getContext().getOrCreateSymbol(StringRef(
"__RAMPZ__")),
331char AVRAsmPrinter::ID = 0;
337LLVMInitializeAVRAsmPrinter() {
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
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<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,...