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*2ccb9417SDylan McKay #include "MCTargetDesc/AVRMCExpr.h" 19e982b420SRichard Trieu #include "TargetInfo/AVRTargetInfo.h" 204d82df32SDylan McKay 214d82df32SDylan McKay #include "llvm/CodeGen/AsmPrinter.h" 224d82df32SDylan McKay #include "llvm/CodeGen/MachineFunction.h" 236bda14b3SChandler Carruth #include "llvm/CodeGen/MachineInstr.h" 24b3bde2eaSDavid Blaikie #include "llvm/CodeGen/TargetRegisterInfo.h" 25b3bde2eaSDavid Blaikie #include "llvm/CodeGen/TargetSubtargetInfo.h" 264d82df32SDylan McKay #include "llvm/IR/Mangler.h" 274d82df32SDylan McKay #include "llvm/MC/MCInst.h" 284d82df32SDylan McKay #include "llvm/MC/MCStreamer.h" 294d82df32SDylan McKay #include "llvm/MC/MCSymbol.h" 304d82df32SDylan McKay #include "llvm/Support/ErrorHandling.h" 314d82df32SDylan McKay #include "llvm/Support/TargetRegistry.h" 324d82df32SDylan McKay #include "llvm/Support/raw_ostream.h" 334d82df32SDylan McKay 344d82df32SDylan McKay #define DEBUG_TYPE "avr-asm-printer" 354d82df32SDylan McKay 364d82df32SDylan McKay namespace llvm { 374d82df32SDylan McKay 384d82df32SDylan McKay /// An AVR assembly code printer. 394d82df32SDylan McKay class AVRAsmPrinter : public AsmPrinter { 404d82df32SDylan McKay public: 414d82df32SDylan McKay AVRAsmPrinter(TargetMachine &TM, 424d82df32SDylan McKay std::unique_ptr<MCStreamer> Streamer) 434d82df32SDylan McKay : AsmPrinter(TM, std::move(Streamer)), MRI(*TM.getMCRegisterInfo()) { } 444d82df32SDylan McKay 454d82df32SDylan McKay StringRef getPassName() const override { return "AVR Assembly Printer"; } 464d82df32SDylan McKay 477ab164c4SNick Desaulniers void printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O); 484d82df32SDylan McKay 494d82df32SDylan McKay bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, 505277b3ffSNick Desaulniers const char *ExtraCode, raw_ostream &O) override; 514d82df32SDylan McKay 524d82df32SDylan McKay bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, 535277b3ffSNick Desaulniers const char *ExtraCode, raw_ostream &O) override; 544d82df32SDylan McKay 55bcd24b2dSFangrui Song void emitInstruction(const MachineInstr *MI) override; 564d82df32SDylan McKay 57*2ccb9417SDylan McKay const MCExpr *lowerConstant(const Constant *CV) override; 58*2ccb9417SDylan McKay 594d82df32SDylan McKay private: 604d82df32SDylan McKay const MCRegisterInfo &MRI; 614d82df32SDylan McKay }; 624d82df32SDylan McKay 634d82df32SDylan McKay void AVRAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo, 647ab164c4SNick Desaulniers raw_ostream &O) { 654d82df32SDylan McKay const MachineOperand &MO = MI->getOperand(OpNo); 664d82df32SDylan McKay 674d82df32SDylan McKay switch (MO.getType()) { 684d82df32SDylan McKay case MachineOperand::MO_Register: 694d82df32SDylan McKay O << AVRInstPrinter::getPrettyRegisterName(MO.getReg(), MRI); 704d82df32SDylan McKay break; 714d82df32SDylan McKay case MachineOperand::MO_Immediate: 724d82df32SDylan McKay O << MO.getImm(); 734d82df32SDylan McKay break; 744d82df32SDylan McKay case MachineOperand::MO_GlobalAddress: 754d82df32SDylan McKay O << getSymbol(MO.getGlobal()); 764d82df32SDylan McKay break; 774d82df32SDylan McKay case MachineOperand::MO_ExternalSymbol: 784d82df32SDylan McKay O << *GetExternalSymbolSymbol(MO.getSymbolName()); 794d82df32SDylan McKay break; 804d82df32SDylan McKay case MachineOperand::MO_MachineBasicBlock: 814d82df32SDylan McKay O << *MO.getMBB()->getSymbol(); 824d82df32SDylan McKay break; 834d82df32SDylan McKay default: 844d82df32SDylan McKay llvm_unreachable("Not implemented yet!"); 854d82df32SDylan McKay } 864d82df32SDylan McKay } 874d82df32SDylan McKay 884d82df32SDylan McKay bool AVRAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, 895277b3ffSNick Desaulniers const char *ExtraCode, raw_ostream &O) { 904d82df32SDylan McKay // Default asm printer can only deal with some extra codes, 914d82df32SDylan McKay // so try it first. 925277b3ffSNick Desaulniers bool Error = AsmPrinter::PrintAsmOperand(MI, OpNum, ExtraCode, O); 934d82df32SDylan McKay 944d82df32SDylan McKay if (Error && ExtraCode && ExtraCode[0]) { 954d82df32SDylan McKay if (ExtraCode[1] != 0) 964d82df32SDylan McKay return true; // Unknown modifier. 974d82df32SDylan McKay 984d82df32SDylan McKay if (ExtraCode[0] >= 'A' && ExtraCode[0] <= 'Z') { 994d82df32SDylan McKay const MachineOperand &RegOp = MI->getOperand(OpNum); 1004d82df32SDylan McKay 1014d82df32SDylan McKay assert(RegOp.isReg() && "Operand must be a register when you're" 1024d82df32SDylan McKay "using 'A'..'Z' operand extracodes."); 1030c476111SDaniel Sanders Register Reg = RegOp.getReg(); 1044d82df32SDylan McKay 1054d82df32SDylan McKay unsigned ByteNumber = ExtraCode[0] - 'A'; 1064d82df32SDylan McKay 1074d82df32SDylan McKay unsigned OpFlags = MI->getOperand(OpNum - 1).getImm(); 1084d82df32SDylan McKay unsigned NumOpRegs = InlineAsm::getNumOperandRegisters(OpFlags); 1091a55f201SDylan McKay (void)NumOpRegs; 1104d82df32SDylan McKay 1114d82df32SDylan McKay const AVRSubtarget &STI = MF->getSubtarget<AVRSubtarget>(); 1124d82df32SDylan McKay const TargetRegisterInfo &TRI = *STI.getRegisterInfo(); 1134d82df32SDylan McKay 11444e25f37SKrzysztof Parzyszek const TargetRegisterClass *RC = TRI.getMinimalPhysRegClass(Reg); 11544e25f37SKrzysztof Parzyszek unsigned BytesPerReg = TRI.getRegSizeInBits(*RC) / 8; 1164d82df32SDylan McKay assert(BytesPerReg <= 2 && "Only 8 and 16 bit regs are supported."); 1174d82df32SDylan McKay 1184d82df32SDylan McKay unsigned RegIdx = ByteNumber / BytesPerReg; 1194d82df32SDylan McKay assert(RegIdx < NumOpRegs && "Multibyte index out of range."); 1204d82df32SDylan McKay 1214d82df32SDylan McKay Reg = MI->getOperand(OpNum + RegIdx).getReg(); 1224d82df32SDylan McKay 1234d82df32SDylan McKay if (BytesPerReg == 2) { 1244d82df32SDylan McKay Reg = TRI.getSubReg(Reg, ByteNumber % BytesPerReg ? AVR::sub_hi 1254d82df32SDylan McKay : AVR::sub_lo); 1264d82df32SDylan McKay } 1274d82df32SDylan McKay 1284d82df32SDylan McKay O << AVRInstPrinter::getPrettyRegisterName(Reg, MRI); 1294d82df32SDylan McKay return false; 1304d82df32SDylan McKay } 1314d82df32SDylan McKay } 1324d82df32SDylan McKay 133b78f3665SDylan McKay if (Error) 1344d82df32SDylan McKay printOperand(MI, OpNum, O); 1354d82df32SDylan McKay 1364d82df32SDylan McKay return false; 1374d82df32SDylan McKay } 1384d82df32SDylan McKay 1394d82df32SDylan McKay bool AVRAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, 1405277b3ffSNick Desaulniers unsigned OpNum, const char *ExtraCode, 1414d82df32SDylan McKay raw_ostream &O) { 1424d82df32SDylan McKay if (ExtraCode && ExtraCode[0]) { 1434d82df32SDylan McKay llvm_unreachable("This branch is not implemented yet"); 1444d82df32SDylan McKay } 1454d82df32SDylan McKay 1464d82df32SDylan McKay const MachineOperand &MO = MI->getOperand(OpNum); 1471a55f201SDylan McKay (void)MO; 1484d82df32SDylan McKay assert(MO.isReg() && "Unexpected inline asm memory operand"); 1494d82df32SDylan McKay 150946ab551SDylan McKay // TODO: We should be able to look up the alternative name for 151946ab551SDylan McKay // the register if it's given. 152946ab551SDylan McKay // TableGen doesn't expose a way of getting retrieving names 153946ab551SDylan McKay // for registers. 1544d82df32SDylan McKay if (MI->getOperand(OpNum).getReg() == AVR::R31R30) { 1554d82df32SDylan McKay O << "Z"; 1564d82df32SDylan McKay } else { 1574d82df32SDylan McKay assert(MI->getOperand(OpNum).getReg() == AVR::R29R28 && 1584d82df32SDylan McKay "Wrong register class for memory operand."); 1594d82df32SDylan McKay O << "Y"; 1604d82df32SDylan McKay } 1614d82df32SDylan McKay 1624d82df32SDylan McKay // If NumOpRegs == 2, then we assume it is product of a FrameIndex expansion 1634d82df32SDylan McKay // and the second operand is an Imm. 1644d82df32SDylan McKay unsigned OpFlags = MI->getOperand(OpNum - 1).getImm(); 1654d82df32SDylan McKay unsigned NumOpRegs = InlineAsm::getNumOperandRegisters(OpFlags); 1664d82df32SDylan McKay 1674d82df32SDylan McKay if (NumOpRegs == 2) { 1684d82df32SDylan McKay O << '+' << MI->getOperand(OpNum + 1).getImm(); 1694d82df32SDylan McKay } 1704d82df32SDylan McKay 1714d82df32SDylan McKay return false; 1724d82df32SDylan McKay } 1734d82df32SDylan McKay 174bcd24b2dSFangrui Song void AVRAsmPrinter::emitInstruction(const MachineInstr *MI) { 1754d82df32SDylan McKay AVRMCInstLower MCInstLowering(OutContext, *this); 1764d82df32SDylan McKay 1774d82df32SDylan McKay MCInst I; 1784d82df32SDylan McKay MCInstLowering.lowerInstruction(*MI, I); 1794d82df32SDylan McKay EmitToStreamer(*OutStreamer, I); 1804d82df32SDylan McKay } 1814d82df32SDylan McKay 182*2ccb9417SDylan McKay const MCExpr *AVRAsmPrinter::lowerConstant(const Constant *CV) { 183*2ccb9417SDylan McKay MCContext &Ctx = OutContext; 184*2ccb9417SDylan McKay 185*2ccb9417SDylan McKay if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV)) { 186*2ccb9417SDylan McKay bool IsProgMem = GV->getAddressSpace() == AVR::ProgramMemory; 187*2ccb9417SDylan McKay if (IsProgMem) { 188*2ccb9417SDylan McKay const MCExpr *Expr = MCSymbolRefExpr::create(getSymbol(GV), Ctx); 189*2ccb9417SDylan McKay return AVRMCExpr::create(AVRMCExpr::VK_AVR_PM, Expr, false, Ctx); 190*2ccb9417SDylan McKay } 191*2ccb9417SDylan McKay } 192*2ccb9417SDylan McKay 193*2ccb9417SDylan McKay return AsmPrinter::lowerConstant(CV); 194*2ccb9417SDylan McKay } 195*2ccb9417SDylan McKay 1964d82df32SDylan McKay } // end of namespace llvm 1974d82df32SDylan McKay 1980dbcb363STom Stellard extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAVRAsmPrinter() { 199f42454b9SMehdi Amini llvm::RegisterAsmPrinter<llvm::AVRAsmPrinter> X(llvm::getTheAVRTarget()); 2004d82df32SDylan McKay } 2014d82df32SDylan McKay 202