301 lines · cpp
1//===-- AVRMCCodeEmitter.cpp - Convert AVR Code to Machine Code -----------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the AVRMCCodeEmitter class.10//11//===----------------------------------------------------------------------===//12 13#include "AVRMCCodeEmitter.h"14 15#include "MCTargetDesc/AVRMCAsmInfo.h"16#include "MCTargetDesc/AVRMCTargetDesc.h"17 18#include "llvm/ADT/APFloat.h"19#include "llvm/ADT/SmallVector.h"20#include "llvm/MC/MCContext.h"21#include "llvm/MC/MCExpr.h"22#include "llvm/MC/MCFixup.h"23#include "llvm/MC/MCInst.h"24#include "llvm/MC/MCInstrInfo.h"25#include "llvm/MC/MCRegisterInfo.h"26#include "llvm/MC/MCSubtargetInfo.h"27#include "llvm/Support/Casting.h"28#include "llvm/Support/EndianStream.h"29 30#define DEBUG_TYPE "mccodeemitter"31 32#define GET_INSTRMAP_INFO33#include "AVRGenInstrInfo.inc"34#undef GET_INSTRMAP_INFO35 36namespace llvm {37 38static void addFixup(SmallVectorImpl<MCFixup> &Fixups, uint32_t Offset,39 const MCExpr *Value, uint16_t Kind) {40 bool PCRel = false;41 switch (Kind) {42 case AVR::fixup_7_pcrel:43 case AVR::fixup_13_pcrel:44 PCRel = true;45 }46 Fixups.push_back(MCFixup::create(Offset, Value, Kind, PCRel));47}48 49/// Performs a post-encoding step on a `LD` or `ST` instruction.50///51/// The encoding of the LD/ST family of instructions is inconsistent w.r.t52/// the pointer register and the addressing mode.53///54/// The permutations of the format are as followed:55/// ld Rd, X `1001 000d dddd 1100`56/// ld Rd, X+ `1001 000d dddd 1101`57/// ld Rd, -X `1001 000d dddd 1110`58///59/// ld Rd, Y `1000 000d dddd 1000`60/// ld Rd, Y+ `1001 000d dddd 1001`61/// ld Rd, -Y `1001 000d dddd 1010`62///63/// ld Rd, Z `1000 000d dddd 0000`64/// ld Rd, Z+ `1001 000d dddd 0001`65/// ld Rd, -Z `1001 000d dddd 0010`66/// ^67/// |68/// Note this one inconsistent bit - it is 1 sometimes and 0 at other times.69/// There is no logical pattern. Looking at a truth table, the following70/// formula can be derived to fit the pattern:71//72/// ```73/// inconsistent_bit = is_predec OR is_postinc OR is_reg_x74/// ```75//76/// We manually set this bit in this post encoder method.77unsigned78AVRMCCodeEmitter::loadStorePostEncoder(const MCInst &MI, unsigned EncodedValue,79 const MCSubtargetInfo &STI) const {80 81 assert(MI.getOperand(0).isReg() && MI.getOperand(1).isReg() &&82 "the load/store operands must be registers");83 84 unsigned Opcode = MI.getOpcode();85 86 // Get the index of the pointer register operand.87 unsigned Idx = 0;88 if (Opcode == AVR::LDRdPtrPd || Opcode == AVR::LDRdPtrPi ||89 Opcode == AVR::LDRdPtr)90 Idx = 1;91 92 // Check if we need to set the inconsistent bit93 bool IsPredec = Opcode == AVR::LDRdPtrPd || Opcode == AVR::STPtrPdRr;94 bool IsPostinc = Opcode == AVR::LDRdPtrPi || Opcode == AVR::STPtrPiRr;95 if (MI.getOperand(Idx).getReg() == AVR::R27R26 || IsPredec || IsPostinc)96 EncodedValue |= (1 << 12);97 98 // Encode the pointer register.99 switch (MI.getOperand(Idx).getReg().id()) {100 case AVR::R27R26:101 EncodedValue |= 0xc;102 break;103 case AVR::R29R28:104 EncodedValue |= 0x8;105 break;106 case AVR::R31R30:107 break;108 default:109 llvm_unreachable("invalid pointer register");110 break;111 }112 113 return EncodedValue;114}115 116template <AVR::Fixups Fixup>117unsigned118AVRMCCodeEmitter::encodeRelCondBrTarget(const MCInst &MI, unsigned OpNo,119 SmallVectorImpl<MCFixup> &Fixups,120 const MCSubtargetInfo &STI) const {121 const MCOperand &MO = MI.getOperand(OpNo);122 123 if (MO.isExpr()) {124 addFixup(Fixups, 0, MO.getExpr(), MCFixupKind(Fixup));125 return 0;126 }127 128 assert(MO.isImm());129 130 // Take the size of the current instruction away.131 // With labels, this is implicitly done.132 auto target = MO.getImm();133 AVR::fixups::adjustBranchTarget(target);134 return target;135}136 137/// Encodes a `memri` operand.138/// The operand is 7-bits.139/// * The lower 6 bits is the immediate140/// * The upper bit is the pointer register bit (Z=0,Y=1)141unsigned AVRMCCodeEmitter::encodeMemri(const MCInst &MI, unsigned OpNo,142 SmallVectorImpl<MCFixup> &Fixups,143 const MCSubtargetInfo &STI) const {144 auto RegOp = MI.getOperand(OpNo);145 auto OffsetOp = MI.getOperand(OpNo + 1);146 147 assert(RegOp.isReg() && "Expected register operand");148 149 uint8_t RegBit = 0;150 151 switch (RegOp.getReg().id()) {152 default:153 Ctx.reportError(MI.getLoc(), "Expected either Y or Z register");154 return 0;155 case AVR::R31R30:156 RegBit = 0;157 break; // Z register158 case AVR::R29R28:159 RegBit = 1;160 break; // Y register161 }162 163 int8_t OffsetBits;164 165 if (OffsetOp.isImm()) {166 OffsetBits = OffsetOp.getImm();167 } else if (OffsetOp.isExpr()) {168 OffsetBits = 0;169 addFixup(Fixups, 0, OffsetOp.getExpr(), AVR::fixup_6);170 } else {171 llvm_unreachable("Invalid value for offset");172 }173 174 return (RegBit << 6) | OffsetBits;175}176 177unsigned AVRMCCodeEmitter::encodeComplement(const MCInst &MI, unsigned OpNo,178 SmallVectorImpl<MCFixup> &Fixups,179 const MCSubtargetInfo &STI) const {180 // The operand should be an immediate.181 assert(MI.getOperand(OpNo).isImm());182 183 auto Imm = MI.getOperand(OpNo).getImm();184 return (~0) - Imm;185}186 187template <AVR::Fixups Fixup, unsigned Offset>188unsigned AVRMCCodeEmitter::encodeImm(const MCInst &MI, unsigned OpNo,189 SmallVectorImpl<MCFixup> &Fixups,190 const MCSubtargetInfo &STI) const {191 auto MO = MI.getOperand(OpNo);192 193 if (MO.isExpr()) {194 if (isa<AVRMCExpr>(MO.getExpr())) {195 // If the expression is already an AVRMCExpr (i.e. a lo8(symbol),196 // we shouldn't perform any more fixups. Without this check, we would197 // instead create a fixup to the symbol named 'lo8(symbol)' which198 // is not correct.199 return getExprOpValue(MO.getExpr(), Fixups, STI);200 }201 202 MCFixupKind FixupKind = static_cast<MCFixupKind>(Fixup);203 addFixup(Fixups, Offset, MO.getExpr(), FixupKind);204 205 return 0;206 }207 208 assert(MO.isImm());209 return MO.getImm();210}211 212unsigned AVRMCCodeEmitter::encodeCallTarget(const MCInst &MI, unsigned OpNo,213 SmallVectorImpl<MCFixup> &Fixups,214 const MCSubtargetInfo &STI) const {215 auto MO = MI.getOperand(OpNo);216 217 if (MO.isExpr()) {218 MCFixupKind FixupKind = AVR::fixup_call;219 addFixup(Fixups, 0, MO.getExpr(), FixupKind);220 return 0;221 }222 223 assert(MO.isImm());224 225 auto Target = MO.getImm();226 AVR::fixups::adjustBranchTarget(Target);227 return Target;228}229 230unsigned AVRMCCodeEmitter::getExprOpValue(const MCExpr *Expr,231 SmallVectorImpl<MCFixup> &Fixups,232 const MCSubtargetInfo &STI) const {233 234 MCExpr::ExprKind Kind = Expr->getKind();235 236 if (Kind == MCExpr::Binary) {237 Expr = static_cast<const MCBinaryExpr *>(Expr)->getLHS();238 Kind = Expr->getKind();239 }240 241 if (Kind == MCExpr::Specifier) {242 AVRMCExpr const *AVRExpr = cast<AVRMCExpr>(Expr);243 int64_t Result;244 if (AVRExpr->evaluateAsConstant(Result)) {245 return Result;246 }247 248 MCFixupKind FixupKind = static_cast<MCFixupKind>(AVRExpr->getFixupKind());249 addFixup(Fixups, 0, AVRExpr, FixupKind);250 return 0;251 }252 253 assert(Kind == MCExpr::SymbolRef);254 return 0;255}256 257unsigned AVRMCCodeEmitter::getMachineOpValue(const MCInst &MI,258 const MCOperand &MO,259 SmallVectorImpl<MCFixup> &Fixups,260 const MCSubtargetInfo &STI) const {261 if (MO.isReg())262 return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg());263 if (MO.isImm())264 return static_cast<unsigned>(MO.getImm());265 266 if (MO.isDFPImm())267 return static_cast<unsigned>(bit_cast<double>(MO.getDFPImm()));268 269 // MO must be an Expr.270 assert(MO.isExpr());271 272 return getExprOpValue(MO.getExpr(), Fixups, STI);273}274 275void AVRMCCodeEmitter::encodeInstruction(const MCInst &MI,276 SmallVectorImpl<char> &CB,277 SmallVectorImpl<MCFixup> &Fixups,278 const MCSubtargetInfo &STI) const {279 const MCInstrDesc &Desc = MCII.get(MI.getOpcode());280 281 // Get byte count of instruction282 unsigned Size = Desc.getSize();283 284 assert(Size > 0 && "Instruction size cannot be zero");285 286 uint64_t BinaryOpCode = getBinaryCodeForInstr(MI, Fixups, STI);287 288 for (int64_t i = Size / 2 - 1; i >= 0; --i) {289 uint16_t Word = (BinaryOpCode >> (i * 16)) & 0xFFFF;290 support::endian::write(CB, Word, llvm::endianness::little);291 }292}293 294MCCodeEmitter *createAVRMCCodeEmitter(const MCInstrInfo &MCII, MCContext &Ctx) {295 return new AVRMCCodeEmitter(MCII, Ctx);296}297 298#include "AVRGenMCCodeEmitter.inc"299 300} // end of namespace llvm301