aboutsummaryrefslogtreecommitdiffstats
path: root/tools/llvm-mc/AsmExpr.cpp
blob: 7e4baf84e77b31f71a35b51957ac85f98d3a6409 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
//===- AsmExpr.cpp - Assembly file expressions ----------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "AsmExpr.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCValue.h"
using namespace llvm;

AsmExpr::~AsmExpr() {
}

bool AsmExpr::EvaluateAsAbsolute(MCContext &Ctx, int64_t &Res) const {
  switch (getKind()) {
  default:
    assert(0 && "Invalid assembly expression kind!");

  case Constant:
    Res = cast<AsmConstantExpr>(this)->getValue();
    return true;

  case SymbolRef: {
    MCSymbol *Sym = cast<AsmSymbolRefExpr>(this)->getSymbol();
    const MCValue *Value = Ctx.GetSymbolValue(Sym);

    // FIXME: Return more information about the failure.
    if (!Value || !Value->isConstant())
      return false;

    Res = Value->getConstant();
    return true;
  }

  case Unary: {
    const AsmUnaryExpr *AUE = cast<AsmUnaryExpr>(this);
    int64_t Value;

    if (!AUE->getSubExpr()->EvaluateAsAbsolute(Ctx, Value))
      return false;

    switch (AUE->getOpcode()) {
    case AsmUnaryExpr::LNot:  Res = !Value; break;
    case AsmUnaryExpr::Minus: Res = -Value; break;
    case AsmUnaryExpr::Not:   Res = ~Value; break;
    case AsmUnaryExpr::Plus:  Res = +Value; break;
    }

    return true;
  }

  case Binary: {
    const AsmBinaryExpr *ABE = cast<AsmBinaryExpr>(this);
    int64_t LHS, RHS;
    
    if (!ABE->getLHS()->EvaluateAsAbsolute(Ctx, LHS) ||
        !ABE->getRHS()->EvaluateAsAbsolute(Ctx, RHS))
      return false;

    // FIXME: We need target hooks for the evaluation. It may be limited in
    // width, and gas defines the result of comparisons differently from Apple
    // as (the result is sign extended).
    switch (ABE->getOpcode()) {
    case AsmBinaryExpr::Add:  Res = LHS + RHS; break;
    case AsmBinaryExpr::And:  Res = LHS & RHS; break;
    case AsmBinaryExpr::Div:  Res = LHS / RHS; break;
    case AsmBinaryExpr::EQ:   Res = LHS == RHS; break;
    case AsmBinaryExpr::GT:   Res = LHS > RHS; break;
    case AsmBinaryExpr::GTE:  Res = LHS >= RHS; break;
    case AsmBinaryExpr::LAnd: Res = LHS && RHS; break;
    case AsmBinaryExpr::LOr:  Res = LHS || RHS; break;
    case AsmBinaryExpr::LT:   Res = LHS < RHS; break;
    case AsmBinaryExpr::LTE:  Res = LHS <= RHS; break;
    case AsmBinaryExpr::Mod:  Res = LHS % RHS; break;
    case AsmBinaryExpr::Mul:  Res = LHS * RHS; break;
    case AsmBinaryExpr::NE:   Res = LHS != RHS; break;
    case AsmBinaryExpr::Or:   Res = LHS | RHS; break;
    case AsmBinaryExpr::Shl:  Res = LHS << RHS; break;
    case AsmBinaryExpr::Shr:  Res = LHS >> RHS; break;
    case AsmBinaryExpr::Sub:  Res = LHS - RHS; break;
    case AsmBinaryExpr::Xor:  Res = LHS ^ RHS; break;
    }

    return true;
  }
  }
}