14d82df32SDylan McKay //===-- AVRAsmPrinter.cpp - AVR LLVM assembly writer ----------------------===// 24d82df32SDylan McKay // 32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 64d82df32SDylan McKay // 74d82df32SDylan McKay //===----------------------------------------------------------------------===// 84d82df32SDylan McKay // 94d82df32SDylan McKay // This file contains a printer that converts from our internal representation 104d82df32SDylan McKay // of machine-dependent LLVM code to GAS-format AVR assembly language. 114d82df32SDylan McKay // 124d82df32SDylan McKay //===----------------------------------------------------------------------===// 134d82df32SDylan McKay 144d82df32SDylan McKay #include "AVR.h" 154d82df32SDylan McKay #include "AVRMCInstLower.h" 164d82df32SDylan McKay #include "AVRSubtarget.h" 17bf9e67b5SRichard Trieu #include "MCTargetDesc/AVRInstPrinter.h" 18*e982b420SRichard Trieu #include "TargetInfo/AVRTargetInfo.h" 194d82df32SDylan McKay 204d82df32SDylan McKay #include "llvm/CodeGen/AsmPrinter.h" 214d82df32SDylan McKay #include "llvm/CodeGen/MachineFunction.h" 226bda14b3SChandler Carruth #include "llvm/CodeGen/MachineInstr.h" 23b3bde2eaSDavid Blaikie #include "llvm/CodeGen/TargetRegisterInfo.h" 24b3bde2eaSDavid Blaikie #include "llvm/CodeGen/TargetSubtargetInfo.h" 254d82df32SDylan McKay #include "llvm/IR/Mangler.h" 264d82df32SDylan McKay #include "llvm/MC/MCInst.h" 274d82df32SDylan McKay #include "llvm/MC/MCStreamer.h" 284d82df32SDylan McKay #include "llvm/MC/MCSymbol.h" 294d82df32SDylan McKay #include "llvm/Support/ErrorHandling.h" 304d82df32SDylan McKay #include "llvm/Support/TargetRegistry.h" 314d82df32SDylan McKay #include "llvm/Support/raw_ostream.h" 324d82df32SDylan McKay 334d82df32SDylan McKay #define DEBUG_TYPE "avr-asm-printer" 344d82df32SDylan McKay 354d82df32SDylan McKay namespace llvm { 364d82df32SDylan McKay 374d82df32SDylan McKay /// An AVR assembly code printer. 384d82df32SDylan McKay class AVRAsmPrinter : public AsmPrinter { 394d82df32SDylan McKay public: 404d82df32SDylan McKay AVRAsmPrinter(TargetMachine &TM, 414d82df32SDylan McKay std::unique_ptr<MCStreamer> Streamer) 424d82df32SDylan McKay : AsmPrinter(TM, std::move(Streamer)), MRI(*TM.getMCRegisterInfo()) { } 434d82df32SDylan McKay 444d82df32SDylan McKay StringRef getPassName() const override { return "AVR Assembly Printer"; } 454d82df32SDylan McKay 467ab164c4SNick Desaulniers void printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O); 474d82df32SDylan McKay 484d82df32SDylan McKay bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, 495277b3ffSNick Desaulniers const char *ExtraCode, raw_ostream &O) override; 504d82df32SDylan McKay 514d82df32SDylan McKay bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, 525277b3ffSNick Desaulniers const char *ExtraCode, raw_ostream &O) override; 534d82df32SDylan McKay 544d82df32SDylan McKay void EmitInstruction(const MachineInstr *MI) override; 554d82df32SDylan McKay 564d82df32SDylan McKay private: 574d82df32SDylan McKay const MCRegisterInfo &MRI; 584d82df32SDylan McKay }; 594d82df32SDylan McKay 604d82df32SDylan McKay void AVRAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo, 617ab164c4SNick Desaulniers raw_ostream &O) { 624d82df32SDylan McKay const MachineOperand &MO = MI->getOperand(OpNo); 634d82df32SDylan McKay 644d82df32SDylan McKay switch (MO.getType()) { 654d82df32SDylan McKay case MachineOperand::MO_Register: 664d82df32SDylan McKay O << AVRInstPrinter::getPrettyRegisterName(MO.getReg(), MRI); 674d82df32SDylan McKay break; 684d82df32SDylan McKay case MachineOperand::MO_Immediate: 694d82df32SDylan McKay O << MO.getImm(); 704d82df32SDylan McKay break; 714d82df32SDylan McKay case MachineOperand::MO_GlobalAddress: 724d82df32SDylan McKay O << getSymbol(MO.getGlobal()); 734d82df32SDylan McKay break; 744d82df32SDylan McKay case MachineOperand::MO_ExternalSymbol: 754d82df32SDylan McKay O << *GetExternalSymbolSymbol(MO.getSymbolName()); 764d82df32SDylan McKay break; 774d82df32SDylan McKay case MachineOperand::MO_MachineBasicBlock: 784d82df32SDylan McKay O << *MO.getMBB()->getSymbol(); 794d82df32SDylan McKay break; 804d82df32SDylan McKay default: 814d82df32SDylan McKay llvm_unreachable("Not implemented yet!"); 824d82df32SDylan McKay } 834d82df32SDylan McKay } 844d82df32SDylan McKay 854d82df32SDylan McKay bool AVRAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, 865277b3ffSNick Desaulniers const char *ExtraCode, raw_ostream &O) { 874d82df32SDylan McKay // Default asm printer can only deal with some extra codes, 884d82df32SDylan McKay // so try it first. 895277b3ffSNick Desaulniers bool Error = AsmPrinter::PrintAsmOperand(MI, OpNum, ExtraCode, O); 904d82df32SDylan McKay 914d82df32SDylan McKay if (Error && ExtraCode && ExtraCode[0]) { 924d82df32SDylan McKay if (ExtraCode[1] != 0) 934d82df32SDylan McKay return true; // Unknown modifier. 944d82df32SDylan McKay 954d82df32SDylan McKay if (ExtraCode[0] >= 'A' && ExtraCode[0] <= 'Z') { 964d82df32SDylan McKay const MachineOperand &RegOp = MI->getOperand(OpNum); 974d82df32SDylan McKay 984d82df32SDylan McKay assert(RegOp.isReg() && "Operand must be a register when you're" 994d82df32SDylan McKay "using 'A'..'Z' operand extracodes."); 1004d82df32SDylan McKay unsigned Reg = RegOp.getReg(); 1014d82df32SDylan McKay 1024d82df32SDylan McKay unsigned ByteNumber = ExtraCode[0] - 'A'; 1034d82df32SDylan McKay 1044d82df32SDylan McKay unsigned OpFlags = MI->getOperand(OpNum - 1).getImm(); 1054d82df32SDylan McKay unsigned NumOpRegs = InlineAsm::getNumOperandRegisters(OpFlags); 1061a55f201SDylan McKay (void)NumOpRegs; 1074d82df32SDylan McKay 1084d82df32SDylan McKay const AVRSubtarget &STI = MF->getSubtarget<AVRSubtarget>(); 1094d82df32SDylan McKay const TargetRegisterInfo &TRI = *STI.getRegisterInfo(); 1104d82df32SDylan McKay 11144e25f37SKrzysztof Parzyszek const TargetRegisterClass *RC = TRI.getMinimalPhysRegClass(Reg); 11244e25f37SKrzysztof Parzyszek unsigned BytesPerReg = TRI.getRegSizeInBits(*RC) / 8; 1134d82df32SDylan McKay assert(BytesPerReg <= 2 && "Only 8 and 16 bit regs are supported."); 1144d82df32SDylan McKay 1154d82df32SDylan McKay unsigned RegIdx = ByteNumber / BytesPerReg; 1164d82df32SDylan McKay assert(RegIdx < NumOpRegs && "Multibyte index out of range."); 1174d82df32SDylan McKay 1184d82df32SDylan McKay Reg = MI->getOperand(OpNum + RegIdx).getReg(); 1194d82df32SDylan McKay 1204d82df32SDylan McKay if (BytesPerReg == 2) { 1214d82df32SDylan McKay Reg = TRI.getSubReg(Reg, ByteNumber % BytesPerReg ? AVR::sub_hi 1224d82df32SDylan McKay : AVR::sub_lo); 1234d82df32SDylan McKay } 1244d82df32SDylan McKay 1254d82df32SDylan McKay O << AVRInstPrinter::getPrettyRegisterName(Reg, MRI); 1264d82df32SDylan McKay return false; 1274d82df32SDylan McKay } 1284d82df32SDylan McKay } 1294d82df32SDylan McKay 130b78f3665SDylan McKay if (Error) 1314d82df32SDylan McKay printOperand(MI, OpNum, O); 1324d82df32SDylan McKay 1334d82df32SDylan McKay return false; 1344d82df32SDylan McKay } 1354d82df32SDylan McKay 1364d82df32SDylan McKay bool AVRAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, 1375277b3ffSNick Desaulniers unsigned OpNum, const char *ExtraCode, 1384d82df32SDylan McKay raw_ostream &O) { 1394d82df32SDylan McKay if (ExtraCode && ExtraCode[0]) { 1404d82df32SDylan McKay llvm_unreachable("This branch is not implemented yet"); 1414d82df32SDylan McKay } 1424d82df32SDylan McKay 1434d82df32SDylan McKay const MachineOperand &MO = MI->getOperand(OpNum); 1441a55f201SDylan McKay (void)MO; 1454d82df32SDylan McKay assert(MO.isReg() && "Unexpected inline asm memory operand"); 1464d82df32SDylan McKay 147946ab551SDylan McKay // TODO: We should be able to look up the alternative name for 148946ab551SDylan McKay // the register if it's given. 149946ab551SDylan McKay // TableGen doesn't expose a way of getting retrieving names 150946ab551SDylan McKay // for registers. 1514d82df32SDylan McKay if (MI->getOperand(OpNum).getReg() == AVR::R31R30) { 1524d82df32SDylan McKay O << "Z"; 1534d82df32SDylan McKay } else { 1544d82df32SDylan McKay assert(MI->getOperand(OpNum).getReg() == AVR::R29R28 && 1554d82df32SDylan McKay "Wrong register class for memory operand."); 1564d82df32SDylan McKay O << "Y"; 1574d82df32SDylan McKay } 1584d82df32SDylan McKay 1594d82df32SDylan McKay // If NumOpRegs == 2, then we assume it is product of a FrameIndex expansion 1604d82df32SDylan McKay // and the second operand is an Imm. 1614d82df32SDylan McKay unsigned OpFlags = MI->getOperand(OpNum - 1).getImm(); 1624d82df32SDylan McKay unsigned NumOpRegs = InlineAsm::getNumOperandRegisters(OpFlags); 1634d82df32SDylan McKay 1644d82df32SDylan McKay if (NumOpRegs == 2) { 1654d82df32SDylan McKay O << '+' << MI->getOperand(OpNum + 1).getImm(); 1664d82df32SDylan McKay } 1674d82df32SDylan McKay 1684d82df32SDylan McKay return false; 1694d82df32SDylan McKay } 1704d82df32SDylan McKay 1714d82df32SDylan McKay void AVRAsmPrinter::EmitInstruction(const MachineInstr *MI) { 1724d82df32SDylan McKay AVRMCInstLower MCInstLowering(OutContext, *this); 1734d82df32SDylan McKay 1744d82df32SDylan McKay MCInst I; 1754d82df32SDylan McKay MCInstLowering.lowerInstruction(*MI, I); 1764d82df32SDylan McKay EmitToStreamer(*OutStreamer, I); 1774d82df32SDylan McKay } 1784d82df32SDylan McKay 1794d82df32SDylan McKay } // end of namespace llvm 1804d82df32SDylan McKay 1814d82df32SDylan McKay extern "C" void LLVMInitializeAVRAsmPrinter() { 182f42454b9SMehdi Amini llvm::RegisterAsmPrinter<llvm::AVRAsmPrinter> X(llvm::getTheAVRTarget()); 1834d82df32SDylan McKay } 1844d82df32SDylan McKay 185