llvm-mc: Evaluation for relocatable expressions.
[oota-llvm.git] / tools / llvm-mc / AsmExpr.cpp
1 //===- AsmExpr.cpp - Assembly file expressions ----------------------------===//
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 #include "AsmExpr.h"
11 #include "llvm/MC/MCContext.h"
12 #include "llvm/MC/MCSymbol.h"
13 #include "llvm/MC/MCValue.h"
14 using namespace llvm;
15
16 AsmExpr::~AsmExpr() {
17 }
18
19 bool AsmExpr::EvaluateAsAbsolute(MCContext &Ctx, int64_t &Res) const {
20   MCValue Value;
21   
22   if (!EvaluateAsRelocatable(Ctx, Value) || !Value.isConstant())
23     return false;
24
25   Res = Value.getConstant();
26   return true;
27 }
28
29 bool AsmExpr::EvaluateAsRelocatable(MCContext &Ctx, MCValue &Res) const {
30   switch (getKind()) {
31   default:
32     assert(0 && "Invalid assembly expression kind!");
33
34   case Constant:
35     Res = MCValue::get(cast<AsmConstantExpr>(this)->getValue());
36     return true;
37
38   case SymbolRef: {
39     MCSymbol *Sym = cast<AsmSymbolRefExpr>(this)->getSymbol();
40     if (const MCValue *Value = Ctx.GetSymbolValue(Sym))
41       Res = *Value;
42     else
43       Res = MCValue::get(Sym, 0, 0);
44     return true;
45   }
46
47   case Unary: {
48     const AsmUnaryExpr *AUE = cast<AsmUnaryExpr>(this);
49     MCValue Value;
50
51     if (!AUE->getSubExpr()->EvaluateAsRelocatable(Ctx, Value))
52       return false;
53
54     switch (AUE->getOpcode()) {
55     case AsmUnaryExpr::LNot:
56       if (!Value.isConstant())
57         return false;
58       Res = MCValue::get(!Value.getConstant());
59       break;
60     case AsmUnaryExpr::Minus:
61       /// -(a - b + const) ==> (b - a - const)
62       if (Value.getSymA() && !Value.getSymA())
63         return false;
64       Res = MCValue::get(Value.getSymB(), Value.getSymA(), 
65                          -Value.getConstant()); 
66       break;
67     case AsmUnaryExpr::Not:
68       if (!Value.isConstant())
69         return false;
70       Res = MCValue::get(~Value.getConstant()); 
71       break;
72     case AsmUnaryExpr::Plus:
73       Res = Value;
74       break;
75     }
76
77     return true;
78   }
79
80   case Binary: {
81     const AsmBinaryExpr *ABE = cast<AsmBinaryExpr>(this);
82     MCValue LHSValue, RHSValue;
83     
84     if (!ABE->getLHS()->EvaluateAsRelocatable(Ctx, LHSValue) ||
85         !ABE->getRHS()->EvaluateAsRelocatable(Ctx, RHSValue))
86       return false;
87
88     // We only support a few operations on non-constant expressions, handle
89     // those first.
90     if (!LHSValue.isConstant() || !RHSValue.isConstant()) {
91       switch (ABE->getOpcode()) {
92       default:
93         return false;
94       case AsmBinaryExpr::Sub:
95         // Negate RHS and fall through.
96         RHSValue = MCValue::get(RHSValue.getSymB(), RHSValue.getSymA(), 
97                                 -RHSValue.getConstant());
98       case AsmBinaryExpr::Add:
99         // (a_0 - b_0 + cst_0) + (a_1 - b_1 + cst_1)
100
101         // We can't add or subtract two symbols.
102         if ((LHSValue.getSymA() && RHSValue.getSymB()) ||
103             (LHSValue.getSymB() && RHSValue.getSymB()))
104           return false;
105
106         MCSymbol *A = 
107           LHSValue.getSymA() ? LHSValue.getSymA() : RHSValue.getSymA();
108         MCSymbol *B = 
109           LHSValue.getSymB() ? LHSValue.getSymB() : RHSValue.getSymB();
110         if (B) {
111           // If we have a negated symbol, then we must have also have a
112           // non-negated symbol, and both symbols must be in the same
113           // non-external section. We can do this check later to permit
114           // expressions which eventually fold to a representable form -- such
115           // as (a + (0 - b)) -- if necessary.
116           if (!A || !A->getSection() || A->getSection() != B->getSection())
117             return false;
118         }
119         Res = MCValue::get(A, B, 
120                            LHSValue.getConstant() + RHSValue.getConstant());
121         return true;
122       }
123     }
124
125     // FIXME: We need target hooks for the evaluation. It may be limited in
126     // width, and gas defines the result of comparisons differently from Apple
127     // as (the result is sign extended).
128     int64_t Result, LHS = LHSValue.getConstant(), RHS = RHSValue.getConstant();
129     switch (ABE->getOpcode()) {
130     case AsmBinaryExpr::Add:  Result = LHS + RHS; break;
131     case AsmBinaryExpr::And:  Result = LHS & RHS; break;
132     case AsmBinaryExpr::Div:  Result = LHS / RHS; break;
133     case AsmBinaryExpr::EQ:   Result = LHS == RHS; break;
134     case AsmBinaryExpr::GT:   Result = LHS > RHS; break;
135     case AsmBinaryExpr::GTE:  Result = LHS >= RHS; break;
136     case AsmBinaryExpr::LAnd: Result = LHS && RHS; break;
137     case AsmBinaryExpr::LOr:  Result = LHS || RHS; break;
138     case AsmBinaryExpr::LT:   Result = LHS < RHS; break;
139     case AsmBinaryExpr::LTE:  Result = LHS <= RHS; break;
140     case AsmBinaryExpr::Mod:  Result = LHS % RHS; break;
141     case AsmBinaryExpr::Mul:  Result = LHS * RHS; break;
142     case AsmBinaryExpr::NE:   Result = LHS != RHS; break;
143     case AsmBinaryExpr::Or:   Result = LHS | RHS; break;
144     case AsmBinaryExpr::Shl:  Result = LHS << RHS; break;
145     case AsmBinaryExpr::Shr:  Result = LHS >> RHS; break;
146     case AsmBinaryExpr::Sub:  Result = LHS - RHS; break;
147     case AsmBinaryExpr::Xor:  Result = LHS ^ RHS; break;
148     }
149
150     Res = MCValue::get(Result);
151     return true;
152   }
153   }
154 }
155