1 //===-- AVRAsmPrinter.cpp - AVR LLVM assembly writer ----------------------===// 2 // 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 6 // 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" 20 #include "llvm/CodeGen/MachineFunction.h" 21 #include "llvm/CodeGen/MachineInstr.h" 22 #include "llvm/CodeGen/TargetRegisterInfo.h" 23 #include "llvm/CodeGen/TargetSubtargetInfo.h" 24 #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" 31 32 #define DEBUG_TYPE "avr-asm-printer" 33 34 namespace llvm { 35 36 /// An AVR assembly code printer. 37 class AVRAsmPrinter : public AsmPrinter { 38 public: 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 47 bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, 48 const char *ExtraCode, raw_ostream &O) override; 49 50 bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, 51 const char *ExtraCode, raw_ostream &O) override; 52 53 void EmitInstruction(const MachineInstr *MI) override; 54 55 private: 56 const MCRegisterInfo &MRI; 57 }; 58 59 void AVRAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo, 60 raw_ostream &O) { 61 const MachineOperand &MO = MI->getOperand(OpNo); 62 63 switch (MO.getType()) { 64 case MachineOperand::MO_Register: 65 O << AVRInstPrinter::getPrettyRegisterName(MO.getReg(), MRI); 66 break; 67 case MachineOperand::MO_Immediate: 68 O << MO.getImm(); 69 break; 70 case MachineOperand::MO_GlobalAddress: 71 O << getSymbol(MO.getGlobal()); 72 break; 73 case MachineOperand::MO_ExternalSymbol: 74 O << *GetExternalSymbolSymbol(MO.getSymbolName()); 75 break; 76 case MachineOperand::MO_MachineBasicBlock: 77 O << *MO.getMBB()->getSymbol(); 78 break; 79 default: 80 llvm_unreachable("Not implemented yet!"); 81 } 82 } 83 84 bool AVRAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, 85 const char *ExtraCode, raw_ostream &O) { 86 // Default asm printer can only deal with some extra codes, 87 // so try it first. 88 bool Error = AsmPrinter::PrintAsmOperand(MI, OpNum, ExtraCode, O); 89 90 if (Error && ExtraCode && ExtraCode[0]) { 91 if (ExtraCode[1] != 0) 92 return true; // Unknown modifier. 93 94 if (ExtraCode[0] >= 'A' && ExtraCode[0] <= 'Z') { 95 const MachineOperand &RegOp = MI->getOperand(OpNum); 96 97 assert(RegOp.isReg() && "Operand must be a register when you're" 98 "using 'A'..'Z' operand extracodes."); 99 unsigned Reg = RegOp.getReg(); 100 101 unsigned ByteNumber = ExtraCode[0] - 'A'; 102 103 unsigned OpFlags = MI->getOperand(OpNum - 1).getImm(); 104 unsigned NumOpRegs = InlineAsm::getNumOperandRegisters(OpFlags); 105 (void)NumOpRegs; 106 107 const AVRSubtarget &STI = MF->getSubtarget<AVRSubtarget>(); 108 const TargetRegisterInfo &TRI = *STI.getRegisterInfo(); 109 110 const TargetRegisterClass *RC = TRI.getMinimalPhysRegClass(Reg); 111 unsigned BytesPerReg = TRI.getRegSizeInBits(*RC) / 8; 112 assert(BytesPerReg <= 2 && "Only 8 and 16 bit regs are supported."); 113 114 unsigned RegIdx = ByteNumber / BytesPerReg; 115 assert(RegIdx < NumOpRegs && "Multibyte index out of range."); 116 117 Reg = MI->getOperand(OpNum + RegIdx).getReg(); 118 119 if (BytesPerReg == 2) { 120 Reg = TRI.getSubReg(Reg, ByteNumber % BytesPerReg ? AVR::sub_hi 121 : AVR::sub_lo); 122 } 123 124 O << AVRInstPrinter::getPrettyRegisterName(Reg, MRI); 125 return false; 126 } 127 } 128 129 if (Error) 130 printOperand(MI, OpNum, O); 131 132 return false; 133 } 134 135 bool AVRAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, 136 unsigned OpNum, const char *ExtraCode, 137 raw_ostream &O) { 138 if (ExtraCode && ExtraCode[0]) { 139 llvm_unreachable("This branch is not implemented yet"); 140 } 141 142 const MachineOperand &MO = MI->getOperand(OpNum); 143 (void)MO; 144 assert(MO.isReg() && "Unexpected inline asm memory operand"); 145 146 // TODO: We should be able to look up the alternative name for 147 // the register if it's given. 148 // TableGen doesn't expose a way of getting retrieving names 149 // for registers. 150 if (MI->getOperand(OpNum).getReg() == AVR::R31R30) { 151 O << "Z"; 152 } else { 153 assert(MI->getOperand(OpNum).getReg() == AVR::R29R28 && 154 "Wrong register class for memory operand."); 155 O << "Y"; 156 } 157 158 // If NumOpRegs == 2, then we assume it is product of a FrameIndex expansion 159 // and the second operand is an Imm. 160 unsigned OpFlags = MI->getOperand(OpNum - 1).getImm(); 161 unsigned NumOpRegs = InlineAsm::getNumOperandRegisters(OpFlags); 162 163 if (NumOpRegs == 2) { 164 O << '+' << MI->getOperand(OpNum + 1).getImm(); 165 } 166 167 return false; 168 } 169 170 void AVRAsmPrinter::EmitInstruction(const MachineInstr *MI) { 171 AVRMCInstLower MCInstLowering(OutContext, *this); 172 173 MCInst I; 174 MCInstLowering.lowerInstruction(*MI, I); 175 EmitToStreamer(*OutStreamer, I); 176 } 177 178 } // end of namespace llvm 179 180 extern "C" void LLVMInitializeAVRAsmPrinter() { 181 llvm::RegisterAsmPrinter<llvm::AVRAsmPrinter> X(llvm::getTheAVRTarget()); 182 } 183 184