1dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines//===- AArch64ExternalSymbolizer.cpp - Symbolizer for AArch64 ---*- C++ -*-===//
2dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines//
3dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines//                     The LLVM Compiler Infrastructure
4dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines//
5dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines// This file is distributed under the University of Illinois Open Source
6dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines// License. See LICENSE.TXT for details.
7dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines//
8dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines//===----------------------------------------------------------------------===//
9dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines
10dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines#include "AArch64ExternalSymbolizer.h"
11dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines#include "AArch64Subtarget.h"
12dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines#include "MCTargetDesc/AArch64AddressingModes.h"
13dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines#include "Utils/AArch64BaseInfo.h"
14dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines#include "llvm/MC/MCContext.h"
15dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines#include "llvm/MC/MCExpr.h"
16dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines#include "llvm/MC/MCInst.h"
17dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines#include "llvm/Support/Format.h"
18dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines#include "llvm/Support/raw_ostream.h"
19dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines
20dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hinesusing namespace llvm;
21dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines
22dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines#define DEBUG_TYPE "aarch64-disassembler"
23dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines
24dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hinesstatic MCSymbolRefExpr::VariantKind
25dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen HinesgetVariant(uint64_t LLVMDisassembler_VariantKind) {
26dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  switch (LLVMDisassembler_VariantKind) {
27dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  case LLVMDisassembler_VariantKind_None:
28dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    return MCSymbolRefExpr::VK_None;
29dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  case LLVMDisassembler_VariantKind_ARM64_PAGE:
30dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    return MCSymbolRefExpr::VK_PAGE;
31dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  case LLVMDisassembler_VariantKind_ARM64_PAGEOFF:
32dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    return MCSymbolRefExpr::VK_PAGEOFF;
33dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  case LLVMDisassembler_VariantKind_ARM64_GOTPAGE:
34dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    return MCSymbolRefExpr::VK_GOTPAGE;
35dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  case LLVMDisassembler_VariantKind_ARM64_GOTPAGEOFF:
36dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    return MCSymbolRefExpr::VK_GOTPAGEOFF;
37dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  case LLVMDisassembler_VariantKind_ARM64_TLVP:
38dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  case LLVMDisassembler_VariantKind_ARM64_TLVOFF:
39dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  default:
40cd81d94322a39503e4a3e87b6ee03d4fcb3465fbStephen Hines    llvm_unreachable("bad LLVMDisassembler_VariantKind");
41dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  }
42dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines}
43dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines
44dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines/// tryAddingSymbolicOperand - tryAddingSymbolicOperand trys to add a symbolic
45dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines/// operand in place of the immediate Value in the MCInst.  The immediate
46dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines/// Value has not had any PC adjustment made by the caller. If the instruction
47dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines/// is a branch that adds the PC to the immediate Value then isBranch is
48dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines/// Success, else Fail. If GetOpInfo is non-null, then it is called to get any
49dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines/// symbolic information at the Address for this instrution.  If that returns
50dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines/// non-zero then the symbolic information it returns is used to create an
51dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines/// MCExpr and that is added as an operand to the MCInst.  If GetOpInfo()
52dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines/// returns zero and isBranch is Success then a symbol look up for
53dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines/// Address + Value is done and if a symbol is found an MCExpr is created with
54dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines/// that, else an MCExpr with Address + Value is created.  If GetOpInfo()
55dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines/// returns zero and isBranch is Fail then the the Opcode of the MCInst is
56dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines/// tested and for ADRP an other instructions that help to load of pointers
57dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines/// a symbol look up is done to see it is returns a specific reference type
58dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines/// to add to the comment stream.  This function returns Success if it adds
59dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines/// an operand to the MCInst and Fail otherwise.
60dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hinesbool AArch64ExternalSymbolizer::tryAddingSymbolicOperand(
61dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    MCInst &MI, raw_ostream &CommentStream, int64_t Value, uint64_t Address,
62dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    bool IsBranch, uint64_t Offset, uint64_t InstSize) {
63dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  // FIXME: This method shares a lot of code with
64dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  //        MCExternalSymbolizer::tryAddingSymbolicOperand. It may be possible
65dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  //        refactor the MCExternalSymbolizer interface to allow more of this
66dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  //        implementation to be shared.
67dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  //
68dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  struct LLVMOpInfo1 SymbolicOp;
69dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  memset(&SymbolicOp, '\0', sizeof(struct LLVMOpInfo1));
70dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  SymbolicOp.Value = Value;
71dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  uint64_t ReferenceType;
72dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  const char *ReferenceName;
73dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  if (!GetOpInfo ||
74dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      !GetOpInfo(DisInfo, Address, 0 /* Offset */, InstSize, 1, &SymbolicOp)) {
75dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    if (IsBranch) {
76dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      ReferenceType = LLVMDisassembler_ReferenceType_In_Branch;
77dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      const char *Name = SymbolLookUp(DisInfo, Address + Value, &ReferenceType,
78dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines                                      Address, &ReferenceName);
79dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      if (Name) {
80dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        SymbolicOp.AddSymbol.Name = Name;
81dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        SymbolicOp.AddSymbol.Present = true;
82dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        SymbolicOp.Value = 0;
83dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      } else {
84dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        SymbolicOp.Value = Address + Value;
85dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      }
86dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      if (ReferenceType == LLVMDisassembler_ReferenceType_Out_SymbolStub)
87dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        CommentStream << "symbol stub for: " << ReferenceName;
88dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      else if (ReferenceType ==
89dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines               LLVMDisassembler_ReferenceType_Out_Objc_Message)
90dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        CommentStream << "Objc message: " << ReferenceName;
91dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    } else if (MI.getOpcode() == AArch64::ADRP) {
92dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        ReferenceType = LLVMDisassembler_ReferenceType_In_ARM64_ADRP;
93dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        // otool expects the fully encoded ADRP instruction to be passed in as
94dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        // the value here, so reconstruct it:
95dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        const MCRegisterInfo &MCRI = *Ctx.getRegisterInfo();
96dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        uint32_t EncodedInst = 0x90000000;
97dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        EncodedInst |= (Value & 0x3) << 29; // immlo
98dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        EncodedInst |= ((Value >> 2) & 0x7FFFF) << 5; // immhi
99dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        EncodedInst |= MCRI.getEncodingValue(MI.getOperand(0).getReg()); // reg
100dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        SymbolLookUp(DisInfo, EncodedInst, &ReferenceType, Address,
101dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines                     &ReferenceName);
102dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        CommentStream << format("0x%llx",
103dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines                                0xfffffffffffff000LL & (Address + Value));
104dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    } else if (MI.getOpcode() == AArch64::ADDXri ||
105dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines               MI.getOpcode() == AArch64::LDRXui ||
106dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines               MI.getOpcode() == AArch64::LDRXl ||
107dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines               MI.getOpcode() == AArch64::ADR) {
108dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      if (MI.getOpcode() == AArch64::ADDXri)
109dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        ReferenceType = LLVMDisassembler_ReferenceType_In_ARM64_ADDXri;
110dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      else if (MI.getOpcode() == AArch64::LDRXui)
111dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        ReferenceType = LLVMDisassembler_ReferenceType_In_ARM64_LDRXui;
112dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      if (MI.getOpcode() == AArch64::LDRXl) {
113dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        ReferenceType = LLVMDisassembler_ReferenceType_In_ARM64_LDRXl;
114dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        SymbolLookUp(DisInfo, Address + Value, &ReferenceType, Address,
115dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines                     &ReferenceName);
116dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      } else if (MI.getOpcode() == AArch64::ADR) {
117dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        ReferenceType = LLVMDisassembler_ReferenceType_In_ARM64_ADR;
118dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        SymbolLookUp(DisInfo, Address + Value, &ReferenceType, Address,
119dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines                            &ReferenceName);
120dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      } else {
121dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        const MCRegisterInfo &MCRI = *Ctx.getRegisterInfo();
122dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        // otool expects the fully encoded ADD/LDR instruction to be passed in
123dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        // as the value here, so reconstruct it:
124dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        unsigned EncodedInst =
125dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines          MI.getOpcode() == AArch64::ADDXri ? 0x91000000: 0xF9400000;
126dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        EncodedInst |= Value << 10; // imm12 [+ shift:2 for ADD]
127dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        EncodedInst |=
128dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines          MCRI.getEncodingValue(MI.getOperand(1).getReg()) << 5; // Rn
129dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        EncodedInst |= MCRI.getEncodingValue(MI.getOperand(0).getReg()); // Rd
130dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines
131dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        SymbolLookUp(DisInfo, EncodedInst, &ReferenceType, Address,
132dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines                     &ReferenceName);
133dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      }
134dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      if (ReferenceType == LLVMDisassembler_ReferenceType_Out_LitPool_SymAddr)
135dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        CommentStream << "literal pool symbol address: " << ReferenceName;
136dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      else if (ReferenceType ==
137dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines               LLVMDisassembler_ReferenceType_Out_LitPool_CstrAddr)
138dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        CommentStream << "literal pool for: \"" << ReferenceName << "\"";
139dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      else if (ReferenceType ==
140dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines               LLVMDisassembler_ReferenceType_Out_Objc_CFString_Ref)
141dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        CommentStream << "Objc cfstring ref: @\"" << ReferenceName << "\"";
142dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      else if (ReferenceType ==
143dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines               LLVMDisassembler_ReferenceType_Out_Objc_Message)
144dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        CommentStream << "Objc message: " << ReferenceName;
145dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      else if (ReferenceType ==
146dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines               LLVMDisassembler_ReferenceType_Out_Objc_Message_Ref)
147dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        CommentStream << "Objc message ref: " << ReferenceName;
148dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      else if (ReferenceType ==
149dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines               LLVMDisassembler_ReferenceType_Out_Objc_Selector_Ref)
150dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        CommentStream << "Objc selector ref: " << ReferenceName;
151dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      else if (ReferenceType ==
152dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines               LLVMDisassembler_ReferenceType_Out_Objc_Class_Ref)
153dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        CommentStream << "Objc class ref: " << ReferenceName;
154dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      // For these instructions, the SymbolLookUp() above is just to get the
155dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      // ReferenceType and ReferenceName.  We want to make sure not to
156dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      // fall through so we don't build an MCExpr to leave the disassembly
157dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      // of the immediate values of these instructions to the InstPrinter.
158dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      return false;
159dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    } else {
160dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      return false;
161dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    }
162dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  }
163dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines
164dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  const MCExpr *Add = nullptr;
165dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  if (SymbolicOp.AddSymbol.Present) {
166dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    if (SymbolicOp.AddSymbol.Name) {
167dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      StringRef Name(SymbolicOp.AddSymbol.Name);
168dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      MCSymbol *Sym = Ctx.GetOrCreateSymbol(Name);
169dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      MCSymbolRefExpr::VariantKind Variant = getVariant(SymbolicOp.VariantKind);
170dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      if (Variant != MCSymbolRefExpr::VK_None)
171dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        Add = MCSymbolRefExpr::Create(Sym, Variant, Ctx);
172dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      else
173dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines        Add = MCSymbolRefExpr::Create(Sym, Ctx);
174dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    } else {
175dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      Add = MCConstantExpr::Create(SymbolicOp.AddSymbol.Value, Ctx);
176dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    }
177dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  }
178dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines
179dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  const MCExpr *Sub = nullptr;
180dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  if (SymbolicOp.SubtractSymbol.Present) {
181dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    if (SymbolicOp.SubtractSymbol.Name) {
182dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      StringRef Name(SymbolicOp.SubtractSymbol.Name);
183dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      MCSymbol *Sym = Ctx.GetOrCreateSymbol(Name);
184dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      Sub = MCSymbolRefExpr::Create(Sym, Ctx);
185dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    } else {
186dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      Sub = MCConstantExpr::Create(SymbolicOp.SubtractSymbol.Value, Ctx);
187dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    }
188dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  }
189dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines
190dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  const MCExpr *Off = nullptr;
191dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  if (SymbolicOp.Value != 0)
192dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    Off = MCConstantExpr::Create(SymbolicOp.Value, Ctx);
193dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines
194dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  const MCExpr *Expr;
195dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  if (Sub) {
196dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    const MCExpr *LHS;
197dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    if (Add)
198dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      LHS = MCBinaryExpr::CreateSub(Add, Sub, Ctx);
199dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    else
200dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      LHS = MCUnaryExpr::CreateMinus(Sub, Ctx);
201dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    if (Off)
202dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      Expr = MCBinaryExpr::CreateAdd(LHS, Off, Ctx);
203dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    else
204dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      Expr = LHS;
205dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  } else if (Add) {
206dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    if (Off)
207dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      Expr = MCBinaryExpr::CreateAdd(Add, Off, Ctx);
208dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    else
209dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      Expr = Add;
210dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  } else {
211dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    if (Off)
212dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      Expr = Off;
213dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines    else
214dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines      Expr = MCConstantExpr::Create(0, Ctx);
215dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  }
216dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines
217dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  MI.addOperand(MCOperand::CreateExpr(Expr));
218dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines
219dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines  return true;
220dce4a407a24b04eebc6a376f8e62b41aaa7b071fStephen Hines}
221