14d82df32SDylan McKay //===-- AVRAsmPrinter.cpp - AVR LLVM assembly writer ----------------------===// 24d82df32SDylan McKay // 3*2946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*2946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information. 5*2946cd70SChandler 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" 174d82df32SDylan McKay #include "InstPrinter/AVRInstPrinter.h" 184d82df32SDylan McKay 194d82df32SDylan McKay #include "llvm/CodeGen/AsmPrinter.h" 204d82df32SDylan McKay #include "llvm/CodeGen/MachineFunction.h" 216bda14b3SChandler Carruth #include "llvm/CodeGen/MachineInstr.h" 22b3bde2eaSDavid Blaikie #include "llvm/CodeGen/TargetRegisterInfo.h" 23b3bde2eaSDavid Blaikie #include "llvm/CodeGen/TargetSubtargetInfo.h" 244d82df32SDylan McKay #include "llvm/IR/Mangler.h" 254d82df32SDylan McKay #include "llvm/MC/MCInst.h" 264d82df32SDylan McKay #include "llvm/MC/MCStreamer.h" 274d82df32SDylan McKay #include "llvm/MC/MCSymbol.h" 284d82df32SDylan McKay #include "llvm/Support/ErrorHandling.h" 294d82df32SDylan McKay #include "llvm/Support/TargetRegistry.h" 304d82df32SDylan McKay #include "llvm/Support/raw_ostream.h" 314d82df32SDylan McKay 324d82df32SDylan McKay #define DEBUG_TYPE "avr-asm-printer" 334d82df32SDylan McKay 344d82df32SDylan McKay namespace llvm { 354d82df32SDylan McKay 364d82df32SDylan McKay /// An AVR assembly code printer. 374d82df32SDylan McKay class AVRAsmPrinter : public AsmPrinter { 384d82df32SDylan McKay public: 394d82df32SDylan McKay AVRAsmPrinter(TargetMachine &TM, 404d82df32SDylan McKay std::unique_ptr<MCStreamer> Streamer) 414d82df32SDylan McKay : AsmPrinter(TM, std::move(Streamer)), MRI(*TM.getMCRegisterInfo()) { } 424d82df32SDylan McKay 434d82df32SDylan McKay StringRef getPassName() const override { return "AVR Assembly Printer"; } 444d82df32SDylan McKay 454d82df32SDylan McKay void printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O, 464d82df32SDylan McKay const char *Modifier = 0); 474d82df32SDylan McKay 484d82df32SDylan McKay bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, 494d82df32SDylan McKay unsigned AsmVariant, const char *ExtraCode, 504d82df32SDylan McKay raw_ostream &O) override; 514d82df32SDylan McKay 524d82df32SDylan McKay bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, 534d82df32SDylan McKay unsigned AsmVariant, const char *ExtraCode, 544d82df32SDylan McKay raw_ostream &O) override; 554d82df32SDylan McKay 564d82df32SDylan McKay void EmitInstruction(const MachineInstr *MI) override; 574d82df32SDylan McKay 584d82df32SDylan McKay private: 594d82df32SDylan McKay const MCRegisterInfo &MRI; 604d82df32SDylan McKay }; 614d82df32SDylan McKay 624d82df32SDylan McKay void AVRAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo, 634d82df32SDylan McKay raw_ostream &O, const char *Modifier) { 644d82df32SDylan McKay const MachineOperand &MO = MI->getOperand(OpNo); 654d82df32SDylan McKay 664d82df32SDylan McKay switch (MO.getType()) { 674d82df32SDylan McKay case MachineOperand::MO_Register: 684d82df32SDylan McKay O << AVRInstPrinter::getPrettyRegisterName(MO.getReg(), MRI); 694d82df32SDylan McKay break; 704d82df32SDylan McKay case MachineOperand::MO_Immediate: 714d82df32SDylan McKay O << MO.getImm(); 724d82df32SDylan McKay break; 734d82df32SDylan McKay case MachineOperand::MO_GlobalAddress: 744d82df32SDylan McKay O << getSymbol(MO.getGlobal()); 754d82df32SDylan McKay break; 764d82df32SDylan McKay case MachineOperand::MO_ExternalSymbol: 774d82df32SDylan McKay O << *GetExternalSymbolSymbol(MO.getSymbolName()); 784d82df32SDylan McKay break; 794d82df32SDylan McKay case MachineOperand::MO_MachineBasicBlock: 804d82df32SDylan McKay O << *MO.getMBB()->getSymbol(); 814d82df32SDylan McKay break; 824d82df32SDylan McKay default: 834d82df32SDylan McKay llvm_unreachable("Not implemented yet!"); 844d82df32SDylan McKay } 854d82df32SDylan McKay } 864d82df32SDylan McKay 874d82df32SDylan McKay bool AVRAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, 884d82df32SDylan McKay unsigned AsmVariant, const char *ExtraCode, 894d82df32SDylan McKay raw_ostream &O) { 904d82df32SDylan McKay // Default asm printer can only deal with some extra codes, 914d82df32SDylan McKay // so try it first. 924d82df32SDylan McKay bool Error = AsmPrinter::PrintAsmOperand(MI, OpNum, AsmVariant, 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."); 1034d82df32SDylan McKay unsigned 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, 1404d82df32SDylan McKay unsigned OpNum, unsigned AsmVariant, 1414d82df32SDylan McKay const char *ExtraCode, 1424d82df32SDylan McKay raw_ostream &O) { 1434d82df32SDylan McKay if (ExtraCode && ExtraCode[0]) { 1444d82df32SDylan McKay llvm_unreachable("This branch is not implemented yet"); 1454d82df32SDylan McKay } 1464d82df32SDylan McKay 1474d82df32SDylan McKay const MachineOperand &MO = MI->getOperand(OpNum); 1481a55f201SDylan McKay (void)MO; 1494d82df32SDylan McKay assert(MO.isReg() && "Unexpected inline asm memory operand"); 1504d82df32SDylan McKay 151946ab551SDylan McKay // TODO: We should be able to look up the alternative name for 152946ab551SDylan McKay // the register if it's given. 153946ab551SDylan McKay // TableGen doesn't expose a way of getting retrieving names 154946ab551SDylan McKay // for registers. 1554d82df32SDylan McKay if (MI->getOperand(OpNum).getReg() == AVR::R31R30) { 1564d82df32SDylan McKay O << "Z"; 1574d82df32SDylan McKay } else { 1584d82df32SDylan McKay assert(MI->getOperand(OpNum).getReg() == AVR::R29R28 && 1594d82df32SDylan McKay "Wrong register class for memory operand."); 1604d82df32SDylan McKay O << "Y"; 1614d82df32SDylan McKay } 1624d82df32SDylan McKay 1634d82df32SDylan McKay // If NumOpRegs == 2, then we assume it is product of a FrameIndex expansion 1644d82df32SDylan McKay // and the second operand is an Imm. 1654d82df32SDylan McKay unsigned OpFlags = MI->getOperand(OpNum - 1).getImm(); 1664d82df32SDylan McKay unsigned NumOpRegs = InlineAsm::getNumOperandRegisters(OpFlags); 1674d82df32SDylan McKay 1684d82df32SDylan McKay if (NumOpRegs == 2) { 1694d82df32SDylan McKay O << '+' << MI->getOperand(OpNum + 1).getImm(); 1704d82df32SDylan McKay } 1714d82df32SDylan McKay 1724d82df32SDylan McKay return false; 1734d82df32SDylan McKay } 1744d82df32SDylan McKay 1754d82df32SDylan McKay void AVRAsmPrinter::EmitInstruction(const MachineInstr *MI) { 1764d82df32SDylan McKay AVRMCInstLower MCInstLowering(OutContext, *this); 1774d82df32SDylan McKay 1784d82df32SDylan McKay MCInst I; 1794d82df32SDylan McKay MCInstLowering.lowerInstruction(*MI, I); 1804d82df32SDylan McKay EmitToStreamer(*OutStreamer, I); 1814d82df32SDylan McKay } 1824d82df32SDylan McKay 1834d82df32SDylan McKay } // end of namespace llvm 1844d82df32SDylan McKay 1854d82df32SDylan McKay extern "C" void LLVMInitializeAVRAsmPrinter() { 186f42454b9SMehdi Amini llvm::RegisterAsmPrinter<llvm::AVRAsmPrinter> X(llvm::getTheAVRTarget()); 1874d82df32SDylan McKay } 1884d82df32SDylan McKay 189