blob: 3c19be308b60fad43f8b8fc87180702ed91d96bf [file] [log] [blame]
Daniel Dunbarfc6877a2009-06-29 20:40:36 +00001//===- 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"
Daniel Dunbar15d17072009-06-30 01:49:52 +000012#include "llvm/MC/MCSymbol.h"
Daniel Dunbarfc6877a2009-06-29 20:40:36 +000013#include "llvm/MC/MCValue.h"
14using namespace llvm;
15
16AsmExpr::~AsmExpr() {
17}
18
19bool AsmExpr::EvaluateAsAbsolute(MCContext &Ctx, int64_t &Res) const {
Daniel Dunbar15d17072009-06-30 01:49:52 +000020 MCValue Value;
21
22 if (!EvaluateAsRelocatable(Ctx, Value) || !Value.isConstant())
23 return false;
24
25 Res = Value.getConstant();
26 return true;
27}
28
Daniel Dunbar35976042009-06-30 02:08:27 +000029static bool EvaluateSymbolicAdd(const MCValue &LHS, MCSymbol *RHS_A,
30 MCSymbol *RHS_B, int64_t RHS_Cst,
31 MCValue &Res) {
32 // We can't add or subtract two symbols.
33 if ((LHS.getSymA() && RHS_A) ||
34 (LHS.getSymB() && RHS_B))
35 return false;
36
37 MCSymbol *A = LHS.getSymA() ? LHS.getSymA() : RHS_A;
38 MCSymbol *B = LHS.getSymB() ? LHS.getSymB() : RHS_B;
39 if (B) {
40 // If we have a negated symbol, then we must have also have a
41 // non-negated symbol, and both symbols must be in the same
42 // non-external section. We can do this check later to permit
43 // expressions which eventually fold to a representable form -- such
44 // as (a + (0 - b)) -- if necessary.
45 if (!A || !A->getSection() || A->getSection() != B->getSection())
46 return false;
47 }
48 Res = MCValue::get(A, B, LHS.getConstant() + RHS_Cst);
49 return true;
50}
51
Daniel Dunbar15d17072009-06-30 01:49:52 +000052bool AsmExpr::EvaluateAsRelocatable(MCContext &Ctx, MCValue &Res) const {
Daniel Dunbarfc6877a2009-06-29 20:40:36 +000053 switch (getKind()) {
54 default:
55 assert(0 && "Invalid assembly expression kind!");
56
57 case Constant:
Daniel Dunbar15d17072009-06-30 01:49:52 +000058 Res = MCValue::get(cast<AsmConstantExpr>(this)->getValue());
Daniel Dunbarfc6877a2009-06-29 20:40:36 +000059 return true;
60
61 case SymbolRef: {
62 MCSymbol *Sym = cast<AsmSymbolRefExpr>(this)->getSymbol();
Daniel Dunbar15d17072009-06-30 01:49:52 +000063 if (const MCValue *Value = Ctx.GetSymbolValue(Sym))
64 Res = *Value;
65 else
66 Res = MCValue::get(Sym, 0, 0);
Daniel Dunbarfc6877a2009-06-29 20:40:36 +000067 return true;
68 }
69
70 case Unary: {
71 const AsmUnaryExpr *AUE = cast<AsmUnaryExpr>(this);
Daniel Dunbar15d17072009-06-30 01:49:52 +000072 MCValue Value;
Daniel Dunbarfc6877a2009-06-29 20:40:36 +000073
Daniel Dunbar15d17072009-06-30 01:49:52 +000074 if (!AUE->getSubExpr()->EvaluateAsRelocatable(Ctx, Value))
Daniel Dunbarfc6877a2009-06-29 20:40:36 +000075 return false;
76
77 switch (AUE->getOpcode()) {
Daniel Dunbar15d17072009-06-30 01:49:52 +000078 case AsmUnaryExpr::LNot:
79 if (!Value.isConstant())
80 return false;
81 Res = MCValue::get(!Value.getConstant());
82 break;
83 case AsmUnaryExpr::Minus:
84 /// -(a - b + const) ==> (b - a - const)
85 if (Value.getSymA() && !Value.getSymA())
86 return false;
87 Res = MCValue::get(Value.getSymB(), Value.getSymA(),
88 -Value.getConstant());
89 break;
90 case AsmUnaryExpr::Not:
91 if (!Value.isConstant())
92 return false;
93 Res = MCValue::get(~Value.getConstant());
94 break;
95 case AsmUnaryExpr::Plus:
96 Res = Value;
97 break;
Daniel Dunbarfc6877a2009-06-29 20:40:36 +000098 }
99
100 return true;
101 }
102
103 case Binary: {
104 const AsmBinaryExpr *ABE = cast<AsmBinaryExpr>(this);
Daniel Dunbar15d17072009-06-30 01:49:52 +0000105 MCValue LHSValue, RHSValue;
Daniel Dunbarfc6877a2009-06-29 20:40:36 +0000106
Daniel Dunbar15d17072009-06-30 01:49:52 +0000107 if (!ABE->getLHS()->EvaluateAsRelocatable(Ctx, LHSValue) ||
108 !ABE->getRHS()->EvaluateAsRelocatable(Ctx, RHSValue))
Daniel Dunbarfc6877a2009-06-29 20:40:36 +0000109 return false;
110
Daniel Dunbar15d17072009-06-30 01:49:52 +0000111 // We only support a few operations on non-constant expressions, handle
112 // those first.
113 if (!LHSValue.isConstant() || !RHSValue.isConstant()) {
114 switch (ABE->getOpcode()) {
115 default:
116 return false;
117 case AsmBinaryExpr::Sub:
Daniel Dunbar35976042009-06-30 02:08:27 +0000118 // Negate RHS and add.
119 return EvaluateSymbolicAdd(LHSValue,
120 RHSValue.getSymB(), RHSValue.getSymA(),
121 -RHSValue.getConstant(),
122 Res);
123
Daniel Dunbar15d17072009-06-30 01:49:52 +0000124 case AsmBinaryExpr::Add:
Daniel Dunbar35976042009-06-30 02:08:27 +0000125 return EvaluateSymbolicAdd(LHSValue,
126 RHSValue.getSymA(), RHSValue.getSymB(),
127 RHSValue.getConstant(),
128 Res);
Daniel Dunbar15d17072009-06-30 01:49:52 +0000129 }
130 }
131
Daniel Dunbarfc6877a2009-06-29 20:40:36 +0000132 // FIXME: We need target hooks for the evaluation. It may be limited in
133 // width, and gas defines the result of comparisons differently from Apple
134 // as (the result is sign extended).
Daniel Dunbarb79742c2009-06-30 16:02:47 +0000135 int64_t LHS = LHSValue.getConstant(), RHS = RHSValue.getConstant();
136 int64_t Result = 0;
Daniel Dunbarfc6877a2009-06-29 20:40:36 +0000137 switch (ABE->getOpcode()) {
Daniel Dunbar15d17072009-06-30 01:49:52 +0000138 case AsmBinaryExpr::Add: Result = LHS + RHS; break;
139 case AsmBinaryExpr::And: Result = LHS & RHS; break;
140 case AsmBinaryExpr::Div: Result = LHS / RHS; break;
141 case AsmBinaryExpr::EQ: Result = LHS == RHS; break;
142 case AsmBinaryExpr::GT: Result = LHS > RHS; break;
143 case AsmBinaryExpr::GTE: Result = LHS >= RHS; break;
144 case AsmBinaryExpr::LAnd: Result = LHS && RHS; break;
145 case AsmBinaryExpr::LOr: Result = LHS || RHS; break;
146 case AsmBinaryExpr::LT: Result = LHS < RHS; break;
147 case AsmBinaryExpr::LTE: Result = LHS <= RHS; break;
148 case AsmBinaryExpr::Mod: Result = LHS % RHS; break;
149 case AsmBinaryExpr::Mul: Result = LHS * RHS; break;
150 case AsmBinaryExpr::NE: Result = LHS != RHS; break;
151 case AsmBinaryExpr::Or: Result = LHS | RHS; break;
152 case AsmBinaryExpr::Shl: Result = LHS << RHS; break;
153 case AsmBinaryExpr::Shr: Result = LHS >> RHS; break;
154 case AsmBinaryExpr::Sub: Result = LHS - RHS; break;
155 case AsmBinaryExpr::Xor: Result = LHS ^ RHS; break;
Daniel Dunbarfc6877a2009-06-29 20:40:36 +0000156 }
157
Daniel Dunbar15d17072009-06-30 01:49:52 +0000158 Res = MCValue::get(Result);
Daniel Dunbarfc6877a2009-06-29 20:40:36 +0000159 return true;
160 }
161 }
162}
163