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 llvm_unreachable("Expected either Y or Z register"); 150 case AVR::R31R30: 151 RegBit = 0; 152 break; // Z register 153 case AVR::R29R28: 154 RegBit = 1; 155 break; // Y register 156 } 157 158 int8_t OffsetBits; 159 160 if (OffsetOp.isImm()) { 161 OffsetBits = OffsetOp.getImm(); 162 } else if (OffsetOp.isExpr()) { 163 OffsetBits = 0; 164 Fixups.push_back(MCFixup::create(0, OffsetOp.getExpr(), 165 MCFixupKind(AVR::fixup_6), MI.getLoc())); 166 } else { 167 llvm_unreachable("invalid value for offset"); 168 } 169 170 return (RegBit << 6) | OffsetBits; 171 } 172 173 unsigned AVRMCCodeEmitter::encodeComplement(const MCInst &MI, unsigned OpNo, 174 SmallVectorImpl<MCFixup> &Fixups, 175 const MCSubtargetInfo &STI) const { 176 // The operand should be an immediate. 177 assert(MI.getOperand(OpNo).isImm()); 178 179 auto Imm = MI.getOperand(OpNo).getImm(); 180 return (~0) - Imm; 181 } 182 183 template <AVR::Fixups Fixup, unsigned Offset> 184 unsigned AVRMCCodeEmitter::encodeImm(const MCInst &MI, unsigned OpNo, 185 SmallVectorImpl<MCFixup> &Fixups, 186 const MCSubtargetInfo &STI) const { 187 auto MO = MI.getOperand(OpNo); 188 189 if (MO.isExpr()) { 190 if (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 would 193 // instead create a fixup to the symbol named 'lo8(symbol)' which 194 // is not correct. 195 return getExprOpValue(MO.getExpr(), Fixups, STI); 196 } 197 198 MCFixupKind FixupKind = static_cast<MCFixupKind>(Fixup); 199 Fixups.push_back( 200 MCFixup::create(Offset, MO.getExpr(), FixupKind, MI.getLoc())); 201 202 return 0; 203 } 204 205 assert(MO.isImm()); 206 return MO.getImm(); 207 } 208 209 unsigned AVRMCCodeEmitter::encodeCallTarget(const MCInst &MI, unsigned OpNo, 210 SmallVectorImpl<MCFixup> &Fixups, 211 const MCSubtargetInfo &STI) const { 212 auto MO = MI.getOperand(OpNo); 213 214 if (MO.isExpr()) { 215 MCFixupKind FixupKind = static_cast<MCFixupKind>(AVR::fixup_call); 216 Fixups.push_back(MCFixup::create(0, MO.getExpr(), FixupKind, MI.getLoc())); 217 return 0; 218 } 219 220 assert(MO.isImm()); 221 222 auto Target = MO.getImm(); 223 AVR::fixups::adjustBranchTarget(Target); 224 return Target; 225 } 226 227 unsigned AVRMCCodeEmitter::getExprOpValue(const MCExpr *Expr, 228 SmallVectorImpl<MCFixup> &Fixups, 229 const MCSubtargetInfo &STI) const { 230 231 MCExpr::ExprKind Kind = Expr->getKind(); 232 233 if (Kind == MCExpr::Binary) { 234 Expr = static_cast<const MCBinaryExpr *>(Expr)->getLHS(); 235 Kind = Expr->getKind(); 236 } 237 238 if (Kind == MCExpr::Target) { 239 AVRMCExpr const *AVRExpr = cast<AVRMCExpr>(Expr); 240 int64_t Result; 241 if (AVRExpr->evaluateAsConstant(Result)) { 242 return Result; 243 } 244 245 MCFixupKind FixupKind = static_cast<MCFixupKind>(AVRExpr->getFixupKind()); 246 Fixups.push_back(MCFixup::create(0, AVRExpr, FixupKind)); 247 return 0; 248 } 249 250 assert(Kind == MCExpr::SymbolRef); 251 return 0; 252 } 253 254 unsigned AVRMCCodeEmitter::getMachineOpValue(const MCInst &MI, 255 const MCOperand &MO, 256 SmallVectorImpl<MCFixup> &Fixups, 257 const MCSubtargetInfo &STI) const { 258 if (MO.isReg()) 259 return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg()); 260 if (MO.isImm()) 261 return static_cast<unsigned>(MO.getImm()); 262 263 if (MO.isDFPImm()) 264 return static_cast<unsigned>(bit_cast<double>(MO.getDFPImm())); 265 266 // MO must be an Expr. 267 assert(MO.isExpr()); 268 269 return getExprOpValue(MO.getExpr(), Fixups, STI); 270 } 271 272 void AVRMCCodeEmitter::emitInstruction(uint64_t Val, unsigned Size, 273 const MCSubtargetInfo &STI, 274 raw_ostream &OS) const { 275 size_t WordCount = Size / 2; 276 277 for (int64_t i = WordCount - 1; i >= 0; --i) { 278 uint16_t Word = (Val >> (i * 16)) & 0xFFFF; 279 support::endian::write(OS, Word, support::endianness::little); 280 } 281 } 282 283 void AVRMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS, 284 SmallVectorImpl<MCFixup> &Fixups, 285 const MCSubtargetInfo &STI) const { 286 const MCInstrDesc &Desc = MCII.get(MI.getOpcode()); 287 288 // Get byte count of instruction 289 unsigned Size = Desc.getSize(); 290 291 assert(Size > 0 && "Instruction size cannot be zero"); 292 293 uint64_t BinaryOpCode = getBinaryCodeForInstr(MI, Fixups, STI); 294 emitInstruction(BinaryOpCode, Size, STI, OS); 295 } 296 297 MCCodeEmitter *createAVRMCCodeEmitter(const MCInstrInfo &MCII, 298 const MCRegisterInfo &MRI, 299 MCContext &Ctx) { 300 return new AVRMCCodeEmitter(MCII, Ctx); 301 } 302 303 #include "AVRGenMCCodeEmitter.inc" 304 305 } // end of namespace llvm 306