diff options
Diffstat (limited to 'contrib/llvm-project/llvm/lib/Target/AVR/AVRAsmPrinter.cpp')
| -rw-r--r-- | contrib/llvm-project/llvm/lib/Target/AVR/AVRAsmPrinter.cpp | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/contrib/llvm-project/llvm/lib/Target/AVR/AVRAsmPrinter.cpp b/contrib/llvm-project/llvm/lib/Target/AVR/AVRAsmPrinter.cpp new file mode 100644 index 000000000000..7586bd7b78fc --- /dev/null +++ b/contrib/llvm-project/llvm/lib/Target/AVR/AVRAsmPrinter.cpp @@ -0,0 +1,184 @@ +//===-- AVRAsmPrinter.cpp - AVR LLVM assembly writer ----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file contains a printer that converts from our internal representation +// of machine-dependent LLVM code to GAS-format AVR assembly language. +// +//===----------------------------------------------------------------------===// + +#include "AVR.h" +#include "AVRMCInstLower.h" +#include "AVRSubtarget.h" +#include "MCTargetDesc/AVRInstPrinter.h" +#include "TargetInfo/AVRTargetInfo.h" + +#include "llvm/CodeGen/AsmPrinter.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/TargetRegisterInfo.h" +#include "llvm/CodeGen/TargetSubtargetInfo.h" +#include "llvm/IR/Mangler.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCStreamer.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" + +#define DEBUG_TYPE "avr-asm-printer" + +namespace llvm { + +/// An AVR assembly code printer. +class AVRAsmPrinter : public AsmPrinter { +public: + AVRAsmPrinter(TargetMachine &TM, + std::unique_ptr<MCStreamer> Streamer) + : AsmPrinter(TM, std::move(Streamer)), MRI(*TM.getMCRegisterInfo()) { } + + StringRef getPassName() const override { return "AVR Assembly Printer"; } + + void printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O); + + bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, + const char *ExtraCode, raw_ostream &O) override; + + bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNum, + const char *ExtraCode, raw_ostream &O) override; + + void EmitInstruction(const MachineInstr *MI) override; + +private: + const MCRegisterInfo &MRI; +}; + +void AVRAsmPrinter::printOperand(const MachineInstr *MI, unsigned OpNo, + raw_ostream &O) { + const MachineOperand &MO = MI->getOperand(OpNo); + + switch (MO.getType()) { + case MachineOperand::MO_Register: + O << AVRInstPrinter::getPrettyRegisterName(MO.getReg(), MRI); + break; + case MachineOperand::MO_Immediate: + O << MO.getImm(); + break; + case MachineOperand::MO_GlobalAddress: + O << getSymbol(MO.getGlobal()); + break; + case MachineOperand::MO_ExternalSymbol: + O << *GetExternalSymbolSymbol(MO.getSymbolName()); + break; + case MachineOperand::MO_MachineBasicBlock: + O << *MO.getMBB()->getSymbol(); + break; + default: + llvm_unreachable("Not implemented yet!"); + } +} + +bool AVRAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNum, + const char *ExtraCode, raw_ostream &O) { + // Default asm printer can only deal with some extra codes, + // so try it first. + bool Error = AsmPrinter::PrintAsmOperand(MI, OpNum, ExtraCode, O); + + if (Error && ExtraCode && ExtraCode[0]) { + if (ExtraCode[1] != 0) + return true; // Unknown modifier. + + if (ExtraCode[0] >= 'A' && ExtraCode[0] <= 'Z') { + const MachineOperand &RegOp = MI->getOperand(OpNum); + + assert(RegOp.isReg() && "Operand must be a register when you're" + "using 'A'..'Z' operand extracodes."); + unsigned Reg = RegOp.getReg(); + + unsigned ByteNumber = ExtraCode[0] - 'A'; + + unsigned OpFlags = MI->getOperand(OpNum - 1).getImm(); + unsigned NumOpRegs = InlineAsm::getNumOperandRegisters(OpFlags); + (void)NumOpRegs; + + const AVRSubtarget &STI = MF->getSubtarget<AVRSubtarget>(); + const TargetRegisterInfo &TRI = *STI.getRegisterInfo(); + + const TargetRegisterClass *RC = TRI.getMinimalPhysRegClass(Reg); + unsigned BytesPerReg = TRI.getRegSizeInBits(*RC) / 8; + assert(BytesPerReg <= 2 && "Only 8 and 16 bit regs are supported."); + + unsigned RegIdx = ByteNumber / BytesPerReg; + assert(RegIdx < NumOpRegs && "Multibyte index out of range."); + + Reg = MI->getOperand(OpNum + RegIdx).getReg(); + + if (BytesPerReg == 2) { + Reg = TRI.getSubReg(Reg, ByteNumber % BytesPerReg ? AVR::sub_hi + : AVR::sub_lo); + } + + O << AVRInstPrinter::getPrettyRegisterName(Reg, MRI); + return false; + } + } + + if (Error) + printOperand(MI, OpNum, O); + + return false; +} + +bool AVRAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI, + unsigned OpNum, const char *ExtraCode, + raw_ostream &O) { + if (ExtraCode && ExtraCode[0]) { + llvm_unreachable("This branch is not implemented yet"); + } + + const MachineOperand &MO = MI->getOperand(OpNum); + (void)MO; + assert(MO.isReg() && "Unexpected inline asm memory operand"); + + // TODO: We should be able to look up the alternative name for + // the register if it's given. + // TableGen doesn't expose a way of getting retrieving names + // for registers. + if (MI->getOperand(OpNum).getReg() == AVR::R31R30) { + O << "Z"; + } else { + assert(MI->getOperand(OpNum).getReg() == AVR::R29R28 && + "Wrong register class for memory operand."); + O << "Y"; + } + + // If NumOpRegs == 2, then we assume it is product of a FrameIndex expansion + // and the second operand is an Imm. + unsigned OpFlags = MI->getOperand(OpNum - 1).getImm(); + unsigned NumOpRegs = InlineAsm::getNumOperandRegisters(OpFlags); + + if (NumOpRegs == 2) { + O << '+' << MI->getOperand(OpNum + 1).getImm(); + } + + return false; +} + +void AVRAsmPrinter::EmitInstruction(const MachineInstr *MI) { + AVRMCInstLower MCInstLowering(OutContext, *this); + + MCInst I; + MCInstLowering.lowerInstruction(*MI, I); + EmitToStreamer(*OutStreamer, I); +} + +} // end of namespace llvm + +extern "C" void LLVMInitializeAVRAsmPrinter() { + llvm::RegisterAsmPrinter<llvm::AVRAsmPrinter> X(llvm::getTheAVRTarget()); +} + |
