518 lines · cpp
1//===-- PPCMCCodeEmitter.cpp - Convert PPC 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 PPCMCCodeEmitter class.10//11//===----------------------------------------------------------------------===//12 13#include "PPCMCCodeEmitter.h"14#include "MCTargetDesc/PPCFixupKinds.h"15#include "PPCMCAsmInfo.h"16#include "PPCMCTargetDesc.h"17#include "llvm/ADT/SmallVector.h"18#include "llvm/ADT/Statistic.h"19#include "llvm/MC/MCExpr.h"20#include "llvm/MC/MCFixup.h"21#include "llvm/MC/MCInstrDesc.h"22#include "llvm/MC/MCRegisterInfo.h"23#include "llvm/Support/Casting.h"24#include "llvm/Support/EndianStream.h"25#include "llvm/Support/MathExtras.h"26#include "llvm/TargetParser/Triple.h"27#include <cassert>28#include <cstdint>29 30using namespace llvm;31 32#define DEBUG_TYPE "mccodeemitter"33 34STATISTIC(MCNumEmitted, "Number of MC instructions emitted");35 36MCCodeEmitter *llvm::createPPCMCCodeEmitter(const MCInstrInfo &MCII,37 MCContext &Ctx) {38 return new PPCMCCodeEmitter(MCII, Ctx);39}40 41static void addFixup(SmallVectorImpl<MCFixup> &Fixups, uint32_t Offset,42 const MCExpr *Value, uint16_t Kind) {43 bool PCRel = false;44 switch (Kind) {45 case PPC::fixup_ppc_br24:46 case PPC::fixup_ppc_br24_notoc:47 case PPC::fixup_ppc_brcond14:48 case PPC::fixup_ppc_pcrel34:49 case PPC::fixup_ppc_pcrel32:50 PCRel = true;51 }52 Fixups.push_back(MCFixup::create(Offset, Value, Kind, PCRel));53}54 55unsigned PPCMCCodeEmitter::56getDirectBrEncoding(const MCInst &MI, unsigned OpNo,57 SmallVectorImpl<MCFixup> &Fixups,58 const MCSubtargetInfo &STI) const {59 const MCOperand &MO = MI.getOperand(OpNo);60 61 if (MO.isReg() || MO.isImm())62 return getMachineOpValue(MI, MO, Fixups, STI);63 64 // Add a fixup for the branch target.65 addFixup(66 Fixups, 0, MO.getExpr(),67 (isNoTOCCallInstr(MI) ? PPC::fixup_ppc_br24_notoc : PPC::fixup_ppc_br24));68 return 0;69}70 71/// Check if Opcode corresponds to a call instruction that should be marked72/// with the NOTOC relocation.73bool PPCMCCodeEmitter::isNoTOCCallInstr(const MCInst &MI) const {74 unsigned Opcode = MI.getOpcode();75 if (!MCII.get(Opcode).isCall())76 return false;77 78 switch (Opcode) {79 default:80#ifndef NDEBUG81 llvm_unreachable("Unknown call opcode");82#endif83 return false;84 case PPC::BL8_NOTOC:85 case PPC::BL8_NOTOC_TLS:86 case PPC::BL8_NOTOC_RM:87 return true;88#ifndef NDEBUG89 case PPC::BL8:90 case PPC::BL:91 case PPC::BL8_TLS:92 case PPC::BL_TLS:93 case PPC::BLA8:94 case PPC::BLA:95 case PPC::BCCL:96 case PPC::BCCLA:97 case PPC::BCL:98 case PPC::BCLn:99 case PPC::BL8_NOP:100 case PPC::BL_NOP:101 case PPC::BL8_NOP_TLS:102 case PPC::BLA8_NOP:103 case PPC::BCTRL8:104 case PPC::BCTRL:105 case PPC::BCCCTRL8:106 case PPC::BCCCTRL:107 case PPC::BCCTRL8:108 case PPC::BCCTRL:109 case PPC::BCCTRL8n:110 case PPC::BCCTRLn:111 case PPC::BL8_RM:112 case PPC::BLA8_RM:113 case PPC::BL8_NOP_RM:114 case PPC::BLA8_NOP_RM:115 case PPC::BCTRL8_RM:116 case PPC::BCTRL8_LDinto_toc:117 case PPC::BCTRL8_LDinto_toc_RM:118 case PPC::BL8_TLS_:119 case PPC::TCRETURNdi8:120 case PPC::TCRETURNai8:121 case PPC::TCRETURNri8:122 case PPC::TAILBCTR8:123 case PPC::TAILB8:124 case PPC::TAILBA8:125 case PPC::BCLalways:126 case PPC::BLRL:127 case PPC::BCCLRL:128 case PPC::BCLRL:129 case PPC::BCLRLn:130 case PPC::BDZL:131 case PPC::BDNZL:132 case PPC::BDZLA:133 case PPC::BDNZLA:134 case PPC::BDZLp:135 case PPC::BDNZLp:136 case PPC::BDZLAp:137 case PPC::BDNZLAp:138 case PPC::BDZLm:139 case PPC::BDNZLm:140 case PPC::BDZLAm:141 case PPC::BDNZLAm:142 case PPC::BDZLRL:143 case PPC::BDNZLRL:144 case PPC::BDZLRLp:145 case PPC::BDNZLRLp:146 case PPC::BDZLRLm:147 case PPC::BDNZLRLm:148 case PPC::BL_RM:149 case PPC::BLA_RM:150 case PPC::BL_NOP_RM:151 case PPC::BCTRL_RM:152 case PPC::TCRETURNdi:153 case PPC::TCRETURNai:154 case PPC::TCRETURNri:155 case PPC::BCTRL_LWZinto_toc:156 case PPC::BCTRL_LWZinto_toc_RM:157 case PPC::TAILBCTR:158 case PPC::TAILB:159 case PPC::TAILBA:160 return false;161#endif162 }163}164 165unsigned PPCMCCodeEmitter::getCondBrEncoding(const MCInst &MI, unsigned OpNo,166 SmallVectorImpl<MCFixup> &Fixups,167 const MCSubtargetInfo &STI) const {168 const MCOperand &MO = MI.getOperand(OpNo);169 if (MO.isReg() || MO.isImm()) return getMachineOpValue(MI, MO, Fixups, STI);170 171 // Add a fixup for the branch target.172 addFixup(Fixups, 0, MO.getExpr(), PPC::fixup_ppc_brcond14);173 return 0;174}175 176unsigned PPCMCCodeEmitter::177getAbsDirectBrEncoding(const MCInst &MI, unsigned OpNo,178 SmallVectorImpl<MCFixup> &Fixups,179 const MCSubtargetInfo &STI) const {180 const MCOperand &MO = MI.getOperand(OpNo);181 if (MO.isReg() || MO.isImm()) return getMachineOpValue(MI, MO, Fixups, STI);182 183 // Add a fixup for the branch target.184 addFixup(Fixups, 0, MO.getExpr(), PPC::fixup_ppc_br24abs);185 return 0;186}187 188unsigned PPCMCCodeEmitter::189getAbsCondBrEncoding(const MCInst &MI, unsigned OpNo,190 SmallVectorImpl<MCFixup> &Fixups,191 const MCSubtargetInfo &STI) const {192 const MCOperand &MO = MI.getOperand(OpNo);193 if (MO.isReg() || MO.isImm()) return getMachineOpValue(MI, MO, Fixups, STI);194 195 // Add a fixup for the branch target.196 addFixup(Fixups, 0, MO.getExpr(), PPC::fixup_ppc_brcond14abs);197 return 0;198}199 200unsigned201PPCMCCodeEmitter::getVSRpEvenEncoding(const MCInst &MI, unsigned OpNo,202 SmallVectorImpl<MCFixup> &Fixups,203 const MCSubtargetInfo &STI) const {204 assert(MI.getOperand(OpNo).isReg() && "Operand should be a register");205 unsigned RegBits = getMachineOpValue(MI, MI.getOperand(OpNo), Fixups, STI)206 << 1;207 return RegBits;208}209 210template <MCFixupKind Fixup>211uint64_t PPCMCCodeEmitter::getImmEncoding(const MCInst &MI, unsigned OpNo,212 SmallVectorImpl<MCFixup> &Fixups,213 const MCSubtargetInfo &STI) const {214 const MCOperand &MO = MI.getOperand(OpNo);215 assert(!MO.isReg() && "Not expecting a register for this operand.");216 if (MO.isImm())217 return getMachineOpValue(MI, MO, Fixups, STI);218 219 uint32_t Offset = 0;220 if (Fixup == PPC::fixup_ppc_half16)221 Offset = IsLittleEndian ? 0 : 2;222 223 // Add a fixup for the immediate field.224 addFixup(Fixups, Offset, MO.getExpr(), Fixup);225 return 0;226}227 228unsigned PPCMCCodeEmitter::getDispRIEncoding(const MCInst &MI, unsigned OpNo,229 SmallVectorImpl<MCFixup> &Fixups,230 const MCSubtargetInfo &STI) const {231 const MCOperand &MO = MI.getOperand(OpNo);232 if (MO.isImm())233 return getMachineOpValue(MI, MO, Fixups, STI) & 0xFFFF;234 235 // Add a fixup for the displacement field.236 addFixup(Fixups, IsLittleEndian ? 0 : 2, MO.getExpr(), PPC::fixup_ppc_half16);237 return 0;238}239 240unsigned241PPCMCCodeEmitter::getDispRIXEncoding(const MCInst &MI, unsigned OpNo,242 SmallVectorImpl<MCFixup> &Fixups,243 const MCSubtargetInfo &STI) const {244 const MCOperand &MO = MI.getOperand(OpNo);245 if (MO.isImm())246 return ((getMachineOpValue(MI, MO, Fixups, STI) >> 2) & 0x3FFF);247 248 // Add a fixup for the displacement field.249 addFixup(Fixups, IsLittleEndian ? 0 : 2, MO.getExpr(),250 PPC::fixup_ppc_half16ds);251 return 0;252}253 254unsigned255PPCMCCodeEmitter::getDispRIX16Encoding(const MCInst &MI, unsigned OpNo,256 SmallVectorImpl<MCFixup> &Fixups,257 const MCSubtargetInfo &STI) const {258 const MCOperand &MO = MI.getOperand(OpNo);259 if (MO.isImm()) {260 assert(!(MO.getImm() % 16) &&261 "Expecting an immediate that is a multiple of 16");262 return ((getMachineOpValue(MI, MO, Fixups, STI) >> 4) & 0xFFF);263 }264 265 // Otherwise add a fixup for the displacement field.266 addFixup(Fixups, IsLittleEndian ? 0 : 2, MO.getExpr(),267 PPC::fixup_ppc_half16dq);268 return 0;269}270 271unsigned272PPCMCCodeEmitter::getDispRIHashEncoding(const MCInst &MI, unsigned OpNo,273 SmallVectorImpl<MCFixup> &Fixups,274 const MCSubtargetInfo &STI) const {275 // Encode imm for the hash load/store to stack for the ROP Protection276 // instructions.277 const MCOperand &MO = MI.getOperand(OpNo);278 279 assert(MO.isImm() && "Expecting an immediate operand.");280 assert(!(MO.getImm() % 8) && "Expecting offset to be 8 byte aligned.");281 282 unsigned DX = (MO.getImm() >> 3) & 0x3F;283 return DX;284}285 286uint64_t287PPCMCCodeEmitter::getDispRI34PCRelEncoding(const MCInst &MI, unsigned OpNo,288 SmallVectorImpl<MCFixup> &Fixups,289 const MCSubtargetInfo &STI) const {290 // Encode the displacement part of pc-relative memri34, which is an imm34.291 // The 34 bit immediate can fall into one of three cases:292 // 1) It is a relocation to be filled in by the linker represented as:293 // (MCExpr::SymbolRef)294 // 2) It is a relocation + SignedOffset represented as:295 // (MCExpr::Binary(MCExpr::SymbolRef + MCExpr::Constant))296 // 3) It is a known value at compile time.297 298 // If this is not a MCExpr then we are in case 3) and we are dealing with299 // a value known at compile time, not a relocation.300 const MCOperand &MO = MI.getOperand(OpNo);301 if (!MO.isExpr())302 return (getMachineOpValue(MI, MO, Fixups, STI)) & 0x3FFFFFFFFUL;303 304 // At this point in the function it is known that MO is of type MCExpr.305 // Therefore we are dealing with either case 1) a symbol ref or306 // case 2) a symbol ref plus a constant.307 const MCExpr *Expr = MO.getExpr();308 switch (Expr->getKind()) {309 default:310 llvm_unreachable("Unsupported MCExpr for getMemRI34PCRelEncoding.");311 case MCExpr::SymbolRef: {312 // Relocation alone.313 const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(Expr);314 (void)SRE;315 // Currently these are the only valid PCRelative Relocations.316 assert(is_contained({PPC::S_PCREL, PPC::S_GOT_PCREL, PPC::S_GOT_TLSGD_PCREL,317 PPC::S_GOT_TLSLD_PCREL, PPC::S_GOT_TPREL_PCREL},318 SRE->getSpecifier()) &&319 "specifier must be S_PCREL, S_GOT_PCREL, S_GOT_TLSGD_PCREL, "320 "S_GOT_TLSLD_PCREL, or S_GOT_TPREL_PCREL");321 // Generate the fixup for the relocation.322 addFixup(Fixups, 0, Expr, PPC::fixup_ppc_pcrel34);323 // Put zero in the location of the immediate. The linker will fill in the324 // correct value based on the relocation.325 return 0;326 }327 case MCExpr::Binary: {328 // Relocation plus some offset.329 const MCBinaryExpr *BE = cast<MCBinaryExpr>(Expr);330 assert(BE->getOpcode() == MCBinaryExpr::Add &&331 "Binary expression opcode must be an add.");332 333 const MCExpr *LHS = BE->getLHS();334 const MCExpr *RHS = BE->getRHS();335 336 // Need to check in both directions. Reloc+Offset and Offset+Reloc.337 if (LHS->getKind() != MCExpr::SymbolRef)338 std::swap(LHS, RHS);339 340 if (LHS->getKind() != MCExpr::SymbolRef ||341 RHS->getKind() != MCExpr::Constant)342 llvm_unreachable("Expecting to have one constant and one relocation.");343 344 const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(LHS);345 (void)SRE;346 assert(isInt<34>(cast<MCConstantExpr>(RHS)->getValue()) &&347 "Value must fit in 34 bits.");348 349 // Currently these are the only valid PCRelative Relocations.350 assert((getSpecifier(SRE) == PPC::S_PCREL ||351 getSpecifier(SRE) == PPC::S_GOT_PCREL) &&352 "VariantKind must be VK_PCREL or VK_GOT_PCREL");353 // Generate the fixup for the relocation.354 addFixup(Fixups, 0, Expr, PPC::fixup_ppc_pcrel34);355 // Put zero in the location of the immediate. The linker will fill in the356 // correct value based on the relocation.357 return 0;358 }359 }360}361 362uint64_t363PPCMCCodeEmitter::getDispRI34Encoding(const MCInst &MI, unsigned OpNo,364 SmallVectorImpl<MCFixup> &Fixups,365 const MCSubtargetInfo &STI) const {366 // Encode the displacement part of a memri34.367 const MCOperand &MO = MI.getOperand(OpNo);368 return (getMachineOpValue(MI, MO, Fixups, STI)) & 0x3FFFFFFFFUL;369}370 371unsigned372PPCMCCodeEmitter::getDispSPE8Encoding(const MCInst &MI, unsigned OpNo,373 SmallVectorImpl<MCFixup> &Fixups,374 const MCSubtargetInfo &STI) const {375 // Encode imm as a dispSPE8, which has the low 5-bits of (imm / 8).376 const MCOperand &MO = MI.getOperand(OpNo);377 assert(MO.isImm());378 return getMachineOpValue(MI, MO, Fixups, STI) >> 3;379}380 381unsigned382PPCMCCodeEmitter::getDispSPE4Encoding(const MCInst &MI, unsigned OpNo,383 SmallVectorImpl<MCFixup> &Fixups,384 const MCSubtargetInfo &STI) const {385 // Encode imm as a dispSPE8, which has the low 5-bits of (imm / 4).386 const MCOperand &MO = MI.getOperand(OpNo);387 assert(MO.isImm());388 return getMachineOpValue(MI, MO, Fixups, STI) >> 2;389}390 391unsigned392PPCMCCodeEmitter::getDispSPE2Encoding(const MCInst &MI, unsigned OpNo,393 SmallVectorImpl<MCFixup> &Fixups,394 const MCSubtargetInfo &STI) const {395 // Encode imm as a dispSPE8, which has the low 5-bits of (imm / 2).396 const MCOperand &MO = MI.getOperand(OpNo);397 assert(MO.isImm());398 return getMachineOpValue(MI, MO, Fixups, STI) >> 1;399}400 401unsigned PPCMCCodeEmitter::getTLSRegEncoding(const MCInst &MI, unsigned OpNo,402 SmallVectorImpl<MCFixup> &Fixups,403 const MCSubtargetInfo &STI) const {404 const MCOperand &MO = MI.getOperand(OpNo);405 if (MO.isReg()) return getMachineOpValue(MI, MO, Fixups, STI);406 407 // Add a fixup for the TLS register, which simply provides a relocation408 // hint to the linker that this statement is part of a relocation sequence.409 // Return the thread-pointer register's encoding. Add a one byte displacement410 // if using PC relative memops.411 const MCExpr *Expr = MO.getExpr();412 const MCSymbolRefExpr *SRE = cast<MCSymbolRefExpr>(Expr);413 bool IsPCRel = getSpecifier(SRE) == PPC::S_TLS_PCREL;414 addFixup(Fixups, IsPCRel ? 1 : 0, Expr, PPC::fixup_ppc_nofixup);415 const Triple &TT = STI.getTargetTriple();416 bool isPPC64 = TT.isPPC64();417 return CTX.getRegisterInfo()->getEncodingValue(isPPC64 ? PPC::X13 : PPC::R2);418}419 420unsigned PPCMCCodeEmitter::getTLSCallEncoding(const MCInst &MI, unsigned OpNo,421 SmallVectorImpl<MCFixup> &Fixups,422 const MCSubtargetInfo &STI) const {423 // For special TLS calls, we need two fixups; one for the branch target424 // (__tls_get_addr), which we create via getDirectBrEncoding as usual,425 // and one for the TLSGD or TLSLD symbol, which is emitted here.426 const MCOperand &MO = MI.getOperand(OpNo+1);427 addFixup(Fixups, 0, MO.getExpr(), PPC::fixup_ppc_nofixup);428 return getDirectBrEncoding(MI, OpNo, Fixups, STI);429}430 431unsigned PPCMCCodeEmitter::432get_crbitm_encoding(const MCInst &MI, unsigned OpNo,433 SmallVectorImpl<MCFixup> &Fixups,434 const MCSubtargetInfo &STI) const {435 const MCOperand &MO = MI.getOperand(OpNo);436 assert((MI.getOpcode() == PPC::MTOCRF || MI.getOpcode() == PPC::MTOCRF8 ||437 MI.getOpcode() == PPC::MFOCRF || MI.getOpcode() == PPC::MFOCRF8) &&438 (MO.getReg() >= PPC::CR0 && MO.getReg() <= PPC::CR7));439 return 0x80 >> CTX.getRegisterInfo()->getEncodingValue(MO.getReg());440}441 442// Get the index for this operand in this instruction. This is needed for443// computing the register number in PPC::getRegNumForOperand() for444// any instructions that use a different numbering scheme for registers in445// different operands.446static unsigned getOpIdxForMO(const MCInst &MI, const MCOperand &MO) {447 for (unsigned i = 0; i < MI.getNumOperands(); i++) {448 const MCOperand &Op = MI.getOperand(i);449 if (&Op == &MO)450 return i;451 }452 llvm_unreachable("This operand is not part of this instruction");453 return ~0U; // Silence any warnings about no return.454}455 456uint64_t PPCMCCodeEmitter::457getMachineOpValue(const MCInst &MI, const MCOperand &MO,458 SmallVectorImpl<MCFixup> &Fixups,459 const MCSubtargetInfo &STI) const {460 if (MO.isReg()) {461 // MTOCRF/MFOCRF should go through get_crbitm_encoding for the CR operand.462 // The GPR operand should come through here though.463 assert((MI.getOpcode() != PPC::MTOCRF && MI.getOpcode() != PPC::MTOCRF8 &&464 MI.getOpcode() != PPC::MFOCRF && MI.getOpcode() != PPC::MFOCRF8) ||465 MO.getReg() < PPC::CR0 || MO.getReg() > PPC::CR7);466 unsigned OpNo = getOpIdxForMO(MI, MO);467 MCRegister Reg =468 PPC::getRegNumForOperand(MCII.get(MI.getOpcode()), MO.getReg(), OpNo);469 return CTX.getRegisterInfo()->getEncodingValue(Reg);470 }471 472 assert(MO.isImm() &&473 "Relocation required in an instruction that we cannot encode!");474 return MO.getImm();475}476 477void PPCMCCodeEmitter::encodeInstruction(const MCInst &MI,478 SmallVectorImpl<char> &CB,479 SmallVectorImpl<MCFixup> &Fixups,480 const MCSubtargetInfo &STI) const {481 uint64_t Bits = getBinaryCodeForInstr(MI, Fixups, STI);482 483 // Output the constant in big/little endian byte order.484 unsigned Size = getInstSizeInBytes(MI);485 llvm::endianness E =486 IsLittleEndian ? llvm::endianness::little : llvm::endianness::big;487 switch (Size) {488 case 0:489 break;490 case 4:491 support::endian::write<uint32_t>(CB, Bits, E);492 break;493 case 8:494 // If we emit a pair of instructions, the first one is495 // always in the top 32 bits, even on little-endian.496 support::endian::write<uint32_t>(CB, Bits >> 32, E);497 support::endian::write<uint32_t>(CB, Bits, E);498 break;499 default:500 llvm_unreachable("Invalid instruction size");501 }502 503 ++MCNumEmitted; // Keep track of the # of mi's emitted.504}505 506// Get the number of bytes used to encode the given MCInst.507unsigned PPCMCCodeEmitter::getInstSizeInBytes(const MCInst &MI) const {508 unsigned Opcode = MI.getOpcode();509 const MCInstrDesc &Desc = MCII.get(Opcode);510 return Desc.getSize();511}512 513bool PPCMCCodeEmitter::isPrefixedInstruction(const MCInst &MI) const {514 return MCII.get(MI.getOpcode()).TSFlags & PPCII::Prefixed;515}516 517#include "PPCGenMCCodeEmitter.inc"518