Path: blob/main/contrib/llvm-project/llvm/lib/Target/Mips/MCTargetDesc/MipsMCExpr.cpp
35294 views
//===-- MipsMCExpr.cpp - Mips specific MC expression classes --------------===//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//===----------------------------------------------------------------------===//78#include "MipsMCExpr.h"9#include "llvm/BinaryFormat/ELF.h"10#include "llvm/MC/MCAsmInfo.h"11#include "llvm/MC/MCAssembler.h"12#include "llvm/MC/MCContext.h"13#include "llvm/MC/MCStreamer.h"14#include "llvm/MC/MCSymbolELF.h"15#include "llvm/MC/MCValue.h"16#include "llvm/Support/Casting.h"17#include "llvm/Support/ErrorHandling.h"18#include "llvm/Support/MathExtras.h"19#include "llvm/Support/raw_ostream.h"20#include <cstdint>2122using namespace llvm;2324#define DEBUG_TYPE "mipsmcexpr"2526const MipsMCExpr *MipsMCExpr::create(MipsMCExpr::MipsExprKind Kind,27const MCExpr *Expr, MCContext &Ctx) {28return new (Ctx) MipsMCExpr(Kind, Expr);29}3031const MipsMCExpr *MipsMCExpr::createGpOff(MipsMCExpr::MipsExprKind Kind,32const MCExpr *Expr, MCContext &Ctx) {33return create(Kind, create(MEK_NEG, create(MEK_GPREL, Expr, Ctx), Ctx), Ctx);34}3536void MipsMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {37int64_t AbsVal;3839switch (Kind) {40case MEK_None:41case MEK_Special:42llvm_unreachable("MEK_None and MEK_Special are invalid");43break;44case MEK_DTPREL:45// MEK_DTPREL is used for marking TLS DIEExpr only46// and contains a regular sub-expression.47getSubExpr()->print(OS, MAI, true);48return;49case MEK_CALL_HI16:50OS << "%call_hi";51break;52case MEK_CALL_LO16:53OS << "%call_lo";54break;55case MEK_DTPREL_HI:56OS << "%dtprel_hi";57break;58case MEK_DTPREL_LO:59OS << "%dtprel_lo";60break;61case MEK_GOT:62OS << "%got";63break;64case MEK_GOTTPREL:65OS << "%gottprel";66break;67case MEK_GOT_CALL:68OS << "%call16";69break;70case MEK_GOT_DISP:71OS << "%got_disp";72break;73case MEK_GOT_HI16:74OS << "%got_hi";75break;76case MEK_GOT_LO16:77OS << "%got_lo";78break;79case MEK_GOT_PAGE:80OS << "%got_page";81break;82case MEK_GOT_OFST:83OS << "%got_ofst";84break;85case MEK_GPREL:86OS << "%gp_rel";87break;88case MEK_HI:89OS << "%hi";90break;91case MEK_HIGHER:92OS << "%higher";93break;94case MEK_HIGHEST:95OS << "%highest";96break;97case MEK_LO:98OS << "%lo";99break;100case MEK_NEG:101OS << "%neg";102break;103case MEK_PCREL_HI16:104OS << "%pcrel_hi";105break;106case MEK_PCREL_LO16:107OS << "%pcrel_lo";108break;109case MEK_TLSGD:110OS << "%tlsgd";111break;112case MEK_TLSLDM:113OS << "%tlsldm";114break;115case MEK_TPREL_HI:116OS << "%tprel_hi";117break;118case MEK_TPREL_LO:119OS << "%tprel_lo";120break;121}122123OS << '(';124if (Expr->evaluateAsAbsolute(AbsVal))125OS << AbsVal;126else127Expr->print(OS, MAI, true);128OS << ')';129}130131bool MipsMCExpr::evaluateAsRelocatableImpl(MCValue &Res, const MCAssembler *Asm,132const MCFixup *Fixup) const {133// Look for the %hi(%neg(%gp_rel(X))) and %lo(%neg(%gp_rel(X))) special cases.134if (isGpOff()) {135const MCExpr *SubExpr =136cast<MipsMCExpr>(cast<MipsMCExpr>(getSubExpr())->getSubExpr())137->getSubExpr();138if (!SubExpr->evaluateAsRelocatable(Res, Asm, Fixup))139return false;140141Res = MCValue::get(Res.getSymA(), Res.getSymB(), Res.getConstant(),142MEK_Special);143return true;144}145146if (!getSubExpr()->evaluateAsRelocatable(Res, Asm, Fixup))147return false;148149if (Res.getRefKind() != MCSymbolRefExpr::VK_None)150return false;151152// evaluateAsAbsolute() and evaluateAsValue() require that we evaluate the153// %hi/%lo/etc. here. Fixup is a null pointer when either of these is the154// caller.155if (Res.isAbsolute() && Fixup == nullptr) {156int64_t AbsVal = Res.getConstant();157switch (Kind) {158case MEK_None:159case MEK_Special:160llvm_unreachable("MEK_None and MEK_Special are invalid");161case MEK_DTPREL:162// MEK_DTPREL is used for marking TLS DIEExpr only163// and contains a regular sub-expression.164return getSubExpr()->evaluateAsRelocatable(Res, Asm, Fixup);165case MEK_DTPREL_HI:166case MEK_DTPREL_LO:167case MEK_GOT:168case MEK_GOTTPREL:169case MEK_GOT_CALL:170case MEK_GOT_DISP:171case MEK_GOT_HI16:172case MEK_GOT_LO16:173case MEK_GOT_OFST:174case MEK_GOT_PAGE:175case MEK_GPREL:176case MEK_PCREL_HI16:177case MEK_PCREL_LO16:178case MEK_TLSGD:179case MEK_TLSLDM:180case MEK_TPREL_HI:181case MEK_TPREL_LO:182return false;183case MEK_LO:184case MEK_CALL_LO16:185AbsVal = SignExtend64<16>(AbsVal);186break;187case MEK_CALL_HI16:188case MEK_HI:189AbsVal = SignExtend64<16>((AbsVal + 0x8000) >> 16);190break;191case MEK_HIGHER:192AbsVal = SignExtend64<16>((AbsVal + 0x80008000LL) >> 32);193break;194case MEK_HIGHEST:195AbsVal = SignExtend64<16>((AbsVal + 0x800080008000LL) >> 48);196break;197case MEK_NEG:198AbsVal = -AbsVal;199break;200}201Res = MCValue::get(AbsVal);202return true;203}204205// We want to defer it for relocatable expressions since the constant is206// applied to the whole symbol value.207//208// The value of getKind() that is given to MCValue is only intended to aid209// debugging when inspecting MCValue objects. It shouldn't be relied upon210// for decision making.211Res =212MCValue::get(Res.getSymA(), Res.getSymB(), Res.getConstant(), getKind());213214return true;215}216217void MipsMCExpr::visitUsedExpr(MCStreamer &Streamer) const {218Streamer.visitUsedExpr(*getSubExpr());219}220221static void fixELFSymbolsInTLSFixupsImpl(const MCExpr *Expr, MCAssembler &Asm) {222switch (Expr->getKind()) {223case MCExpr::Target:224fixELFSymbolsInTLSFixupsImpl(cast<MipsMCExpr>(Expr)->getSubExpr(), Asm);225break;226case MCExpr::Constant:227break;228case MCExpr::Binary: {229const MCBinaryExpr *BE = cast<MCBinaryExpr>(Expr);230fixELFSymbolsInTLSFixupsImpl(BE->getLHS(), Asm);231fixELFSymbolsInTLSFixupsImpl(BE->getRHS(), Asm);232break;233}234case MCExpr::SymbolRef: {235// We're known to be under a TLS fixup, so any symbol should be236// modified. There should be only one.237const MCSymbolRefExpr &SymRef = *cast<MCSymbolRefExpr>(Expr);238cast<MCSymbolELF>(SymRef.getSymbol()).setType(ELF::STT_TLS);239break;240}241case MCExpr::Unary:242fixELFSymbolsInTLSFixupsImpl(cast<MCUnaryExpr>(Expr)->getSubExpr(), Asm);243break;244}245}246247void MipsMCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const {248switch (getKind()) {249case MEK_None:250case MEK_Special:251llvm_unreachable("MEK_None and MEK_Special are invalid");252break;253case MEK_CALL_HI16:254case MEK_CALL_LO16:255case MEK_GOT:256case MEK_GOT_CALL:257case MEK_GOT_DISP:258case MEK_GOT_HI16:259case MEK_GOT_LO16:260case MEK_GOT_OFST:261case MEK_GOT_PAGE:262case MEK_GPREL:263case MEK_HI:264case MEK_HIGHER:265case MEK_HIGHEST:266case MEK_LO:267case MEK_NEG:268case MEK_PCREL_HI16:269case MEK_PCREL_LO16:270// If we do have nested target-specific expressions, they will be in271// a consecutive chain.272if (const MipsMCExpr *E = dyn_cast<const MipsMCExpr>(getSubExpr()))273E->fixELFSymbolsInTLSFixups(Asm);274break;275case MEK_DTPREL:276case MEK_DTPREL_HI:277case MEK_DTPREL_LO:278case MEK_TLSLDM:279case MEK_TLSGD:280case MEK_GOTTPREL:281case MEK_TPREL_HI:282case MEK_TPREL_LO:283fixELFSymbolsInTLSFixupsImpl(getSubExpr(), Asm);284break;285}286}287288bool MipsMCExpr::isGpOff(MipsExprKind &Kind) const {289if (getKind() == MEK_HI || getKind() == MEK_LO) {290if (const MipsMCExpr *S1 = dyn_cast<const MipsMCExpr>(getSubExpr())) {291if (const MipsMCExpr *S2 = dyn_cast<const MipsMCExpr>(S1->getSubExpr())) {292if (S1->getKind() == MEK_NEG && S2->getKind() == MEK_GPREL) {293Kind = getKind();294return true;295}296}297}298}299return false;300}301302303