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,...