Index: lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.h =================================================================== --- /dev/null +++ lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.h @@ -0,0 +1,115 @@ +//===-- AVRMCCodeEmitter.h - Convert AVR Code to Machine Code -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines the AVRMCCodeEmitter class. +// +//===----------------------------------------------------------------------===// +// + +#ifndef LLVM_AVR_CODE_EMITTER_H +#define LLVM_AVR_CODE_EMITTER_H + +#include "AVRFixupKinds.h" + +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/Support/DataTypes.h" + +#define GET_INSTRINFO_OPERAND_TYPES_ENUM +#include "AVRGenInstrInfo.inc" + +namespace llvm { + +class MCContext; +class MCExpr; +class MCFixup; +class MCInst; +class MCInstrInfo; +class MCOperand; +class MCSubtargetInfo; +class raw_ostream; + +/// Writes AVR machine code to a stream. +class AVRMCCodeEmitter : public MCCodeEmitter { +public: + AVRMCCodeEmitter(const MCInstrInfo &MCII, MCContext &Ctx) + : MCII(MCII), Ctx(Ctx) {} + +private: + /// Finishes up encoding an LD/ST instruction. + /// The purpose of this function is to set an bit in the instruction + /// which follows no logical pattern. See the implementation for details. + unsigned loadStorePostEncoder(const MCInst &MI, unsigned EncodedValue, + const MCSubtargetInfo &STI) const; + + /// Gets the encoding for a conditional branch target. + template + unsigned encodeRelCondBrTarget(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + /// Encodes the `PTRREGS` operand to a load or store instruction. + unsigned encodeLDSTPtrReg(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + /// Encodes a `register+immediate` operand for `LDD`/`STD`. + unsigned encodeMemri(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + /// Takes the compliment of a number (~0 - val). + unsigned encodeComplement(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + /// Encodes an immediate value with a given fixup. + template + unsigned encodeImm(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + /// Gets the encoding of the target for the `CALL k` instruction. + unsigned encodeCallTarget(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + /// TableGen'ed function to get the binary encoding for an instruction. + uint64_t getBinaryCodeForInstr(const MCInst &MI, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + unsigned getExprOpValue(const MCExpr *Expr, SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + /// Returns the binary encoding of operand. + /// + /// If the machine operand requires relocation, the relocation is recorded + /// and zero is returned. + unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + void emitInstruction(uint64_t Val, unsigned Size, const MCSubtargetInfo &STI, + raw_ostream &OS) const; + + void encodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const override; + + AVRMCCodeEmitter(const AVRMCCodeEmitter &) = delete; + void operator=(const AVRMCCodeEmitter &) = delete; + + const MCInstrInfo &MCII; + MCContext &Ctx; +}; + +} // end namespace of llvm. + +#endif // LLVM_AVR_CODE_EMITTER_H + Index: lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.cpp =================================================================== --- /dev/null +++ lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.cpp @@ -0,0 +1,305 @@ +//===-- AVRMCCodeEmitter.cpp - Convert AVR Code to Machine Code -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements the AVRMCCodeEmitter class. +// +//===----------------------------------------------------------------------===// + +#include "AVRMCCodeEmitter.h" + +#include "MCTargetDesc/AVRMCExpr.h" +#include "MCTargetDesc/AVRMCTargetDesc.h" + +#include "llvm/ADT/APFloat.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCFixup.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/raw_ostream.h" + +#define DEBUG_TYPE "mccodeemitter" + +#define GET_INSTRMAP_INFO +#include "AVRGenInstrInfo.inc" +#undef GET_INSTRMAP_INFO + +namespace llvm { + +/// Performs a post-encoding step on a `LD` or `ST` instruction. +/// +/// The encoding of the LD/ST family of instructions is inconsistent w.r.t +/// the pointer register and the addressing mode. +/// +/// The permutations of the format are as followed: +/// ld Rd, X `1001 000d dddd 1100` +/// ld Rd, X+ `1001 000d dddd 1101` +/// ld Rd, -X `1001 000d dddd 1110` +/// +/// ld Rd, Y `1000 000d dddd 1000` +/// ld Rd, Y+ `1001 000d dddd 1001` +/// ld Rd, -Y `1001 000d dddd 1010` +/// +/// ld Rd, Z `1000 000d dddd 0000` +/// ld Rd, Z+ `1001 000d dddd 0001` +/// ld Rd, -Z `1001 000d dddd 0010` +/// ^ +/// | +/// Note this one inconsistent bit - it is 1 sometimes and 0 at other times. +/// There is no logical pattern. Looking at a truth table, the following +/// formula can be derived to fit the pattern: +// +/// ``` +/// inconsistent_bit = is_predec OR is_postinc OR is_reg_x +/// ``` +// +/// We manually set this bit in this post encoder method. +unsigned +AVRMCCodeEmitter::loadStorePostEncoder(const MCInst &MI, unsigned EncodedValue, + const MCSubtargetInfo &STI) const { + + assert(MI.getOperand(0).isReg() && MI.getOperand(1).isReg() && + "the load/store operands must be registers"); + + unsigned Opcode = MI.getOpcode(); + + // check whether either of the registers are the X pointer register. + bool IsRegX = MI.getOperand(0).getReg() == AVR::R27R26 || + MI.getOperand(1).getReg() == AVR::R27R26; + + bool IsPredec = Opcode == AVR::LDRdPtrPd || Opcode == AVR::STPtrPdRr; + bool IsPostinc = Opcode == AVR::LDRdPtrPi || Opcode == AVR::STPtrPiRr; + + // Check if we need to set the inconsistent bit + if (IsRegX || IsPredec || IsPostinc) { + EncodedValue |= (1 << 12); + } + + return EncodedValue; +} + +template +unsigned +AVRMCCodeEmitter::encodeRelCondBrTarget(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCOperand &MO = MI.getOperand(OpNo); + + if (MO.isExpr()) { + Fixups.push_back(MCFixup::create(0, MO.getExpr(), + MCFixupKind(Fixup), MI.getLoc())); + return 0; + } + + assert(MO.isImm()); + + // Take the size of the current instruction away. + // With labels, this is implicitly done. + auto target = MO.getImm(); + AVR::fixups::adjustBranchTarget(target); + return target; +} + +unsigned AVRMCCodeEmitter::encodeLDSTPtrReg(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + auto MO = MI.getOperand(OpNo); + + // The operand should be a pointer register. + assert(MO.isReg()); + + switch (MO.getReg()) { + case AVR::R27R26: return 0x03; // X: 0b11 + case AVR::R29R28: return 0x02; // Y: 0b10 + case AVR::R31R30: return 0x00; // Z: 0b00 + default: + llvm_unreachable("invalid pointer register"); + } +} + +/// Encodes a `memri` operand. +/// The operand is 7-bits. +/// * The lower 6 bits is the immediate +/// * The upper bit is the pointer register bit (Z=0,Y=1) +unsigned AVRMCCodeEmitter::encodeMemri(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + auto RegOp = MI.getOperand(OpNo); + auto OffsetOp = MI.getOperand(OpNo + 1); + + assert(RegOp.isReg() && "Expected register operand"); + + uint8_t RegBit = 0; + + switch (RegOp.getReg()) { + default: + llvm_unreachable("Expected either Y or Z register"); + case AVR::R31R30: + RegBit = 0; + break; // Z register + case AVR::R29R28: + RegBit = 1; + break; // Y register + } + + int8_t OffsetBits; + + if (OffsetOp.isImm()) { + OffsetBits = OffsetOp.getImm(); + } else if (OffsetOp.isExpr()) { + OffsetBits = 0; + Fixups.push_back(MCFixup::create(0, OffsetOp.getExpr(), MCFixupKind(AVR::fixup_6), MI.getLoc())); + } else { + llvm_unreachable("invalid value for offset"); + } + + return (RegBit << 6) | OffsetBits; +} + +unsigned AVRMCCodeEmitter::encodeComplement(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + // The operand should be an immediate. + assert(MI.getOperand(OpNo).isImm()); + + auto Imm = MI.getOperand(OpNo).getImm(); + return (~0) - Imm; +} + +template +unsigned AVRMCCodeEmitter::encodeImm(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + auto MO = MI.getOperand(OpNo); + + if (MO.isExpr()) { + if (isa(MO.getExpr())) { + // If the expression is already an AVRMCExpr (i.e. a lo8(symbol), + // we shouldn't perform any more fixups. Without this check, we would + // instead create a fixup to the symbol named 'lo8(symbol)' which + // is not correct. + return getExprOpValue(MO.getExpr(), Fixups, STI); + } else { + MCFixupKind FixupKind = static_cast(Fixup); + Fixups.push_back(MCFixup::create(0, MO.getExpr(), FixupKind, MI.getLoc())); + + return 0; + } + } + + assert(MO.isImm()); + return MO.getImm(); +} + +unsigned AVRMCCodeEmitter::encodeCallTarget(const MCInst &MI, unsigned OpNo, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + auto MO = MI.getOperand(OpNo); + + if (MO.isExpr()) { + MCFixupKind FixupKind = static_cast(AVR::fixup_call); + Fixups.push_back(MCFixup::create(0, MO.getExpr(), FixupKind, MI.getLoc())); + return 0; + } + + assert(MO.isImm()); + + auto Target = MO.getImm(); + AVR::fixups::adjustBranchTarget(Target); + return Target; +} + +unsigned AVRMCCodeEmitter::getExprOpValue(const MCExpr *Expr, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + + MCExpr::ExprKind Kind = Expr->getKind(); + + if (Kind == MCExpr::Binary) { + Expr = static_cast(Expr)->getLHS(); + Kind = Expr->getKind(); + } + + if (Kind == MCExpr::Target) { + AVRMCExpr const *AVRExpr = cast(Expr); + int64_t Result; + if (AVRExpr->evaluateAsConstant(Result)) { + return Result; + } + + MCFixupKind FixupKind = static_cast(AVRExpr->getFixupKind()); + Fixups.push_back(MCFixup::create(0, AVRExpr, FixupKind)); + return 0; + } + + assert(Kind == MCExpr::SymbolRef); + return 0; +} + +unsigned AVRMCCodeEmitter::getMachineOpValue(const MCInst &MI, + const MCOperand &MO, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + if (MO.isReg()) { + return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg()); + } else if (MO.isImm()) { + return static_cast(MO.getImm()); + } else if (MO.isFPImm()) { + return static_cast(APFloat(MO.getFPImm()) + .bitcastToAPInt() + .getHiBits(32) + .getLimitedValue()); + } + + // MO must be an Expr. + assert(MO.isExpr()); + + return getExprOpValue(MO.getExpr(), Fixups, STI); +} + +void AVRMCCodeEmitter::emitInstruction(uint64_t Val, unsigned Size, + const MCSubtargetInfo &STI, + raw_ostream &OS) const { + const uint16_t *Words = reinterpret_cast(&Val); + size_t WordCount = Size / 2; + + for (int64_t i = WordCount - 1; i >= 0; --i) { + uint16_t Word = Words[i]; + + OS << (uint8_t) ((Word & 0x00ff) >> 0); + OS << (uint8_t) ((Word & 0xff00) >> 8); + } +} + +void AVRMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + const MCInstrDesc &Desc = MCII.get(MI.getOpcode()); + + // Get byte count of instruction + unsigned Size = Desc.getSize(); + + assert(Size > 0 && "Instruction size cannot be zero"); + + uint64_t BinaryOpCode = getBinaryCodeForInstr(MI, Fixups, STI); + emitInstruction(BinaryOpCode, Size, STI, OS); +} + +MCCodeEmitter *createAVRMCCodeEmitter(const MCInstrInfo &MCII, + const MCRegisterInfo &MRI, + MCContext &Ctx) { + return new AVRMCCodeEmitter(MCII, Ctx); +} + +#include "AVRGenMCCodeEmitter.inc" + +} // end of namespace llvm Index: lib/Target/AVR/MCTargetDesc/AVRMCTargetDesc.cpp =================================================================== --- lib/Target/AVR/MCTargetDesc/AVRMCTargetDesc.cpp +++ lib/Target/AVR/MCTargetDesc/AVRMCTargetDesc.cpp @@ -100,6 +100,9 @@ // Register the MCInstPrinter. TargetRegistry::RegisterMCInstPrinter(TheAVRTarget, createAVRMCInstPrinter); + // Register the MC Code Emitter + TargetRegistry::RegisterMCCodeEmitter(TheAVRTarget, createAVRMCCodeEmitter); + // Register the ELF streamer TargetRegistry::RegisterELFStreamer(TheAVRTarget, createMCStreamer); Index: lib/Target/AVR/MCTargetDesc/CMakeLists.txt =================================================================== --- lib/Target/AVR/MCTargetDesc/CMakeLists.txt +++ lib/Target/AVR/MCTargetDesc/CMakeLists.txt @@ -3,6 +3,7 @@ AVRELFObjectWriter.cpp AVRELFStreamer.cpp AVRMCAsmInfo.cpp + AVRMCCodeEmitter.cpp AVRMCExpr.cpp AVRMCTargetDesc.cpp AVRTargetStreamer.cpp