blob: f96f58860c77b0fbcb5d1341e9e931d66a141f41 [file] [log] [blame]
Dylan McKay4d82df32b2016-10-08 00:02:36 +00001//===-- AVRAsmPrinter.cpp - AVR LLVM assembly writer ----------------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Dylan McKay4d82df32b2016-10-08 00:02:36 +00006//
7//===----------------------------------------------------------------------===//
8//
9// This file contains a printer that converts from our internal representation
10// of machine-dependent LLVM code to GAS-format AVR assembly language.
11//
12//===----------------------------------------------------------------------===//
13
14#include "AVR.h"
15#include "AVRMCInstLower.h"
16#include "AVRSubtarget.h"
17#include "InstPrinter/AVRInstPrinter.h"
18
19#include "llvm/CodeGen/AsmPrinter.h"
Dylan McKay4d82df32b2016-10-08 00:02:36 +000020#include "llvm/CodeGen/MachineFunction.h"
Chandler Carruth6bda14b2017-06-06 11:49:48 +000021#include "llvm/CodeGen/MachineInstr.h"
David Blaikieb3bde2e2017-11-17 01:07:10 +000022#include "llvm/CodeGen/TargetRegisterInfo.h"
23#include "llvm/CodeGen/TargetSubtargetInfo.h"
Dylan McKay4d82df32b2016-10-08 00:02:36 +000024#include "llvm/IR/Mangler.h"
25#include "llvm/MC/MCInst.h"
26#include "llvm/MC/MCStreamer.h"
27#include "llvm/MC/MCSymbol.h"
28#include "llvm/Support/ErrorHandling.h"
29#include "llvm/Support/TargetRegistry.h"
30#include "llvm/Support/raw_ostream.h"
Dylan McKay4d82df32b2016-10-08 00:02:36 +000031
32#define DEBUG_TYPE "avr-asm-printer"
33
34namespace llvm {
35
36/// An AVR assembly code printer.
37class AVRAsmPrinter : public AsmPrinter {
38public:
39 AVRAsmPrinter(TargetMachine &TM,
40 std::unique_ptr<MCStreamer> Streamer)
41 : AsmPrinter(TM, std::move(Streamer)), MRI(*TM.getMCRegisterInfo()) { }
42
43 StringRef getPassName() const override { return "AVR Assembly Printer"; }
44
45 void printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O,
46 const char *Modifier = 0);
47
48 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
49 unsigned AsmVariant, const char *ExtraCode,
50 raw_ostream &O) override;
51
52 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum,
53 unsigned AsmVariant, const char *ExtraCode,
54 raw_ostream &O) override;
55
56 void EmitInstruction(const MachineInstr *MI) override;
57
58private:
59 const MCRegisterInfo &MRI;
60};
61
62void AVRAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo,
63 raw_ostream &O, const char *Modifier) {
64 const MachineOperand &MO = MI->getOperand(OpNo);
65
66 switch (MO.getType()) {
67 case MachineOperand::MO_Register:
68 O << AVRInstPrinter::getPrettyRegisterName(MO.getReg(), MRI);
69 break;
70 case MachineOperand::MO_Immediate:
71 O << MO.getImm();
72 break;
73 case MachineOperand::MO_GlobalAddress:
74 O << getSymbol(MO.getGlobal());
75 break;
76 case MachineOperand::MO_ExternalSymbol:
77 O << *GetExternalSymbolSymbol(MO.getSymbolName());
78 break;
79 case MachineOperand::MO_MachineBasicBlock:
80 O << *MO.getMBB()->getSymbol();
81 break;
82 default:
83 llvm_unreachable("Not implemented yet!");
84 }
85}
86
87bool AVRAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
88 unsigned AsmVariant, const char *ExtraCode,
89 raw_ostream &O) {
90 // Default asm printer can only deal with some extra codes,
91 // so try it first.
92 bool Error = AsmPrinter::PrintAsmOperand(MI, OpNum, AsmVariant, ExtraCode, O);
93
94 if (Error && ExtraCode && ExtraCode[0]) {
95 if (ExtraCode[1] != 0)
96 return true; // Unknown modifier.
97
98 if (ExtraCode[0] >= 'A' && ExtraCode[0] <= 'Z') {
99 const MachineOperand &RegOp = MI->getOperand(OpNum);
100
101 assert(RegOp.isReg() && "Operand must be a register when you're"
102 "using 'A'..'Z' operand extracodes.");
103 unsigned Reg = RegOp.getReg();
104
105 unsigned ByteNumber = ExtraCode[0] - 'A';
106
107 unsigned OpFlags = MI->getOperand(OpNum - 1).getImm();
108 unsigned NumOpRegs = InlineAsm::getNumOperandRegisters(OpFlags);
Dylan McKay1a55f202016-11-19 01:33:42 +0000109 (void)NumOpRegs;
Dylan McKay4d82df32b2016-10-08 00:02:36 +0000110
111 const AVRSubtarget &STI = MF->getSubtarget<AVRSubtarget>();
112 const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
113
Krzysztof Parzyszek44e25f32017-04-24 18:55:33 +0000114 const TargetRegisterClass *RC = TRI.getMinimalPhysRegClass(Reg);
115 unsigned BytesPerReg = TRI.getRegSizeInBits(*RC) / 8;
Dylan McKay4d82df32b2016-10-08 00:02:36 +0000116 assert(BytesPerReg <= 2 && "Only 8 and 16 bit regs are supported.");
117
118 unsigned RegIdx = ByteNumber / BytesPerReg;
119 assert(RegIdx < NumOpRegs && "Multibyte index out of range.");
120
121 Reg = MI->getOperand(OpNum + RegIdx).getReg();
122
123 if (BytesPerReg == 2) {
124 Reg = TRI.getSubReg(Reg, ByteNumber % BytesPerReg ? AVR::sub_hi
125 : AVR::sub_lo);
126 }
127
128 O << AVRInstPrinter::getPrettyRegisterName(Reg, MRI);
129 return false;
130 }
131 }
132
Dylan McKayb78f3662017-02-05 10:42:49 +0000133 if (Error)
134 printOperand(MI, OpNum, O);
Dylan McKay4d82df32b2016-10-08 00:02:36 +0000135
136 return false;
137}
138
139bool AVRAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
140 unsigned OpNum, unsigned AsmVariant,
141 const char *ExtraCode,
142 raw_ostream &O) {
143 if (ExtraCode && ExtraCode[0]) {
144 llvm_unreachable("This branch is not implemented yet");
145 }
146
147 const MachineOperand &MO = MI->getOperand(OpNum);
Dylan McKay1a55f202016-11-19 01:33:42 +0000148 (void)MO;
Dylan McKay4d82df32b2016-10-08 00:02:36 +0000149 assert(MO.isReg() && "Unexpected inline asm memory operand");
150
Dylan McKay946ab552017-07-11 05:14:40 +0000151 // TODO: We should be able to look up the alternative name for
152 // the register if it's given.
153 // TableGen doesn't expose a way of getting retrieving names
154 // for registers.
Dylan McKay4d82df32b2016-10-08 00:02:36 +0000155 if (MI->getOperand(OpNum).getReg() == AVR::R31R30) {
156 O << "Z";
157 } else {
158 assert(MI->getOperand(OpNum).getReg() == AVR::R29R28 &&
159 "Wrong register class for memory operand.");
160 O << "Y";
161 }
162
163 // If NumOpRegs == 2, then we assume it is product of a FrameIndex expansion
164 // and the second operand is an Imm.
165 unsigned OpFlags = MI->getOperand(OpNum - 1).getImm();
166 unsigned NumOpRegs = InlineAsm::getNumOperandRegisters(OpFlags);
167
168 if (NumOpRegs == 2) {
169 O << '+' << MI->getOperand(OpNum + 1).getImm();
170 }
171
172 return false;
173}
174
175void AVRAsmPrinter::EmitInstruction(const MachineInstr *MI) {
176 AVRMCInstLower MCInstLowering(OutContext, *this);
177
178 MCInst I;
179 MCInstLowering.lowerInstruction(*MI, I);
180 EmitToStreamer(*OutStreamer, I);
181}
182
183} // end of namespace llvm
184
185extern "C" void LLVMInitializeAVRAsmPrinter() {
Mehdi Aminif42454b2016-10-09 23:00:34 +0000186 llvm::RegisterAsmPrinter<llvm::AVRAsmPrinter> X(llvm::getTheAVRTarget());
Dylan McKay4d82df32b2016-10-08 00:02:36 +0000187}
188