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