14d82df32SDylan McKay //===-- AVRAsmPrinter.cpp - AVR LLVM assembly writer ----------------------===// 24d82df32SDylan McKay // 34d82df32SDylan McKay // The LLVM Compiler Infrastructure 44d82df32SDylan McKay // 54d82df32SDylan McKay // This file is distributed under the University of Illinois Open Source 64d82df32SDylan McKay // License. See LICENSE.TXT for details. 74d82df32SDylan McKay // 84d82df32SDylan McKay //===----------------------------------------------------------------------===// 94d82df32SDylan McKay // 104d82df32SDylan McKay // This file contains a printer that converts from our internal representation 114d82df32SDylan McKay // of machine-dependent LLVM code to GAS-format AVR assembly language. 124d82df32SDylan McKay // 134d82df32SDylan McKay //===----------------------------------------------------------------------===// 144d82df32SDylan McKay 154d82df32SDylan McKay #include "AVR.h" 164d82df32SDylan McKay #include "AVRMCInstLower.h" 174d82df32SDylan McKay #include "AVRSubtarget.h" 184d82df32SDylan McKay #include "InstPrinter/AVRInstPrinter.h" 194d82df32SDylan McKay 204d82df32SDylan McKay #include "llvm/CodeGen/AsmPrinter.h" 214d82df32SDylan McKay #include "llvm/CodeGen/MachineFunction.h" 226bda14b3SChandler Carruth #include "llvm/CodeGen/MachineInstr.h" 234d82df32SDylan McKay #include "llvm/IR/Mangler.h" 244d82df32SDylan McKay #include "llvm/MC/MCInst.h" 254d82df32SDylan McKay #include "llvm/MC/MCStreamer.h" 264d82df32SDylan McKay #include "llvm/MC/MCSymbol.h" 274d82df32SDylan McKay #include "llvm/Support/ErrorHandling.h" 284d82df32SDylan McKay #include "llvm/Support/TargetRegistry.h" 294d82df32SDylan McKay #include "llvm/Support/raw_ostream.h" 304d82df32SDylan McKay #include "llvm/Target/TargetRegisterInfo.h" 314d82df32SDylan McKay #include "llvm/Target/TargetSubtargetInfo.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 464d82df32SDylan McKay void printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O, 474d82df32SDylan McKay const char *Modifier = 0); 484d82df32SDylan McKay 494d82df32SDylan McKay bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, 504d82df32SDylan McKay unsigned AsmVariant, const char *ExtraCode, 514d82df32SDylan McKay raw_ostream &O) override; 524d82df32SDylan McKay 534d82df32SDylan McKay bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, 544d82df32SDylan McKay unsigned AsmVariant, const char *ExtraCode, 554d82df32SDylan McKay raw_ostream &O) override; 564d82df32SDylan McKay 574d82df32SDylan McKay void EmitInstruction(const MachineInstr *MI) override; 584d82df32SDylan McKay 594d82df32SDylan McKay private: 604d82df32SDylan McKay const MCRegisterInfo &MRI; 614d82df32SDylan McKay }; 624d82df32SDylan McKay 634d82df32SDylan McKay void AVRAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo, 644d82df32SDylan McKay raw_ostream &O, const char *Modifier) { 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, 894d82df32SDylan McKay unsigned AsmVariant, const char *ExtraCode, 904d82df32SDylan McKay raw_ostream &O) { 914d82df32SDylan McKay // Default asm printer can only deal with some extra codes, 924d82df32SDylan McKay // so try it first. 934d82df32SDylan McKay bool Error = AsmPrinter::PrintAsmOperand(MI, OpNum, AsmVariant, ExtraCode, O); 944d82df32SDylan McKay 954d82df32SDylan McKay if (Error && ExtraCode && ExtraCode[0]) { 964d82df32SDylan McKay if (ExtraCode[1] != 0) 974d82df32SDylan McKay return true; // Unknown modifier. 984d82df32SDylan McKay 994d82df32SDylan McKay if (ExtraCode[0] >= 'A' && ExtraCode[0] <= 'Z') { 1004d82df32SDylan McKay const MachineOperand &RegOp = MI->getOperand(OpNum); 1014d82df32SDylan McKay 1024d82df32SDylan McKay assert(RegOp.isReg() && "Operand must be a register when you're" 1034d82df32SDylan McKay "using 'A'..'Z' operand extracodes."); 1044d82df32SDylan McKay unsigned Reg = RegOp.getReg(); 1054d82df32SDylan McKay 1064d82df32SDylan McKay unsigned ByteNumber = ExtraCode[0] - 'A'; 1074d82df32SDylan McKay 1084d82df32SDylan McKay unsigned OpFlags = MI->getOperand(OpNum - 1).getImm(); 1094d82df32SDylan McKay unsigned NumOpRegs = InlineAsm::getNumOperandRegisters(OpFlags); 1101a55f201SDylan McKay (void)NumOpRegs; 1114d82df32SDylan McKay 1124d82df32SDylan McKay const AVRSubtarget &STI = MF->getSubtarget<AVRSubtarget>(); 1134d82df32SDylan McKay const TargetRegisterInfo &TRI = *STI.getRegisterInfo(); 1144d82df32SDylan McKay 11544e25f37SKrzysztof Parzyszek const TargetRegisterClass *RC = TRI.getMinimalPhysRegClass(Reg); 11644e25f37SKrzysztof Parzyszek unsigned BytesPerReg = TRI.getRegSizeInBits(*RC) / 8; 1174d82df32SDylan McKay assert(BytesPerReg <= 2 && "Only 8 and 16 bit regs are supported."); 1184d82df32SDylan McKay 1194d82df32SDylan McKay unsigned RegIdx = ByteNumber / BytesPerReg; 1204d82df32SDylan McKay assert(RegIdx < NumOpRegs && "Multibyte index out of range."); 1214d82df32SDylan McKay 1224d82df32SDylan McKay Reg = MI->getOperand(OpNum + RegIdx).getReg(); 1234d82df32SDylan McKay 1244d82df32SDylan McKay if (BytesPerReg == 2) { 1254d82df32SDylan McKay Reg = TRI.getSubReg(Reg, ByteNumber % BytesPerReg ? AVR::sub_hi 1264d82df32SDylan McKay : AVR::sub_lo); 1274d82df32SDylan McKay } 1284d82df32SDylan McKay 1294d82df32SDylan McKay O << AVRInstPrinter::getPrettyRegisterName(Reg, MRI); 1304d82df32SDylan McKay return false; 1314d82df32SDylan McKay } 1324d82df32SDylan McKay } 1334d82df32SDylan McKay 134b78f3665SDylan McKay if (Error) 1354d82df32SDylan McKay printOperand(MI, OpNum, O); 1364d82df32SDylan McKay 1374d82df32SDylan McKay return false; 1384d82df32SDylan McKay } 1394d82df32SDylan McKay 1404d82df32SDylan McKay bool AVRAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, 1414d82df32SDylan McKay unsigned OpNum, unsigned AsmVariant, 1424d82df32SDylan McKay const char *ExtraCode, 1434d82df32SDylan McKay raw_ostream &O) { 1444d82df32SDylan McKay if (ExtraCode && ExtraCode[0]) { 1454d82df32SDylan McKay llvm_unreachable("This branch is not implemented yet"); 1464d82df32SDylan McKay } 1474d82df32SDylan McKay 1484d82df32SDylan McKay const MachineOperand &MO = MI->getOperand(OpNum); 1491a55f201SDylan McKay (void)MO; 1504d82df32SDylan McKay assert(MO.isReg() && "Unexpected inline asm memory operand"); 1514d82df32SDylan McKay 152*946ab551SDylan McKay // TODO: We should be able to look up the alternative name for 153*946ab551SDylan McKay // the register if it's given. 154*946ab551SDylan McKay // TableGen doesn't expose a way of getting retrieving names 155*946ab551SDylan McKay // for registers. 1564d82df32SDylan McKay if (MI->getOperand(OpNum).getReg() == AVR::R31R30) { 1574d82df32SDylan McKay O << "Z"; 1584d82df32SDylan McKay } else { 1594d82df32SDylan McKay assert(MI->getOperand(OpNum).getReg() == AVR::R29R28 && 1604d82df32SDylan McKay "Wrong register class for memory operand."); 1614d82df32SDylan McKay O << "Y"; 1624d82df32SDylan McKay } 1634d82df32SDylan McKay 1644d82df32SDylan McKay // If NumOpRegs == 2, then we assume it is product of a FrameIndex expansion 1654d82df32SDylan McKay // and the second operand is an Imm. 1664d82df32SDylan McKay unsigned OpFlags = MI->getOperand(OpNum - 1).getImm(); 1674d82df32SDylan McKay unsigned NumOpRegs = InlineAsm::getNumOperandRegisters(OpFlags); 1684d82df32SDylan McKay 1694d82df32SDylan McKay if (NumOpRegs == 2) { 1704d82df32SDylan McKay O << '+' << MI->getOperand(OpNum + 1).getImm(); 1714d82df32SDylan McKay } 1724d82df32SDylan McKay 1734d82df32SDylan McKay return false; 1744d82df32SDylan McKay } 1754d82df32SDylan McKay 1764d82df32SDylan McKay void AVRAsmPrinter::EmitInstruction(const MachineInstr *MI) { 1774d82df32SDylan McKay AVRMCInstLower MCInstLowering(OutContext, *this); 1784d82df32SDylan McKay 1794d82df32SDylan McKay MCInst I; 1804d82df32SDylan McKay MCInstLowering.lowerInstruction(*MI, I); 1814d82df32SDylan McKay EmitToStreamer(*OutStreamer, I); 1824d82df32SDylan McKay } 1834d82df32SDylan McKay 1844d82df32SDylan McKay } // end of namespace llvm 1854d82df32SDylan McKay 1864d82df32SDylan McKay extern "C" void LLVMInitializeAVRAsmPrinter() { 187f42454b9SMehdi Amini llvm::RegisterAsmPrinter<llvm::AVRAsmPrinter> X(llvm::getTheAVRTarget()); 1884d82df32SDylan McKay } 1894d82df32SDylan McKay 190