[PowerPC] Clean up generation of ha16() / lo16() markers
[oota-llvm.git] / lib / Target / PowerPC / MCTargetDesc / PPCMCExpr.cpp
1 //===-- PPCMCExpr.cpp - PPC specific MC expression classes ----------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #define DEBUG_TYPE "ppcmcexpr"
11 #include "PPCMCExpr.h"
12 #include "llvm/MC/MCAssembler.h"
13 #include "llvm/MC/MCContext.h"
14
15 using namespace llvm;
16
17 const PPCMCExpr*
18 PPCMCExpr::Create(VariantKind Kind, const MCExpr *Expr,
19                        MCContext &Ctx) {
20   return new (Ctx) PPCMCExpr(Kind, Expr);
21 }
22
23 void PPCMCExpr::PrintImpl(raw_ostream &OS) const {
24   switch (Kind) {
25   default: llvm_unreachable("Invalid kind!");
26   case VK_PPC_HA16: OS << "ha16"; break;
27   case VK_PPC_LO16: OS << "lo16"; break;
28   }
29
30   OS << '(';
31   getSubExpr()->print(OS);
32   OS << ')';
33 }
34
35 bool
36 PPCMCExpr::EvaluateAsRelocatableImpl(MCValue &Res,
37                                      const MCAsmLayout *Layout) const {
38   MCValue Value;
39
40   if (!getSubExpr()->EvaluateAsRelocatable(Value, *Layout))
41     return false;
42
43   if (Value.isAbsolute()) {
44     int64_t Result = Value.getConstant();
45     switch (Kind) {
46       default:
47         llvm_unreachable("Invalid kind!");
48       case VK_PPC_HA16:
49         Result = ((Result >> 16) + ((Result & 0x8000) ? 1 : 0)) & 0xffff;
50         break;
51       case VK_PPC_LO16:
52         Result = Result & 0xffff;
53         break;
54     }
55     Res = MCValue::get(Result);
56   } else {
57     MCContext &Context = Layout->getAssembler().getContext();
58     const MCSymbolRefExpr *Sym = Value.getSymA();
59     MCSymbolRefExpr::VariantKind Modifier = Sym->getKind();
60     if (Modifier != MCSymbolRefExpr::VK_None)
61       return false;
62     switch (Kind) {
63       default:
64         llvm_unreachable("Invalid kind!");
65       case VK_PPC_HA16:
66         Modifier = MCSymbolRefExpr::VK_PPC_ADDR16_HA;
67         break;
68       case VK_PPC_LO16:
69         Modifier = MCSymbolRefExpr::VK_PPC_ADDR16_LO;
70         break;
71     }
72     Sym = MCSymbolRefExpr::Create(&Sym->getSymbol(), Modifier, Context);
73     Res = MCValue::get(Sym, Value.getSymB(), Value.getConstant());
74   }
75
76   return true;
77 }
78
79 // FIXME: This basically copies MCObjectStreamer::AddValueSymbols. Perhaps
80 // that method should be made public?
81 static void AddValueSymbols_(const MCExpr *Value, MCAssembler *Asm) {
82   switch (Value->getKind()) {
83   case MCExpr::Target:
84     llvm_unreachable("Can't handle nested target expr!");
85
86   case MCExpr::Constant:
87     break;
88
89   case MCExpr::Binary: {
90     const MCBinaryExpr *BE = cast<MCBinaryExpr>(Value);
91     AddValueSymbols_(BE->getLHS(), Asm);
92     AddValueSymbols_(BE->getRHS(), Asm);
93     break;
94   }
95
96   case MCExpr::SymbolRef:
97     Asm->getOrCreateSymbolData(cast<MCSymbolRefExpr>(Value)->getSymbol());
98     break;
99
100   case MCExpr::Unary:
101     AddValueSymbols_(cast<MCUnaryExpr>(Value)->getSubExpr(), Asm);
102     break;
103   }
104 }
105
106 void PPCMCExpr::AddValueSymbols(MCAssembler *Asm) const {
107   AddValueSymbols_(getSubExpr(), Asm);
108 }