109467b48Spatrick //===-- AVRAsmPrinter.cpp - AVR LLVM assembly writer ----------------------===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick //
909467b48Spatrick // This file contains a printer that converts from our internal representation
1009467b48Spatrick // of machine-dependent LLVM code to GAS-format AVR assembly language.
1109467b48Spatrick //
1209467b48Spatrick //===----------------------------------------------------------------------===//
1309467b48Spatrick 
1409467b48Spatrick #include "AVR.h"
1509467b48Spatrick #include "AVRMCInstLower.h"
1609467b48Spatrick #include "AVRSubtarget.h"
1709467b48Spatrick #include "MCTargetDesc/AVRInstPrinter.h"
18*73471bf0Spatrick #include "MCTargetDesc/AVRMCExpr.h"
1909467b48Spatrick #include "TargetInfo/AVRTargetInfo.h"
2009467b48Spatrick 
2109467b48Spatrick #include "llvm/CodeGen/AsmPrinter.h"
2209467b48Spatrick #include "llvm/CodeGen/MachineFunction.h"
2309467b48Spatrick #include "llvm/CodeGen/MachineInstr.h"
2409467b48Spatrick #include "llvm/CodeGen/TargetRegisterInfo.h"
2509467b48Spatrick #include "llvm/CodeGen/TargetSubtargetInfo.h"
2609467b48Spatrick #include "llvm/IR/Mangler.h"
2709467b48Spatrick #include "llvm/MC/MCInst.h"
2809467b48Spatrick #include "llvm/MC/MCStreamer.h"
2909467b48Spatrick #include "llvm/MC/MCSymbol.h"
3009467b48Spatrick #include "llvm/Support/ErrorHandling.h"
3109467b48Spatrick #include "llvm/Support/TargetRegistry.h"
3209467b48Spatrick #include "llvm/Support/raw_ostream.h"
3309467b48Spatrick 
3409467b48Spatrick #define DEBUG_TYPE "avr-asm-printer"
3509467b48Spatrick 
3609467b48Spatrick namespace llvm {
3709467b48Spatrick 
3809467b48Spatrick /// An AVR assembly code printer.
3909467b48Spatrick class AVRAsmPrinter : public AsmPrinter {
4009467b48Spatrick public:
4109467b48Spatrick   AVRAsmPrinter(TargetMachine &TM,
4209467b48Spatrick                 std::unique_ptr<MCStreamer> Streamer)
4309467b48Spatrick       : AsmPrinter(TM, std::move(Streamer)), MRI(*TM.getMCRegisterInfo()) { }
4409467b48Spatrick 
4509467b48Spatrick   StringRef getPassName() const override { return "AVR Assembly Printer"; }
4609467b48Spatrick 
4709467b48Spatrick   void printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O);
4809467b48Spatrick 
4909467b48Spatrick   bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
5009467b48Spatrick                        const char *ExtraCode, raw_ostream &O) override;
5109467b48Spatrick 
5209467b48Spatrick   bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum,
5309467b48Spatrick                              const char *ExtraCode, raw_ostream &O) override;
5409467b48Spatrick 
55097a140dSpatrick   void emitInstruction(const MachineInstr *MI) override;
5609467b48Spatrick 
57*73471bf0Spatrick   const MCExpr *lowerConstant(const Constant *CV) override;
58*73471bf0Spatrick 
5909467b48Spatrick private:
6009467b48Spatrick   const MCRegisterInfo &MRI;
6109467b48Spatrick };
6209467b48Spatrick 
6309467b48Spatrick void AVRAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo,
6409467b48Spatrick                                  raw_ostream &O) {
6509467b48Spatrick   const MachineOperand &MO = MI->getOperand(OpNo);
6609467b48Spatrick 
6709467b48Spatrick   switch (MO.getType()) {
6809467b48Spatrick   case MachineOperand::MO_Register:
6909467b48Spatrick     O << AVRInstPrinter::getPrettyRegisterName(MO.getReg(), MRI);
7009467b48Spatrick     break;
7109467b48Spatrick   case MachineOperand::MO_Immediate:
7209467b48Spatrick     O << MO.getImm();
7309467b48Spatrick     break;
7409467b48Spatrick   case MachineOperand::MO_GlobalAddress:
7509467b48Spatrick     O << getSymbol(MO.getGlobal());
7609467b48Spatrick     break;
7709467b48Spatrick   case MachineOperand::MO_ExternalSymbol:
7809467b48Spatrick     O << *GetExternalSymbolSymbol(MO.getSymbolName());
7909467b48Spatrick     break;
8009467b48Spatrick   case MachineOperand::MO_MachineBasicBlock:
8109467b48Spatrick     O << *MO.getMBB()->getSymbol();
8209467b48Spatrick     break;
8309467b48Spatrick   default:
8409467b48Spatrick     llvm_unreachable("Not implemented yet!");
8509467b48Spatrick   }
8609467b48Spatrick }
8709467b48Spatrick 
8809467b48Spatrick bool AVRAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum,
8909467b48Spatrick                                     const char *ExtraCode, raw_ostream &O) {
9009467b48Spatrick   // Default asm printer can only deal with some extra codes,
9109467b48Spatrick   // so try it first.
9209467b48Spatrick   bool Error = AsmPrinter::PrintAsmOperand(MI, OpNum, ExtraCode, O);
9309467b48Spatrick 
9409467b48Spatrick   if (Error && ExtraCode && ExtraCode[0]) {
9509467b48Spatrick     if (ExtraCode[1] != 0)
9609467b48Spatrick       return true; // Unknown modifier.
9709467b48Spatrick 
9809467b48Spatrick     if (ExtraCode[0] >= 'A' && ExtraCode[0] <= 'Z') {
9909467b48Spatrick       const MachineOperand &RegOp = MI->getOperand(OpNum);
10009467b48Spatrick 
10109467b48Spatrick       assert(RegOp.isReg() && "Operand must be a register when you're"
10209467b48Spatrick                               "using 'A'..'Z' operand extracodes.");
10309467b48Spatrick       Register Reg = RegOp.getReg();
10409467b48Spatrick 
10509467b48Spatrick       unsigned ByteNumber = ExtraCode[0] - 'A';
10609467b48Spatrick 
10709467b48Spatrick       unsigned OpFlags = MI->getOperand(OpNum - 1).getImm();
10809467b48Spatrick       unsigned NumOpRegs = InlineAsm::getNumOperandRegisters(OpFlags);
10909467b48Spatrick       (void)NumOpRegs;
11009467b48Spatrick 
11109467b48Spatrick       const AVRSubtarget &STI = MF->getSubtarget<AVRSubtarget>();
11209467b48Spatrick       const TargetRegisterInfo &TRI = *STI.getRegisterInfo();
11309467b48Spatrick 
11409467b48Spatrick       const TargetRegisterClass *RC = TRI.getMinimalPhysRegClass(Reg);
11509467b48Spatrick       unsigned BytesPerReg = TRI.getRegSizeInBits(*RC) / 8;
11609467b48Spatrick       assert(BytesPerReg <= 2 && "Only 8 and 16 bit regs are supported.");
11709467b48Spatrick 
11809467b48Spatrick       unsigned RegIdx = ByteNumber / BytesPerReg;
11909467b48Spatrick       assert(RegIdx < NumOpRegs && "Multibyte index out of range.");
12009467b48Spatrick 
12109467b48Spatrick       Reg = MI->getOperand(OpNum + RegIdx).getReg();
12209467b48Spatrick 
12309467b48Spatrick       if (BytesPerReg == 2) {
12409467b48Spatrick         Reg = TRI.getSubReg(Reg, ByteNumber % BytesPerReg ? AVR::sub_hi
12509467b48Spatrick                                                           : AVR::sub_lo);
12609467b48Spatrick       }
12709467b48Spatrick 
12809467b48Spatrick       O << AVRInstPrinter::getPrettyRegisterName(Reg, MRI);
12909467b48Spatrick       return false;
13009467b48Spatrick     }
13109467b48Spatrick   }
13209467b48Spatrick 
13309467b48Spatrick   if (Error)
13409467b48Spatrick     printOperand(MI, OpNum, O);
13509467b48Spatrick 
13609467b48Spatrick   return false;
13709467b48Spatrick }
13809467b48Spatrick 
13909467b48Spatrick bool AVRAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
14009467b48Spatrick                                           unsigned OpNum, const char *ExtraCode,
14109467b48Spatrick                                           raw_ostream &O) {
14209467b48Spatrick   if (ExtraCode && ExtraCode[0]) {
14309467b48Spatrick     llvm_unreachable("This branch is not implemented yet");
14409467b48Spatrick   }
14509467b48Spatrick 
14609467b48Spatrick   const MachineOperand &MO = MI->getOperand(OpNum);
14709467b48Spatrick   (void)MO;
14809467b48Spatrick   assert(MO.isReg() && "Unexpected inline asm memory operand");
14909467b48Spatrick 
15009467b48Spatrick   // TODO: We should be able to look up the alternative name for
15109467b48Spatrick   // the register if it's given.
15209467b48Spatrick   // TableGen doesn't expose a way of getting retrieving names
15309467b48Spatrick   // for registers.
15409467b48Spatrick   if (MI->getOperand(OpNum).getReg() == AVR::R31R30) {
15509467b48Spatrick     O << "Z";
15609467b48Spatrick   } else {
15709467b48Spatrick     assert(MI->getOperand(OpNum).getReg() == AVR::R29R28 &&
15809467b48Spatrick            "Wrong register class for memory operand.");
15909467b48Spatrick     O << "Y";
16009467b48Spatrick   }
16109467b48Spatrick 
16209467b48Spatrick   // If NumOpRegs == 2, then we assume it is product of a FrameIndex expansion
16309467b48Spatrick   // and the second operand is an Imm.
16409467b48Spatrick   unsigned OpFlags = MI->getOperand(OpNum - 1).getImm();
16509467b48Spatrick   unsigned NumOpRegs = InlineAsm::getNumOperandRegisters(OpFlags);
16609467b48Spatrick 
16709467b48Spatrick   if (NumOpRegs == 2) {
16809467b48Spatrick     O << '+' << MI->getOperand(OpNum + 1).getImm();
16909467b48Spatrick   }
17009467b48Spatrick 
17109467b48Spatrick   return false;
17209467b48Spatrick }
17309467b48Spatrick 
174097a140dSpatrick void AVRAsmPrinter::emitInstruction(const MachineInstr *MI) {
17509467b48Spatrick   AVRMCInstLower MCInstLowering(OutContext, *this);
17609467b48Spatrick 
17709467b48Spatrick   MCInst I;
17809467b48Spatrick   MCInstLowering.lowerInstruction(*MI, I);
17909467b48Spatrick   EmitToStreamer(*OutStreamer, I);
18009467b48Spatrick }
18109467b48Spatrick 
182*73471bf0Spatrick const MCExpr *AVRAsmPrinter::lowerConstant(const Constant *CV) {
183*73471bf0Spatrick   MCContext &Ctx = OutContext;
184*73471bf0Spatrick 
185*73471bf0Spatrick   if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV)) {
186*73471bf0Spatrick     bool IsProgMem = GV->getAddressSpace() == AVR::ProgramMemory;
187*73471bf0Spatrick     if (IsProgMem) {
188*73471bf0Spatrick       const MCExpr *Expr = MCSymbolRefExpr::create(getSymbol(GV), Ctx);
189*73471bf0Spatrick       return AVRMCExpr::create(AVRMCExpr::VK_AVR_PM, Expr, false, Ctx);
190*73471bf0Spatrick     }
191*73471bf0Spatrick   }
192*73471bf0Spatrick 
193*73471bf0Spatrick   return AsmPrinter::lowerConstant(CV);
194*73471bf0Spatrick }
195*73471bf0Spatrick 
19609467b48Spatrick } // end of namespace llvm
19709467b48Spatrick 
19809467b48Spatrick extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeAVRAsmPrinter() {
19909467b48Spatrick   llvm::RegisterAsmPrinter<llvm::AVRAsmPrinter> X(llvm::getTheAVRTarget());
20009467b48Spatrick }
20109467b48Spatrick 
202