1249259Sdim//===-- AArch64MCExpr.cpp - AArch64 specific MC expression classes --------===//
2249259Sdim//
3249259Sdim//                     The LLVM Compiler Infrastructure
4249259Sdim//
5249259Sdim// This file is distributed under the University of Illinois Open Source
6249259Sdim// License. See LICENSE.TXT for details.
7249259Sdim//
8249259Sdim//===----------------------------------------------------------------------===//
9249259Sdim//
10249259Sdim// This file contains the implementation of the assembly expression modifiers
11249259Sdim// accepted by the AArch64 architecture (e.g. ":lo12:", ":gottprel_g1:", ...).
12249259Sdim//
13249259Sdim//===----------------------------------------------------------------------===//
14249259Sdim
15249259Sdim#define DEBUG_TYPE "aarch64mcexpr"
16249259Sdim#include "AArch64MCExpr.h"
17249259Sdim#include "llvm/MC/MCContext.h"
18249259Sdim#include "llvm/MC/MCAssembler.h"
19249259Sdim#include "llvm/MC/MCELF.h"
20249259Sdim#include "llvm/Object/ELF.h"
21249259Sdim
22249259Sdimusing namespace llvm;
23249259Sdim
24249259Sdimconst AArch64MCExpr*
25249259SdimAArch64MCExpr::Create(VariantKind Kind, const MCExpr *Expr,
26249259Sdim                      MCContext &Ctx) {
27249259Sdim  return new (Ctx) AArch64MCExpr(Kind, Expr);
28249259Sdim}
29249259Sdim
30249259Sdimvoid AArch64MCExpr::PrintImpl(raw_ostream &OS) const {
31249259Sdim  switch (Kind) {
32249259Sdim  default: llvm_unreachable("Invalid kind!");
33249259Sdim  case VK_AARCH64_GOT:              OS << ":got:"; break;
34249259Sdim  case VK_AARCH64_GOT_LO12:         OS << ":got_lo12:"; break;
35249259Sdim  case VK_AARCH64_LO12:             OS << ":lo12:"; break;
36249259Sdim  case VK_AARCH64_ABS_G0:           OS << ":abs_g0:"; break;
37249259Sdim  case VK_AARCH64_ABS_G0_NC:        OS << ":abs_g0_nc:"; break;
38249259Sdim  case VK_AARCH64_ABS_G1:           OS << ":abs_g1:"; break;
39249259Sdim  case VK_AARCH64_ABS_G1_NC:        OS << ":abs_g1_nc:"; break;
40249259Sdim  case VK_AARCH64_ABS_G2:           OS << ":abs_g2:"; break;
41249259Sdim  case VK_AARCH64_ABS_G2_NC:        OS << ":abs_g2_nc:"; break;
42249259Sdim  case VK_AARCH64_ABS_G3:           OS << ":abs_g3:"; break;
43249259Sdim  case VK_AARCH64_SABS_G0:          OS << ":abs_g0_s:"; break;
44249259Sdim  case VK_AARCH64_SABS_G1:          OS << ":abs_g1_s:"; break;
45249259Sdim  case VK_AARCH64_SABS_G2:          OS << ":abs_g2_s:"; break;
46249259Sdim  case VK_AARCH64_DTPREL_G2:        OS << ":dtprel_g2:"; break;
47249259Sdim  case VK_AARCH64_DTPREL_G1:        OS << ":dtprel_g1:"; break;
48249259Sdim  case VK_AARCH64_DTPREL_G1_NC:     OS << ":dtprel_g1_nc:"; break;
49249259Sdim  case VK_AARCH64_DTPREL_G0:        OS << ":dtprel_g0:"; break;
50249259Sdim  case VK_AARCH64_DTPREL_G0_NC:     OS << ":dtprel_g0_nc:"; break;
51249259Sdim  case VK_AARCH64_DTPREL_HI12:      OS << ":dtprel_hi12:"; break;
52249259Sdim  case VK_AARCH64_DTPREL_LO12:      OS << ":dtprel_lo12:"; break;
53249259Sdim  case VK_AARCH64_DTPREL_LO12_NC:   OS << ":dtprel_lo12_nc:"; break;
54249259Sdim  case VK_AARCH64_GOTTPREL_G1:      OS << ":gottprel_g1:"; break;
55249259Sdim  case VK_AARCH64_GOTTPREL_G0_NC:   OS << ":gottprel_g0_nc:"; break;
56249259Sdim  case VK_AARCH64_GOTTPREL:         OS << ":gottprel:"; break;
57249259Sdim  case VK_AARCH64_GOTTPREL_LO12:    OS << ":gottprel_lo12:"; break;
58249259Sdim  case VK_AARCH64_TPREL_G2:         OS << ":tprel_g2:"; break;
59249259Sdim  case VK_AARCH64_TPREL_G1:         OS << ":tprel_g1:"; break;
60249259Sdim  case VK_AARCH64_TPREL_G1_NC:      OS << ":tprel_g1_nc:"; break;
61249259Sdim  case VK_AARCH64_TPREL_G0:         OS << ":tprel_g0:"; break;
62249259Sdim  case VK_AARCH64_TPREL_G0_NC:      OS << ":tprel_g0_nc:"; break;
63249259Sdim  case VK_AARCH64_TPREL_HI12:       OS << ":tprel_hi12:"; break;
64249259Sdim  case VK_AARCH64_TPREL_LO12:       OS << ":tprel_lo12:"; break;
65249259Sdim  case VK_AARCH64_TPREL_LO12_NC:    OS << ":tprel_lo12_nc:"; break;
66249259Sdim  case VK_AARCH64_TLSDESC:          OS << ":tlsdesc:"; break;
67249259Sdim  case VK_AARCH64_TLSDESC_LO12:     OS << ":tlsdesc_lo12:"; break;
68249259Sdim
69249259Sdim  }
70249259Sdim
71249259Sdim  const MCExpr *Expr = getSubExpr();
72249259Sdim  if (Expr->getKind() != MCExpr::SymbolRef)
73249259Sdim    OS << '(';
74249259Sdim  Expr->print(OS);
75249259Sdim  if (Expr->getKind() != MCExpr::SymbolRef)
76249259Sdim    OS << ')';
77249259Sdim}
78249259Sdim
79249259Sdimbool
80249259SdimAArch64MCExpr::EvaluateAsRelocatableImpl(MCValue &Res,
81249259Sdim                                         const MCAsmLayout *Layout) const {
82249259Sdim  return getSubExpr()->EvaluateAsRelocatable(Res, *Layout);
83249259Sdim}
84249259Sdim
85249259Sdimstatic void fixELFSymbolsInTLSFixupsImpl(const MCExpr *Expr, MCAssembler &Asm) {
86249259Sdim  switch (Expr->getKind()) {
87249259Sdim  case MCExpr::Target:
88249259Sdim    llvm_unreachable("Can't handle nested target expression");
89249259Sdim    break;
90249259Sdim  case MCExpr::Constant:
91249259Sdim    break;
92249259Sdim
93249259Sdim  case MCExpr::Binary: {
94249259Sdim    const MCBinaryExpr *BE = cast<MCBinaryExpr>(Expr);
95249259Sdim    fixELFSymbolsInTLSFixupsImpl(BE->getLHS(), Asm);
96249259Sdim    fixELFSymbolsInTLSFixupsImpl(BE->getRHS(), Asm);
97249259Sdim    break;
98249259Sdim  }
99249259Sdim
100249259Sdim  case MCExpr::SymbolRef: {
101249259Sdim    // We're known to be under a TLS fixup, so any symbol should be
102249259Sdim    // modified. There should be only one.
103249259Sdim    const MCSymbolRefExpr &SymRef = *cast<MCSymbolRefExpr>(Expr);
104249259Sdim    MCSymbolData &SD = Asm.getOrCreateSymbolData(SymRef.getSymbol());
105249259Sdim    MCELF::SetType(SD, ELF::STT_TLS);
106249259Sdim    break;
107249259Sdim  }
108249259Sdim
109249259Sdim  case MCExpr::Unary:
110249259Sdim    fixELFSymbolsInTLSFixupsImpl(cast<MCUnaryExpr>(Expr)->getSubExpr(), Asm);
111249259Sdim    break;
112249259Sdim  }
113249259Sdim}
114249259Sdim
115249259Sdimvoid AArch64MCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const {
116249259Sdim  switch (getKind()) {
117249259Sdim  default:
118249259Sdim    return;
119249259Sdim  case VK_AARCH64_DTPREL_G2:
120249259Sdim  case VK_AARCH64_DTPREL_G1:
121249259Sdim  case VK_AARCH64_DTPREL_G1_NC:
122249259Sdim  case VK_AARCH64_DTPREL_G0:
123249259Sdim  case VK_AARCH64_DTPREL_G0_NC:
124249259Sdim  case VK_AARCH64_DTPREL_HI12:
125249259Sdim  case VK_AARCH64_DTPREL_LO12:
126249259Sdim  case VK_AARCH64_DTPREL_LO12_NC:
127249259Sdim  case VK_AARCH64_GOTTPREL_G1:
128249259Sdim  case VK_AARCH64_GOTTPREL_G0_NC:
129249259Sdim  case VK_AARCH64_GOTTPREL:
130249259Sdim  case VK_AARCH64_GOTTPREL_LO12:
131249259Sdim  case VK_AARCH64_TPREL_G2:
132249259Sdim  case VK_AARCH64_TPREL_G1:
133249259Sdim  case VK_AARCH64_TPREL_G1_NC:
134249259Sdim  case VK_AARCH64_TPREL_G0:
135249259Sdim  case VK_AARCH64_TPREL_G0_NC:
136249259Sdim  case VK_AARCH64_TPREL_HI12:
137249259Sdim  case VK_AARCH64_TPREL_LO12:
138249259Sdim  case VK_AARCH64_TPREL_LO12_NC:
139249259Sdim  case VK_AARCH64_TLSDESC:
140249259Sdim  case VK_AARCH64_TLSDESC_LO12:
141249259Sdim    break;
142249259Sdim  }
143249259Sdim
144249259Sdim  fixELFSymbolsInTLSFixupsImpl(getSubExpr(), Asm);
145249259Sdim}
146249259Sdim
147249259Sdim// FIXME: This basically copies MCObjectStreamer::AddValueSymbols. Perhaps
148249259Sdim// that method should be made public?
149249259Sdim// FIXME: really do above: now that two backends are using it.
150249259Sdimstatic void AddValueSymbolsImpl(const MCExpr *Value, MCAssembler *Asm) {
151249259Sdim  switch (Value->getKind()) {
152249259Sdim  case MCExpr::Target:
153249259Sdim    llvm_unreachable("Can't handle nested target expr!");
154249259Sdim    break;
155249259Sdim
156249259Sdim  case MCExpr::Constant:
157249259Sdim    break;
158249259Sdim
159249259Sdim  case MCExpr::Binary: {
160249259Sdim    const MCBinaryExpr *BE = cast<MCBinaryExpr>(Value);
161249259Sdim    AddValueSymbolsImpl(BE->getLHS(), Asm);
162249259Sdim    AddValueSymbolsImpl(BE->getRHS(), Asm);
163249259Sdim    break;
164249259Sdim  }
165249259Sdim
166249259Sdim  case MCExpr::SymbolRef:
167249259Sdim    Asm->getOrCreateSymbolData(cast<MCSymbolRefExpr>(Value)->getSymbol());
168249259Sdim    break;
169249259Sdim
170249259Sdim  case MCExpr::Unary:
171249259Sdim    AddValueSymbolsImpl(cast<MCUnaryExpr>(Value)->getSubExpr(), Asm);
172249259Sdim    break;
173249259Sdim  }
174249259Sdim}
175249259Sdim
176249259Sdimvoid AArch64MCExpr::AddValueSymbols(MCAssembler *Asm) const {
177249259Sdim  AddValueSymbolsImpl(getSubExpr(), Asm);
178249259Sdim}
179