blob: 63599927bf87ba45da412775ccecdeb5368dc595 [file] [log] [blame]
Chris Lattnera5682852006-08-07 23:03:03 +00001//===-- SelectionDAGCSEMap.cpp - Implement the SelectionDAG CSE Map -------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file was developed by Chris Lattner and is distributed under
6// the University of Illinois Open Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This implements the SelectionDAGCSEMap class.
11//
12//===----------------------------------------------------------------------===//
13
14#include "llvm/CodeGen/SelectionDAG.h"
15using namespace llvm;
16
17//===----------------------------------------------------------------------===//
18// SelectionDAGCSEMap::NodeID Implementation
19
20SelectionDAGCSEMap::NodeID::NodeID(SDNode *N) {
21 SetOpcode(N->getOpcode());
22 // Add the return value info.
23 SetValueTypes(N->value_begin());
24 // Add the operand info.
25 SetOperands(N->op_begin(), N->getNumOperands());
26}
27
28SelectionDAGCSEMap::NodeID::NodeID(unsigned short ID, const void *VTList) {
29 SetOpcode(ID);
30 SetValueTypes(VTList);
31 SetOperands();
32}
33SelectionDAGCSEMap::NodeID::NodeID(unsigned short ID, const void *VTList,
34 SDOperand Op) {
35 SetOpcode(ID);
36 SetValueTypes(VTList);
37 SetOperands(Op);
38}
39SelectionDAGCSEMap::NodeID::NodeID(unsigned short ID, const void *VTList,
40 SDOperand Op1, SDOperand Op2) {
41 SetOpcode(ID);
42 SetValueTypes(VTList);
43 SetOperands(Op1, Op2);
44}
45SelectionDAGCSEMap::NodeID::NodeID(unsigned short ID, const void *VTList,
46 SDOperand Op1, SDOperand Op2,
47 SDOperand Op3) {
48 SetOpcode(ID);
49 SetValueTypes(VTList);
50 SetOperands(Op1, Op2, Op3);
51}
52SelectionDAGCSEMap::NodeID::NodeID(unsigned short ID, const void *VTList,
53 const SDOperand *OpList, unsigned N) {
54 SetOpcode(ID);
55 SetValueTypes(VTList);
56 SetOperands(OpList, N);
57}
58
59void SelectionDAGCSEMap::NodeID::AddPointer(const void *Ptr) {
60 // Note: this adds pointers to the hash using sizes and endianness that depend
61 // on the host. It doesn't matter however, because hashing on pointer values
62 // in inherently unstable. Nothing in the SelectionDAG should depend on the
63 // ordering of nodes in the CSEMap.
64 union {
65 intptr_t PtrI;
66 unsigned char PtrA[sizeof(intptr_t)];
67 };
68 PtrI = (intptr_t)Ptr;
69 Bits.append(PtrA, PtrA+sizeof(intptr_t));
70}
71
72void SelectionDAGCSEMap::NodeID::AddOperand(SDOperand Op) {
73 AddPointer(Op.Val);
74 // 2 bytes of resno might be too small, three should certainly be enough. :)
75 assert(Op.ResNo < (1 << 24) && "ResNo too large for CSE Map to handle!");
76 Bits.push_back((Op.ResNo >> 0) & 0xFF);
77 Bits.push_back((Op.ResNo >> 8) & 0xFF);
78 Bits.push_back((Op.ResNo >> 16) & 0xFF);
79}
80
81void SelectionDAGCSEMap::NodeID::SetOperands(const SDOperand *Ops,
82 unsigned NumOps) {
83 for (; NumOps; --NumOps, ++Ops)
84 AddOperand(*Ops);
85}
86
87
88/// ComputeHash - Compute a strong hash value for this NodeID, for lookup in
89/// the SelectionDAGCSEMap.
90unsigned SelectionDAGCSEMap::NodeID::ComputeHash() const {
91 // FIXME: this hash function sucks.
92 unsigned Hash = 0;
93 for (unsigned i = 0, e = Bits.size(); i != e; ++i)
94 Hash += Bits[i];
95 return Hash;
96}
97
98bool SelectionDAGCSEMap::NodeID::operator==(const NodeID &RHS) const {
99 if (Bits.size() != RHS.Bits.size()) return false;
100 return memcmp(&Bits[0], &RHS.Bits[0], Bits.size()) == 0;
101}
102
103
104//===----------------------------------------------------------------------===//
105// SelectionDAGCSEMap Implementation
106
107SelectionDAGCSEMap::SelectionDAGCSEMap() {
108 NumBuckets = 256;
109 Buckets = new void*[NumBuckets];
110 memset(Buckets, 0, NumBuckets*sizeof(void*));
111}
112SelectionDAGCSEMap::~SelectionDAGCSEMap() {
113 delete [] Buckets;
114}
115
116/// GetNextPtr - In order to save space, each bucket is a singly-linked-list. In
117/// order to make deletion more efficient, we make the list circular, so we can
118/// delete a node without computing its hash. The problem with this is that the
119/// start of the hash buckets are not SDNodes. If NextInBucketPtr is a bucket
120/// pointer, this method returns null: use GetBucketPtr when this happens.
121SDNode *SelectionDAGCSEMap::GetNextPtr(void *NextInBucketPtr) {
122 if (NextInBucketPtr >= Buckets && NextInBucketPtr < Buckets+NumBuckets)
123 return 0;
124 return static_cast<SDNode*>(NextInBucketPtr);
125}
126
127void **SelectionDAGCSEMap::GetBucketPtr(void *NextInBucketPtr) {
128 assert(NextInBucketPtr >= Buckets && NextInBucketPtr < Buckets+NumBuckets &&
129 "NextInBucketPtr is not a bucket ptr");
130 return static_cast<void**>(NextInBucketPtr);
131}
132
133/// GetBucketFor - Hash the specified node ID and return the hash bucket for the
134/// specified ID.
135void **SelectionDAGCSEMap::GetBucketFor(const NodeID &ID) const {
136 // TODO: if load is high, resize hash table.
137
138 // NumBuckets is always a power of 2.
139 unsigned BucketNum = ID.ComputeHash() & (NumBuckets-1);
140 return Buckets+BucketNum;
141}
142
143/// FindNodeOrInsertPos - Look up the node specified by ID. If it exists,
144/// return it. If not, return the insertion token that will make insertion
145/// faster.
146SDNode *SelectionDAGCSEMap::FindNodeOrInsertPos(const NodeID &ID,
147 void *&InsertPos) {
148 void **Bucket = GetBucketFor(ID);
149 void *Probe = *Bucket;
150
151 InsertPos = 0;
152
153 unsigned Opc = ID.getOpcode();
154 while (SDNode *NodeInBucket = GetNextPtr(Probe)) {
155 // If we found a node with the same opcode, it might be a matching node.
156 // Because it is in the same bucket as this one, we know the hash values
157 // match. Compute the NodeID for the possible match and do a final compare.
158 if (NodeInBucket->getOpcode() == Opc) {
159 NodeID OtherID(NodeInBucket);
160 if (OtherID == ID)
161 return NodeInBucket;
162 }
163
164 Probe = NodeInBucket->getNextInBucket();
165 }
166
167 // Didn't find the node, return null with the bucket as the InsertPos.
168 InsertPos = Bucket;
169 return 0;
170}
171
172/// InsertNode - Insert the specified node into the CSE Map, knowing that it
173/// is not already in the map. InsertPos must be obtained from
174/// FindNodeOrInsertPos.
175void SelectionDAGCSEMap::InsertNode(SDNode *N, void *InsertPos) {
176 /// The insert position is actually a bucket pointer.
177 void **Bucket = static_cast<void**>(InsertPos);
178
179 void *Next = *Bucket;
180
181 // If this is the first insertion into this bucket, its next pointer will be
182 // null. Pretend as if it pointed to itself.
183 if (Next == 0)
184 Next = Bucket;
185
186 // Set the nodes next pointer, and make the bucket point to the node.
187 N->SetNextInBucket(Next);
188 *Bucket = N;
189}
190
191
192/// RemoveNode - Remove a node from the CSE map, returning true if one was
193/// removed or false if the node was not in the CSE map.
194bool SelectionDAGCSEMap::RemoveNode(SDNode *N) {
195 // Because each bucket is a circular list, we don't need to compute N's hash
196 // to remove it. Chase around the list until we find the node (or bucket)
197 // which points to N.
198 void *Ptr = N->getNextInBucket();
199 if (Ptr == 0) return false; // Not in CSEMap.
200
201 void *NodeNextPtr = Ptr;
202 N->SetNextInBucket(0);
203 while (1) {
204 if (SDNode *NodeInBucket = GetNextPtr(Ptr)) {
205 // Advance pointer.
206 Ptr = NodeInBucket->getNextInBucket();
207
208 // We found a node that points to N, change it to point to N's next node,
209 // removing N from the list.
210 if (Ptr == N) {
211 NodeInBucket->SetNextInBucket(NodeNextPtr);
212 return true;
213 }
214 } else {
215 void **Bucket = GetBucketPtr(Ptr);
216 Ptr = *Bucket;
217
218 // If we found that the bucket points to N, update the bucket to point to
219 // whatever is next.
220 if (Ptr == N) {
221 *Bucket = NodeNextPtr;
222 return true;
223 }
224 }
225 }
226}
227
228/// GetOrInsertSimpleNode - If there is an existing simple SDNode exactly
229/// equal to the specified node, return it. Otherwise, insert 'N' and it
230/// instead. This only works on *simple* SDNodes, not ConstantSDNode or any
231/// other classes derived from SDNode.
232SDNode *SelectionDAGCSEMap::GetOrInsertNode(SDNode *N) {
233 SelectionDAGCSEMap::NodeID ID(N);
234 void *IP;
235 if (SDNode *E = FindNodeOrInsertPos(ID, IP))
236 return E;
237 InsertNode(N, IP);
238 return N;
239}