Path: blob/main/contrib/llvm-project/llvm/lib/Target/AVR/MCTargetDesc/AVRMCCodeEmitter.cpp
35294 views
//===-- AVRMCCodeEmitter.cpp - Convert AVR Code to Machine Code -----------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements the AVRMCCodeEmitter class.9//10//===----------------------------------------------------------------------===//1112#include "AVRMCCodeEmitter.h"1314#include "MCTargetDesc/AVRMCExpr.h"15#include "MCTargetDesc/AVRMCTargetDesc.h"1617#include "llvm/ADT/APFloat.h"18#include "llvm/ADT/SmallVector.h"19#include "llvm/MC/MCContext.h"20#include "llvm/MC/MCExpr.h"21#include "llvm/MC/MCFixup.h"22#include "llvm/MC/MCInst.h"23#include "llvm/MC/MCInstrInfo.h"24#include "llvm/MC/MCRegisterInfo.h"25#include "llvm/MC/MCSubtargetInfo.h"26#include "llvm/Support/Casting.h"27#include "llvm/Support/EndianStream.h"28#include "llvm/Support/raw_ostream.h"2930#define DEBUG_TYPE "mccodeemitter"3132#define GET_INSTRMAP_INFO33#include "AVRGenInstrInfo.inc"34#undef GET_INSTRMAP_INFO3536namespace llvm {3738/// Performs a post-encoding step on a `LD` or `ST` instruction.39///40/// The encoding of the LD/ST family of instructions is inconsistent w.r.t41/// the pointer register and the addressing mode.42///43/// The permutations of the format are as followed:44/// ld Rd, X `1001 000d dddd 1100`45/// ld Rd, X+ `1001 000d dddd 1101`46/// ld Rd, -X `1001 000d dddd 1110`47///48/// ld Rd, Y `1000 000d dddd 1000`49/// ld Rd, Y+ `1001 000d dddd 1001`50/// ld Rd, -Y `1001 000d dddd 1010`51///52/// ld Rd, Z `1000 000d dddd 0000`53/// ld Rd, Z+ `1001 000d dddd 0001`54/// ld Rd, -Z `1001 000d dddd 0010`55/// ^56/// |57/// Note this one inconsistent bit - it is 1 sometimes and 0 at other times.58/// There is no logical pattern. Looking at a truth table, the following59/// formula can be derived to fit the pattern:60//61/// ```62/// inconsistent_bit = is_predec OR is_postinc OR is_reg_x63/// ```64//65/// We manually set this bit in this post encoder method.66unsigned67AVRMCCodeEmitter::loadStorePostEncoder(const MCInst &MI, unsigned EncodedValue,68const MCSubtargetInfo &STI) const {6970assert(MI.getOperand(0).isReg() && MI.getOperand(1).isReg() &&71"the load/store operands must be registers");7273unsigned Opcode = MI.getOpcode();7475// check whether either of the registers are the X pointer register.76bool IsRegX = MI.getOperand(0).getReg() == AVR::R27R26 ||77MI.getOperand(1).getReg() == AVR::R27R26;7879bool IsPredec = Opcode == AVR::LDRdPtrPd || Opcode == AVR::STPtrPdRr;80bool IsPostinc = Opcode == AVR::LDRdPtrPi || Opcode == AVR::STPtrPiRr;8182// Check if we need to set the inconsistent bit83if (IsRegX || IsPredec || IsPostinc) {84EncodedValue |= (1 << 12);85}8687return EncodedValue;88}8990template <AVR::Fixups Fixup>91unsigned92AVRMCCodeEmitter::encodeRelCondBrTarget(const MCInst &MI, unsigned OpNo,93SmallVectorImpl<MCFixup> &Fixups,94const MCSubtargetInfo &STI) const {95const MCOperand &MO = MI.getOperand(OpNo);9697if (MO.isExpr()) {98Fixups.push_back(99MCFixup::create(0, MO.getExpr(), MCFixupKind(Fixup), MI.getLoc()));100return 0;101}102103assert(MO.isImm());104105// Take the size of the current instruction away.106// With labels, this is implicitly done.107auto target = MO.getImm();108AVR::fixups::adjustBranchTarget(target);109return target;110}111112unsigned AVRMCCodeEmitter::encodeLDSTPtrReg(const MCInst &MI, unsigned OpNo,113SmallVectorImpl<MCFixup> &Fixups,114const MCSubtargetInfo &STI) const {115auto MO = MI.getOperand(OpNo);116117// The operand should be a pointer register.118assert(MO.isReg());119120switch (MO.getReg()) {121case AVR::R27R26:122return 0x03; // X: 0b11123case AVR::R29R28:124return 0x02; // Y: 0b10125case AVR::R31R30:126return 0x00; // Z: 0b00127default:128llvm_unreachable("invalid pointer register");129}130}131132/// Encodes a `memri` operand.133/// The operand is 7-bits.134/// * The lower 6 bits is the immediate135/// * The upper bit is the pointer register bit (Z=0,Y=1)136unsigned AVRMCCodeEmitter::encodeMemri(const MCInst &MI, unsigned OpNo,137SmallVectorImpl<MCFixup> &Fixups,138const MCSubtargetInfo &STI) const {139auto RegOp = MI.getOperand(OpNo);140auto OffsetOp = MI.getOperand(OpNo + 1);141142assert(RegOp.isReg() && "Expected register operand");143144uint8_t RegBit = 0;145146switch (RegOp.getReg()) {147default:148Ctx.reportError(MI.getLoc(), "Expected either Y or Z register");149return 0;150case AVR::R31R30:151RegBit = 0;152break; // Z register153case AVR::R29R28:154RegBit = 1;155break; // Y register156}157158int8_t OffsetBits;159160if (OffsetOp.isImm()) {161OffsetBits = OffsetOp.getImm();162} else if (OffsetOp.isExpr()) {163OffsetBits = 0;164Fixups.push_back(MCFixup::create(0, OffsetOp.getExpr(),165MCFixupKind(AVR::fixup_6), MI.getLoc()));166} else {167llvm_unreachable("Invalid value for offset");168}169170return (RegBit << 6) | OffsetBits;171}172173unsigned AVRMCCodeEmitter::encodeComplement(const MCInst &MI, unsigned OpNo,174SmallVectorImpl<MCFixup> &Fixups,175const MCSubtargetInfo &STI) const {176// The operand should be an immediate.177assert(MI.getOperand(OpNo).isImm());178179auto Imm = MI.getOperand(OpNo).getImm();180return (~0) - Imm;181}182183template <AVR::Fixups Fixup, unsigned Offset>184unsigned AVRMCCodeEmitter::encodeImm(const MCInst &MI, unsigned OpNo,185SmallVectorImpl<MCFixup> &Fixups,186const MCSubtargetInfo &STI) const {187auto MO = MI.getOperand(OpNo);188189if (MO.isExpr()) {190if (isa<AVRMCExpr>(MO.getExpr())) {191// If the expression is already an AVRMCExpr (i.e. a lo8(symbol),192// we shouldn't perform any more fixups. Without this check, we would193// instead create a fixup to the symbol named 'lo8(symbol)' which194// is not correct.195return getExprOpValue(MO.getExpr(), Fixups, STI);196}197198MCFixupKind FixupKind = static_cast<MCFixupKind>(Fixup);199Fixups.push_back(200MCFixup::create(Offset, MO.getExpr(), FixupKind, MI.getLoc()));201202return 0;203}204205assert(MO.isImm());206return MO.getImm();207}208209unsigned AVRMCCodeEmitter::encodeCallTarget(const MCInst &MI, unsigned OpNo,210SmallVectorImpl<MCFixup> &Fixups,211const MCSubtargetInfo &STI) const {212auto MO = MI.getOperand(OpNo);213214if (MO.isExpr()) {215MCFixupKind FixupKind = static_cast<MCFixupKind>(AVR::fixup_call);216Fixups.push_back(MCFixup::create(0, MO.getExpr(), FixupKind, MI.getLoc()));217return 0;218}219220assert(MO.isImm());221222auto Target = MO.getImm();223AVR::fixups::adjustBranchTarget(Target);224return Target;225}226227unsigned AVRMCCodeEmitter::getExprOpValue(const MCExpr *Expr,228SmallVectorImpl<MCFixup> &Fixups,229const MCSubtargetInfo &STI) const {230231MCExpr::ExprKind Kind = Expr->getKind();232233if (Kind == MCExpr::Binary) {234Expr = static_cast<const MCBinaryExpr *>(Expr)->getLHS();235Kind = Expr->getKind();236}237238if (Kind == MCExpr::Target) {239AVRMCExpr const *AVRExpr = cast<AVRMCExpr>(Expr);240int64_t Result;241if (AVRExpr->evaluateAsConstant(Result)) {242return Result;243}244245MCFixupKind FixupKind = static_cast<MCFixupKind>(AVRExpr->getFixupKind());246Fixups.push_back(MCFixup::create(0, AVRExpr, FixupKind));247return 0;248}249250assert(Kind == MCExpr::SymbolRef);251return 0;252}253254unsigned AVRMCCodeEmitter::getMachineOpValue(const MCInst &MI,255const MCOperand &MO,256SmallVectorImpl<MCFixup> &Fixups,257const MCSubtargetInfo &STI) const {258if (MO.isReg())259return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg());260if (MO.isImm())261return static_cast<unsigned>(MO.getImm());262263if (MO.isDFPImm())264return static_cast<unsigned>(bit_cast<double>(MO.getDFPImm()));265266// MO must be an Expr.267assert(MO.isExpr());268269return getExprOpValue(MO.getExpr(), Fixups, STI);270}271272void AVRMCCodeEmitter::encodeInstruction(const MCInst &MI,273SmallVectorImpl<char> &CB,274SmallVectorImpl<MCFixup> &Fixups,275const MCSubtargetInfo &STI) const {276const MCInstrDesc &Desc = MCII.get(MI.getOpcode());277278// Get byte count of instruction279unsigned Size = Desc.getSize();280281assert(Size > 0 && "Instruction size cannot be zero");282283uint64_t BinaryOpCode = getBinaryCodeForInstr(MI, Fixups, STI);284285for (int64_t i = Size / 2 - 1; i >= 0; --i) {286uint16_t Word = (BinaryOpCode >> (i * 16)) & 0xFFFF;287support::endian::write(CB, Word, llvm::endianness::little);288}289}290291MCCodeEmitter *createAVRMCCodeEmitter(const MCInstrInfo &MCII,292MCContext &Ctx) {293return new AVRMCCodeEmitter(MCII, Ctx);294}295296#include "AVRGenMCCodeEmitter.inc"297298} // end of namespace llvm299300301