1249259Sdim//===-- Use.cpp - Implement the Use class ---------------------------------===//
2249259Sdim//
3249259Sdim//                     The LLVM Compiler Infrastructure
4249259Sdim//
5249259Sdim// This file is distributed under the University of Illinois Open Source
6249259Sdim// License. See LICENSE.TXT for details.
7249259Sdim//
8249259Sdim//===----------------------------------------------------------------------===//
9249259Sdim//
10249259Sdim// This file implements the algorithm for finding the User of a Use.
11249259Sdim//
12249259Sdim//===----------------------------------------------------------------------===//
13249259Sdim
14249259Sdim#include "llvm/IR/Value.h"
15249259Sdim#include <new>
16249259Sdim
17249259Sdimnamespace llvm {
18249259Sdim
19249259Sdim//===----------------------------------------------------------------------===//
20249259Sdim//                         Use swap Implementation
21249259Sdim//===----------------------------------------------------------------------===//
22249259Sdim
23249259Sdimvoid Use::swap(Use &RHS) {
24249259Sdim  Value *V1(Val);
25249259Sdim  Value *V2(RHS.Val);
26249259Sdim  if (V1 != V2) {
27249259Sdim    if (V1) {
28249259Sdim      removeFromList();
29249259Sdim    }
30249259Sdim
31249259Sdim    if (V2) {
32249259Sdim      RHS.removeFromList();
33249259Sdim      Val = V2;
34249259Sdim      V2->addUse(*this);
35249259Sdim    } else {
36249259Sdim      Val = 0;
37249259Sdim    }
38249259Sdim
39249259Sdim    if (V1) {
40249259Sdim      RHS.Val = V1;
41249259Sdim      V1->addUse(RHS);
42249259Sdim    } else {
43249259Sdim      RHS.Val = 0;
44249259Sdim    }
45249259Sdim  }
46249259Sdim}
47249259Sdim
48249259Sdim//===----------------------------------------------------------------------===//
49249259Sdim//                         Use getImpliedUser Implementation
50249259Sdim//===----------------------------------------------------------------------===//
51249259Sdim
52249259Sdimconst Use *Use::getImpliedUser() const {
53249259Sdim  const Use *Current = this;
54249259Sdim
55249259Sdim  while (true) {
56249259Sdim    unsigned Tag = (Current++)->Prev.getInt();
57249259Sdim    switch (Tag) {
58249259Sdim      case zeroDigitTag:
59249259Sdim      case oneDigitTag:
60249259Sdim        continue;
61249259Sdim
62249259Sdim      case stopTag: {
63249259Sdim        ++Current;
64249259Sdim        ptrdiff_t Offset = 1;
65249259Sdim        while (true) {
66249259Sdim          unsigned Tag = Current->Prev.getInt();
67249259Sdim          switch (Tag) {
68249259Sdim            case zeroDigitTag:
69249259Sdim            case oneDigitTag:
70249259Sdim              ++Current;
71249259Sdim              Offset = (Offset << 1) + Tag;
72249259Sdim              continue;
73249259Sdim            default:
74249259Sdim              return Current + Offset;
75249259Sdim          }
76249259Sdim        }
77249259Sdim      }
78249259Sdim
79249259Sdim      case fullStopTag:
80249259Sdim        return Current;
81249259Sdim    }
82249259Sdim  }
83249259Sdim}
84249259Sdim
85249259Sdim//===----------------------------------------------------------------------===//
86249259Sdim//                         Use initTags Implementation
87249259Sdim//===----------------------------------------------------------------------===//
88249259Sdim
89249259SdimUse *Use::initTags(Use * const Start, Use *Stop) {
90249259Sdim  ptrdiff_t Done = 0;
91249259Sdim  while (Done < 20) {
92249259Sdim    if (Start == Stop--)
93249259Sdim      return Start;
94249259Sdim    static const PrevPtrTag tags[20] = { fullStopTag, oneDigitTag, stopTag,
95249259Sdim                                         oneDigitTag, oneDigitTag, stopTag,
96249259Sdim                                         zeroDigitTag, oneDigitTag, oneDigitTag,
97249259Sdim                                         stopTag, zeroDigitTag, oneDigitTag,
98249259Sdim                                         zeroDigitTag, oneDigitTag, stopTag,
99249259Sdim                                         oneDigitTag, oneDigitTag, oneDigitTag,
100249259Sdim                                         oneDigitTag, stopTag
101249259Sdim                                       };
102249259Sdim    new(Stop) Use(tags[Done++]);
103249259Sdim  }
104249259Sdim
105249259Sdim  ptrdiff_t Count = Done;
106249259Sdim  while (Start != Stop) {
107249259Sdim    --Stop;
108249259Sdim    if (!Count) {
109249259Sdim      new(Stop) Use(stopTag);
110249259Sdim      ++Done;
111249259Sdim      Count = Done;
112249259Sdim    } else {
113249259Sdim      new(Stop) Use(PrevPtrTag(Count & 1));
114249259Sdim      Count >>= 1;
115249259Sdim      ++Done;
116249259Sdim    }
117249259Sdim  }
118249259Sdim
119249259Sdim  return Start;
120249259Sdim}
121249259Sdim
122249259Sdim//===----------------------------------------------------------------------===//
123249259Sdim//                         Use zap Implementation
124249259Sdim//===----------------------------------------------------------------------===//
125249259Sdim
126249259Sdimvoid Use::zap(Use *Start, const Use *Stop, bool del) {
127249259Sdim  while (Start != Stop)
128249259Sdim    (--Stop)->~Use();
129249259Sdim  if (del)
130249259Sdim    ::operator delete(Start);
131249259Sdim}
132249259Sdim
133249259Sdim//===----------------------------------------------------------------------===//
134249259Sdim//                         Use getUser Implementation
135249259Sdim//===----------------------------------------------------------------------===//
136249259Sdim
137249259SdimUser *Use::getUser() const {
138249259Sdim  const Use *End = getImpliedUser();
139249259Sdim  const UserRef *ref = reinterpret_cast<const UserRef*>(End);
140249259Sdim  return ref->getInt()
141249259Sdim    ? ref->getPointer()
142249259Sdim    : reinterpret_cast<User*>(const_cast<Use*>(End));
143249259Sdim}
144249259Sdim
145249259Sdim} // End llvm namespace
146