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