1 //===-- AVRAsmPrinter.cpp - AVR LLVM assembly writer ----------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file contains a printer that converts from our internal representation
10 // of machine-dependent LLVM code to GAS-format AVR assembly language.
12 //===----------------------------------------------------------------------===//
15 #include "AVRMCInstLower.h"
16 #include "AVRSubtarget.h"
17 #include "MCTargetDesc/AVRInstPrinter.h"
18 #include "TargetInfo/AVRTargetInfo.h"
20 #include "llvm/CodeGen/AsmPrinter.h"
21 #include "llvm/CodeGen/MachineFunction.h"
22 #include "llvm/CodeGen/MachineInstr.h"
23 #include "llvm/CodeGen/TargetRegisterInfo.h"
24 #include "llvm/CodeGen/TargetSubtargetInfo.h"
25 #include "llvm/IR/Mangler.h"
26 #include "llvm/MC/MCInst.h"
27 #include "llvm/MC/MCStreamer.h"
28 #include "llvm/MC/MCSymbol.h"
29 #include "llvm/Support/ErrorHandling.h"
30 #include "llvm/Support/TargetRegistry.h"
31 #include "llvm/Support/raw_ostream.h"
33 #define DEBUG_TYPE "avr-asm-printer"
37 /// An AVR assembly code printer.
38 class AVRAsmPrinter
: public AsmPrinter
{
40 AVRAsmPrinter(TargetMachine
&TM
,
41 std::unique_ptr
<MCStreamer
> Streamer
)
42 : AsmPrinter(TM
, std::move(Streamer
)), MRI(*TM
.getMCRegisterInfo()) { }
44 StringRef
getPassName() const override
{ return "AVR Assembly Printer"; }
46 void printOperand(const MachineInstr
*MI
, unsigned OpNo
, raw_ostream
&O
);
48 bool PrintAsmOperand(const MachineInstr
*MI
, unsigned OpNum
,
49 const char *ExtraCode
, raw_ostream
&O
) override
;
51 bool PrintAsmMemoryOperand(const MachineInstr
*MI
, unsigned OpNum
,
52 const char *ExtraCode
, raw_ostream
&O
) override
;
54 void EmitInstruction(const MachineInstr
*MI
) override
;
57 const MCRegisterInfo
&MRI
;
60 void AVRAsmPrinter::printOperand(const MachineInstr
*MI
, unsigned OpNo
,
62 const MachineOperand
&MO
= MI
->getOperand(OpNo
);
64 switch (MO
.getType()) {
65 case MachineOperand::MO_Register
:
66 O
<< AVRInstPrinter::getPrettyRegisterName(MO
.getReg(), MRI
);
68 case MachineOperand::MO_Immediate
:
71 case MachineOperand::MO_GlobalAddress
:
72 O
<< getSymbol(MO
.getGlobal());
74 case MachineOperand::MO_ExternalSymbol
:
75 O
<< *GetExternalSymbolSymbol(MO
.getSymbolName());
77 case MachineOperand::MO_MachineBasicBlock
:
78 O
<< *MO
.getMBB()->getSymbol();
81 llvm_unreachable("Not implemented yet!");
85 bool AVRAsmPrinter::PrintAsmOperand(const MachineInstr
*MI
, unsigned OpNum
,
86 const char *ExtraCode
, raw_ostream
&O
) {
87 // Default asm printer can only deal with some extra codes,
89 bool Error
= AsmPrinter::PrintAsmOperand(MI
, OpNum
, ExtraCode
, O
);
91 if (Error
&& ExtraCode
&& ExtraCode
[0]) {
92 if (ExtraCode
[1] != 0)
93 return true; // Unknown modifier.
95 if (ExtraCode
[0] >= 'A' && ExtraCode
[0] <= 'Z') {
96 const MachineOperand
&RegOp
= MI
->getOperand(OpNum
);
98 assert(RegOp
.isReg() && "Operand must be a register when you're"
99 "using 'A'..'Z' operand extracodes.");
100 Register Reg
= RegOp
.getReg();
102 unsigned ByteNumber
= ExtraCode
[0] - 'A';
104 unsigned OpFlags
= MI
->getOperand(OpNum
- 1).getImm();
105 unsigned NumOpRegs
= InlineAsm::getNumOperandRegisters(OpFlags
);
108 const AVRSubtarget
&STI
= MF
->getSubtarget
<AVRSubtarget
>();
109 const TargetRegisterInfo
&TRI
= *STI
.getRegisterInfo();
111 const TargetRegisterClass
*RC
= TRI
.getMinimalPhysRegClass(Reg
);
112 unsigned BytesPerReg
= TRI
.getRegSizeInBits(*RC
) / 8;
113 assert(BytesPerReg
<= 2 && "Only 8 and 16 bit regs are supported.");
115 unsigned RegIdx
= ByteNumber
/ BytesPerReg
;
116 assert(RegIdx
< NumOpRegs
&& "Multibyte index out of range.");
118 Reg
= MI
->getOperand(OpNum
+ RegIdx
).getReg();
120 if (BytesPerReg
== 2) {
121 Reg
= TRI
.getSubReg(Reg
, ByteNumber
% BytesPerReg
? AVR::sub_hi
125 O
<< AVRInstPrinter::getPrettyRegisterName(Reg
, MRI
);
131 printOperand(MI
, OpNum
, O
);
136 bool AVRAsmPrinter::PrintAsmMemoryOperand(const MachineInstr
*MI
,
137 unsigned OpNum
, const char *ExtraCode
,
139 if (ExtraCode
&& ExtraCode
[0]) {
140 llvm_unreachable("This branch is not implemented yet");
143 const MachineOperand
&MO
= MI
->getOperand(OpNum
);
145 assert(MO
.isReg() && "Unexpected inline asm memory operand");
147 // TODO: We should be able to look up the alternative name for
148 // the register if it's given.
149 // TableGen doesn't expose a way of getting retrieving names
151 if (MI
->getOperand(OpNum
).getReg() == AVR::R31R30
) {
154 assert(MI
->getOperand(OpNum
).getReg() == AVR::R29R28
&&
155 "Wrong register class for memory operand.");
159 // If NumOpRegs == 2, then we assume it is product of a FrameIndex expansion
160 // and the second operand is an Imm.
161 unsigned OpFlags
= MI
->getOperand(OpNum
- 1).getImm();
162 unsigned NumOpRegs
= InlineAsm::getNumOperandRegisters(OpFlags
);
164 if (NumOpRegs
== 2) {
165 O
<< '+' << MI
->getOperand(OpNum
+ 1).getImm();
171 void AVRAsmPrinter::EmitInstruction(const MachineInstr
*MI
) {
172 AVRMCInstLower
MCInstLowering(OutContext
, *this);
175 MCInstLowering
.lowerInstruction(*MI
, I
);
176 EmitToStreamer(*OutStreamer
, I
);
179 } // end of namespace llvm
181 extern "C" void LLVMInitializeAVRAsmPrinter() {
182 llvm::RegisterAsmPrinter
<llvm::AVRAsmPrinter
> X(llvm::getTheAVRTarget());