1 //===-- AVRAsmPrinter.cpp - AVR LLVM assembly writer ----------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file contains a printer that converts from our internal representation
11 // of machine-dependent LLVM code to GAS-format AVR assembly language.
13 //===----------------------------------------------------------------------===//
16 #include "AVRMCInstLower.h"
17 #include "AVRSubtarget.h"
18 #include "InstPrinter/AVRInstPrinter.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
,
47 const char *Modifier
= 0);
49 bool PrintAsmOperand(const MachineInstr
*MI
, unsigned OpNum
,
50 unsigned AsmVariant
, const char *ExtraCode
,
51 raw_ostream
&O
) override
;
53 bool PrintAsmMemoryOperand(const MachineInstr
*MI
, unsigned OpNum
,
54 unsigned AsmVariant
, const char *ExtraCode
,
55 raw_ostream
&O
) override
;
57 void EmitInstruction(const MachineInstr
*MI
) override
;
60 const MCRegisterInfo
&MRI
;
63 void AVRAsmPrinter::printOperand(const MachineInstr
*MI
, unsigned OpNo
,
64 raw_ostream
&O
, const char *Modifier
) {
65 const MachineOperand
&MO
= MI
->getOperand(OpNo
);
67 switch (MO
.getType()) {
68 case MachineOperand::MO_Register
:
69 O
<< AVRInstPrinter::getPrettyRegisterName(MO
.getReg(), MRI
);
71 case MachineOperand::MO_Immediate
:
74 case MachineOperand::MO_GlobalAddress
:
75 O
<< getSymbol(MO
.getGlobal());
77 case MachineOperand::MO_ExternalSymbol
:
78 O
<< *GetExternalSymbolSymbol(MO
.getSymbolName());
80 case MachineOperand::MO_MachineBasicBlock
:
81 O
<< *MO
.getMBB()->getSymbol();
84 llvm_unreachable("Not implemented yet!");
88 bool AVRAsmPrinter::PrintAsmOperand(const MachineInstr
*MI
, unsigned OpNum
,
89 unsigned AsmVariant
, const char *ExtraCode
,
91 // Default asm printer can only deal with some extra codes,
93 bool Error
= AsmPrinter::PrintAsmOperand(MI
, OpNum
, AsmVariant
, ExtraCode
, O
);
95 if (Error
&& ExtraCode
&& ExtraCode
[0]) {
96 if (ExtraCode
[1] != 0)
97 return true; // Unknown modifier.
99 if (ExtraCode
[0] >= 'A' && ExtraCode
[0] <= 'Z') {
100 const MachineOperand
&RegOp
= MI
->getOperand(OpNum
);
102 assert(RegOp
.isReg() && "Operand must be a register when you're"
103 "using 'A'..'Z' operand extracodes.");
104 unsigned Reg
= RegOp
.getReg();
106 unsigned ByteNumber
= ExtraCode
[0] - 'A';
108 unsigned OpFlags
= MI
->getOperand(OpNum
- 1).getImm();
109 unsigned NumOpRegs
= InlineAsm::getNumOperandRegisters(OpFlags
);
112 const AVRSubtarget
&STI
= MF
->getSubtarget
<AVRSubtarget
>();
113 const TargetRegisterInfo
&TRI
= *STI
.getRegisterInfo();
115 const TargetRegisterClass
*RC
= TRI
.getMinimalPhysRegClass(Reg
);
116 unsigned BytesPerReg
= TRI
.getRegSizeInBits(*RC
) / 8;
117 assert(BytesPerReg
<= 2 && "Only 8 and 16 bit regs are supported.");
119 unsigned RegIdx
= ByteNumber
/ BytesPerReg
;
120 assert(RegIdx
< NumOpRegs
&& "Multibyte index out of range.");
122 Reg
= MI
->getOperand(OpNum
+ RegIdx
).getReg();
124 if (BytesPerReg
== 2) {
125 Reg
= TRI
.getSubReg(Reg
, ByteNumber
% BytesPerReg
? AVR::sub_hi
129 O
<< AVRInstPrinter::getPrettyRegisterName(Reg
, MRI
);
135 printOperand(MI
, OpNum
, O
);
140 bool AVRAsmPrinter::PrintAsmMemoryOperand(const MachineInstr
*MI
,
141 unsigned OpNum
, unsigned AsmVariant
,
142 const char *ExtraCode
,
144 if (ExtraCode
&& ExtraCode
[0]) {
145 llvm_unreachable("This branch is not implemented yet");
148 const MachineOperand
&MO
= MI
->getOperand(OpNum
);
150 assert(MO
.isReg() && "Unexpected inline asm memory operand");
152 // TODO: We should be able to look up the alternative name for
153 // the register if it's given.
154 // TableGen doesn't expose a way of getting retrieving names
156 if (MI
->getOperand(OpNum
).getReg() == AVR::R31R30
) {
159 assert(MI
->getOperand(OpNum
).getReg() == AVR::R29R28
&&
160 "Wrong register class for memory operand.");
164 // If NumOpRegs == 2, then we assume it is product of a FrameIndex expansion
165 // and the second operand is an Imm.
166 unsigned OpFlags
= MI
->getOperand(OpNum
- 1).getImm();
167 unsigned NumOpRegs
= InlineAsm::getNumOperandRegisters(OpFlags
);
169 if (NumOpRegs
== 2) {
170 O
<< '+' << MI
->getOperand(OpNum
+ 1).getImm();
176 void AVRAsmPrinter::EmitInstruction(const MachineInstr
*MI
) {
177 AVRMCInstLower
MCInstLowering(OutContext
, *this);
180 MCInstLowering
.lowerInstruction(*MI
, I
);
181 EmitToStreamer(*OutStreamer
, I
);
184 } // end of namespace llvm
186 extern "C" void LLVMInitializeAVRAsmPrinter() {
187 llvm::RegisterAsmPrinter
<llvm::AVRAsmPrinter
> X(llvm::getTheAVRTarget());