1//===-- CSKYMCExpr.cpp - CSKY specific MC expression classes -*- C++ -*----===//
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#include "CSKYMCExpr.h"
10#include "CSKYFixupKinds.h"
11#include "llvm/BinaryFormat/ELF.h"
12#include "llvm/MC/MCAssembler.h"
13#include "llvm/MC/MCContext.h"
14#include "llvm/MC/MCStreamer.h"
15#include "llvm/MC/MCSymbolELF.h"
16#include "llvm/Support/Casting.h"
17
18using namespace llvm;
19
20#define DEBUG_TYPE "csky-mc-expr"
21
22const CSKYMCExpr *CSKYMCExpr::create(const MCExpr *Expr, VariantKind Kind,
23                                     MCContext &Ctx) {
24  return new (Ctx) CSKYMCExpr(Kind, Expr);
25}
26
27StringRef CSKYMCExpr::getVariantKindName(VariantKind Kind) {
28  switch (Kind) {
29  default:
30    llvm_unreachable("Invalid ELF symbol kind");
31  case VK_CSKY_None:
32  case VK_CSKY_ADDR:
33    return "";
34  case VK_CSKY_ADDR_HI16:
35    return "@HI16";
36  case VK_CSKY_ADDR_LO16:
37    return "@LO16";
38  case VK_CSKY_GOT_IMM18_BY4:
39  case VK_CSKY_GOT:
40    return "@GOT";
41  case VK_CSKY_GOTPC:
42    return "@GOTPC";
43  case VK_CSKY_GOTOFF:
44    return "@GOTOFF";
45  case VK_CSKY_PLT_IMM18_BY4:
46  case VK_CSKY_PLT:
47    return "@PLT";
48  case VK_CSKY_TLSLE:
49    return "@TPOFF";
50  case VK_CSKY_TLSIE:
51    return "@GOTTPOFF";
52  case VK_CSKY_TLSGD:
53    return "@TLSGD32";
54  case VK_CSKY_TLSLDO:
55    return "@TLSLDO32";
56  case VK_CSKY_TLSLDM:
57    return "@TLSLDM32";
58  }
59}
60
61void CSKYMCExpr::visitUsedExpr(MCStreamer &Streamer) const {
62  Streamer.visitUsedExpr(*getSubExpr());
63}
64
65void CSKYMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
66  Expr->print(OS, MAI);
67  OS << getVariantKindName(getKind());
68}
69
70static void fixELFSymbolsInTLSFixupsImpl(const MCExpr *Expr, MCAssembler &Asm) {
71  switch (Expr->getKind()) {
72  case MCExpr::Target:
73    llvm_unreachable("Can't handle nested target expression");
74    break;
75  case MCExpr::Constant:
76    break;
77
78  case MCExpr::Binary: {
79    const MCBinaryExpr *BE = cast<MCBinaryExpr>(Expr);
80    fixELFSymbolsInTLSFixupsImpl(BE->getLHS(), Asm);
81    fixELFSymbolsInTLSFixupsImpl(BE->getRHS(), Asm);
82    break;
83  }
84
85  case MCExpr::SymbolRef: {
86    // We're known to be under a TLS fixup, so any symbol should be
87    // modified. There should be only one.
88    const MCSymbolRefExpr &SymRef = *cast<MCSymbolRefExpr>(Expr);
89    cast<MCSymbolELF>(SymRef.getSymbol()).setType(ELF::STT_TLS);
90    break;
91  }
92
93  case MCExpr::Unary:
94    fixELFSymbolsInTLSFixupsImpl(cast<MCUnaryExpr>(Expr)->getSubExpr(), Asm);
95    break;
96  }
97}
98
99void CSKYMCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const {
100  switch (getKind()) {
101  default:
102    return;
103  case VK_CSKY_TLSLE:
104  case VK_CSKY_TLSIE:
105  case VK_CSKY_TLSGD:
106    break;
107  }
108
109  fixELFSymbolsInTLSFixupsImpl(getSubExpr(), Asm);
110}
111
112bool CSKYMCExpr::evaluateAsRelocatableImpl(MCValue &Res,
113                                           const MCAsmLayout *Layout,
114                                           const MCFixup *Fixup) const {
115  if (!getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup))
116    return false;
117
118  // Some custom fixup types are not valid with symbol difference expressions
119  if (Res.getSymA() && Res.getSymB()) {
120    switch (getKind()) {
121    default:
122      return true;
123    case VK_CSKY_GOT:
124    case VK_CSKY_GOT_IMM18_BY4:
125    case VK_CSKY_GOTPC:
126    case VK_CSKY_GOTOFF:
127    case VK_CSKY_PLT:
128    case VK_CSKY_PLT_IMM18_BY4:
129    case VK_CSKY_TLSIE:
130    case VK_CSKY_TLSLE:
131    case VK_CSKY_TLSGD:
132    case VK_CSKY_TLSLDO:
133    case VK_CSKY_TLSLDM:
134      return false;
135    }
136  }
137
138  return true;
139}
140