blob: cd255ba3272e00304d6bf30e47b30b4bfbd7c7d2 [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"
Chris Lattnerc9f8f412006-08-11 21:55:30 +000015#include "llvm/Support/MathExtras.h"
Chris Lattnera5682852006-08-07 23:03:03 +000016using namespace llvm;
17
18//===----------------------------------------------------------------------===//
19// SelectionDAGCSEMap::NodeID Implementation
20
21SelectionDAGCSEMap::NodeID::NodeID(SDNode *N) {
22 SetOpcode(N->getOpcode());
23 // Add the return value info.
24 SetValueTypes(N->value_begin());
25 // Add the operand info.
26 SetOperands(N->op_begin(), N->getNumOperands());
Chris Lattner61b09412006-08-11 21:01:22 +000027
28 // Handle SDNode leafs with special info.
29 if (N->getNumOperands() == 0) {
30 switch (N->getOpcode()) {
31 default: break; // Normal nodes don't need extra info.
32 case ISD::TargetConstant:
33 case ISD::Constant:
34 AddInteger(cast<ConstantSDNode>(N)->getValue());
35 break;
Chris Lattnerc9f8f412006-08-11 21:55:30 +000036 case ISD::TargetConstantFP:
37 case ISD::ConstantFP:
38 AddInteger(DoubleToBits(cast<ConstantFPSDNode>(N)->getValue()));
39 break;
Chris Lattner61b09412006-08-11 21:01:22 +000040 case ISD::TargetGlobalAddress:
41 case ISD::GlobalAddress:
42 AddPointer(cast<GlobalAddressSDNode>(N)->getGlobal());
43 AddInteger(cast<GlobalAddressSDNode>(N)->getOffset());
44 break;
45 case ISD::BasicBlock:
46 AddPointer(cast<BasicBlockSDNode>(N)->getBasicBlock());
47 break;
48 case ISD::Register:
49 AddInteger(cast<RegisterSDNode>(N)->getReg());
50 break;
51 case ISD::SRCVALUE:
52 AddPointer(cast<SrcValueSDNode>(N)->getValue());
53 AddInteger(cast<SrcValueSDNode>(N)->getOffset());
54 break;
Chris Lattnerc9f8f412006-08-11 21:55:30 +000055 case ISD::FrameIndex:
56 case ISD::TargetFrameIndex:
57 AddInteger(cast<FrameIndexSDNode>(N)->getIndex());
58 break;
59 case ISD::JumpTable:
60 case ISD::TargetJumpTable:
61 AddInteger(cast<JumpTableSDNode>(N)->getIndex());
62 break;
63 case ISD::ConstantPool:
64 case ISD::TargetConstantPool:
65 AddInteger(cast<ConstantPoolSDNode>(N)->getAlignment());
66 AddInteger(cast<ConstantPoolSDNode>(N)->getOffset());
Chris Lattner130fc132006-08-14 20:12:44 +000067 AddPointer(cast<ConstantPoolSDNode>(N)->get());
Chris Lattnerc9f8f412006-08-11 21:55:30 +000068 break;
Chris Lattner61b09412006-08-11 21:01:22 +000069 }
70 }
Chris Lattnera5682852006-08-07 23:03:03 +000071}
72
73SelectionDAGCSEMap::NodeID::NodeID(unsigned short ID, const void *VTList) {
74 SetOpcode(ID);
75 SetValueTypes(VTList);
76 SetOperands();
77}
78SelectionDAGCSEMap::NodeID::NodeID(unsigned short ID, const void *VTList,
79 SDOperand Op) {
80 SetOpcode(ID);
81 SetValueTypes(VTList);
82 SetOperands(Op);
83}
84SelectionDAGCSEMap::NodeID::NodeID(unsigned short ID, const void *VTList,
85 SDOperand Op1, SDOperand Op2) {
86 SetOpcode(ID);
87 SetValueTypes(VTList);
88 SetOperands(Op1, Op2);
89}
90SelectionDAGCSEMap::NodeID::NodeID(unsigned short ID, const void *VTList,
91 SDOperand Op1, SDOperand Op2,
92 SDOperand Op3) {
93 SetOpcode(ID);
94 SetValueTypes(VTList);
95 SetOperands(Op1, Op2, Op3);
96}
97SelectionDAGCSEMap::NodeID::NodeID(unsigned short ID, const void *VTList,
98 const SDOperand *OpList, unsigned N) {
99 SetOpcode(ID);
100 SetValueTypes(VTList);
101 SetOperands(OpList, N);
102}
103
104void SelectionDAGCSEMap::NodeID::AddPointer(const void *Ptr) {
105 // Note: this adds pointers to the hash using sizes and endianness that depend
106 // on the host. It doesn't matter however, because hashing on pointer values
107 // in inherently unstable. Nothing in the SelectionDAG should depend on the
108 // ordering of nodes in the CSEMap.
Chris Lattner7ed9ea82006-08-11 23:55:53 +0000109 intptr_t PtrI = (intptr_t)Ptr;
110 Bits.push_back(unsigned(PtrI));
111 if (sizeof(intptr_t) > sizeof(unsigned))
112 Bits.push_back(unsigned(uint64_t(PtrI) >> 32));
Chris Lattnera5682852006-08-07 23:03:03 +0000113}
114
115void SelectionDAGCSEMap::NodeID::AddOperand(SDOperand Op) {
116 AddPointer(Op.Val);
Chris Lattner7ed9ea82006-08-11 23:55:53 +0000117 Bits.push_back(Op.ResNo);
Chris Lattnera5682852006-08-07 23:03:03 +0000118}
119
120void SelectionDAGCSEMap::NodeID::SetOperands(const SDOperand *Ops,
121 unsigned NumOps) {
122 for (; NumOps; --NumOps, ++Ops)
123 AddOperand(*Ops);
124}
125
126
127/// ComputeHash - Compute a strong hash value for this NodeID, for lookup in
128/// the SelectionDAGCSEMap.
129unsigned SelectionDAGCSEMap::NodeID::ComputeHash() const {
Chris Lattnerdd289002006-08-12 01:07:10 +0000130 // This is adapted from SuperFastHash by Paul Hsieh.
131 unsigned Hash = Bits.size();
132 for (const unsigned *BP = &Bits[0], *E = BP+Bits.size(); BP != E; ++BP) {
133 unsigned Data = *BP;
134 Hash += Data & 0xFFFF;
135 unsigned Tmp = ((Data >> 16) << 11) ^ Hash;
136 Hash = (Hash << 16) ^ Tmp;
137 Hash += Hash >> 11;
138 }
139
140 // Force "avalanching" of final 127 bits.
141 Hash ^= Hash << 3;
142 Hash += Hash >> 5;
143 Hash ^= Hash << 4;
144 Hash += Hash >> 17;
145 Hash ^= Hash << 25;
146 Hash += Hash >> 6;
Chris Lattnera5682852006-08-07 23:03:03 +0000147 return Hash;
148}
149
150bool SelectionDAGCSEMap::NodeID::operator==(const NodeID &RHS) const {
151 if (Bits.size() != RHS.Bits.size()) return false;
Chris Lattner7ed9ea82006-08-11 23:55:53 +0000152 return memcmp(&Bits[0], &RHS.Bits[0], Bits.size()*sizeof(Bits[0])) == 0;
Chris Lattnera5682852006-08-07 23:03:03 +0000153}
154
155
156//===----------------------------------------------------------------------===//
157// SelectionDAGCSEMap Implementation
158
Chris Lattnerdd289002006-08-12 01:07:10 +0000159SelectionDAGCSEMap::SelectionDAGCSEMap() : NumNodes(0) {
Chris Lattner213a16c2006-08-14 22:19:25 +0000160 NumBuckets = 64;
Chris Lattnera5682852006-08-07 23:03:03 +0000161 Buckets = new void*[NumBuckets];
162 memset(Buckets, 0, NumBuckets*sizeof(void*));
163}
164SelectionDAGCSEMap::~SelectionDAGCSEMap() {
165 delete [] Buckets;
166}
167
168/// GetNextPtr - In order to save space, each bucket is a singly-linked-list. In
169/// order to make deletion more efficient, we make the list circular, so we can
170/// delete a node without computing its hash. The problem with this is that the
171/// start of the hash buckets are not SDNodes. If NextInBucketPtr is a bucket
172/// pointer, this method returns null: use GetBucketPtr when this happens.
173SDNode *SelectionDAGCSEMap::GetNextPtr(void *NextInBucketPtr) {
174 if (NextInBucketPtr >= Buckets && NextInBucketPtr < Buckets+NumBuckets)
175 return 0;
176 return static_cast<SDNode*>(NextInBucketPtr);
177}
178
Chris Lattner213a16c2006-08-14 22:19:25 +0000179/// GetNextPtr - This is just like the previous GetNextPtr implementation, but
180/// allows a bucket array to be specified.
181SDNode *SelectionDAGCSEMap::GetNextPtr(void *NextInBucketPtr, void **Bucks,
182 unsigned NumBuck) {
183 if (NextInBucketPtr >= Bucks && NextInBucketPtr < Bucks+NumBuck)
184 return 0;
185 return static_cast<SDNode*>(NextInBucketPtr);
186}
187
Chris Lattnera5682852006-08-07 23:03:03 +0000188void **SelectionDAGCSEMap::GetBucketPtr(void *NextInBucketPtr) {
Chris Lattner7ed9ea82006-08-11 23:55:53 +0000189 //assert(NextInBucketPtr >= Buckets && NextInBucketPtr < Buckets+NumBuckets &&
190 // "NextInBucketPtr is not a bucket ptr");
Chris Lattnera5682852006-08-07 23:03:03 +0000191 return static_cast<void**>(NextInBucketPtr);
192}
193
194/// GetBucketFor - Hash the specified node ID and return the hash bucket for the
195/// specified ID.
196void **SelectionDAGCSEMap::GetBucketFor(const NodeID &ID) const {
Chris Lattnera5682852006-08-07 23:03:03 +0000197 // NumBuckets is always a power of 2.
198 unsigned BucketNum = ID.ComputeHash() & (NumBuckets-1);
199 return Buckets+BucketNum;
200}
201
Chris Lattner213a16c2006-08-14 22:19:25 +0000202/// GrowHashTable - Double the size of the hash table and rehash everything.
203///
204void SelectionDAGCSEMap::GrowHashTable() {
205 void **OldBuckets = Buckets;
206 unsigned OldNumBuckets = NumBuckets;
207 NumBuckets <<= 1;
208
209 // Reset the node count to zero: we're going to reinsert everything.
210 NumNodes = 0;
211
212 // Clear out new buckets.
213 Buckets = new void*[NumBuckets];
214 memset(Buckets, 0, NumBuckets*sizeof(void*));
215
216 // Walk the old buckets, rehashing nodes into their new place.
217 for (unsigned i = 0; i != OldNumBuckets; ++i) {
218 void *Probe = OldBuckets[i];
219 if (!Probe) continue;
220 while (SDNode *NodeInBucket = GetNextPtr(Probe, OldBuckets, OldNumBuckets)){
221 // Figure out the next link, remove NodeInBucket from the old link.
222 Probe = NodeInBucket->getNextInBucket();
223 NodeInBucket->SetNextInBucket(0);
224
225 // Insert the node into the new bucket, after recomputing the hash.
226 InsertNode(NodeInBucket, GetBucketFor(NodeID(NodeInBucket)));
227 }
228 }
229
230 delete[] OldBuckets;
231}
232
Chris Lattnera5682852006-08-07 23:03:03 +0000233/// FindNodeOrInsertPos - Look up the node specified by ID. If it exists,
234/// return it. If not, return the insertion token that will make insertion
235/// faster.
236SDNode *SelectionDAGCSEMap::FindNodeOrInsertPos(const NodeID &ID,
237 void *&InsertPos) {
238 void **Bucket = GetBucketFor(ID);
239 void *Probe = *Bucket;
240
241 InsertPos = 0;
242
243 unsigned Opc = ID.getOpcode();
244 while (SDNode *NodeInBucket = GetNextPtr(Probe)) {
245 // If we found a node with the same opcode, it might be a matching node.
246 // Because it is in the same bucket as this one, we know the hash values
247 // match. Compute the NodeID for the possible match and do a final compare.
248 if (NodeInBucket->getOpcode() == Opc) {
249 NodeID OtherID(NodeInBucket);
250 if (OtherID == ID)
251 return NodeInBucket;
252 }
253
254 Probe = NodeInBucket->getNextInBucket();
255 }
256
257 // Didn't find the node, return null with the bucket as the InsertPos.
258 InsertPos = Bucket;
259 return 0;
260}
261
262/// InsertNode - Insert the specified node into the CSE Map, knowing that it
263/// is not already in the map. InsertPos must be obtained from
264/// FindNodeOrInsertPos.
265void SelectionDAGCSEMap::InsertNode(SDNode *N, void *InsertPos) {
Chris Lattnerdd289002006-08-12 01:07:10 +0000266 ++NumNodes;
Chris Lattner213a16c2006-08-14 22:19:25 +0000267 // Do we need to grow the hashtable?
268 if (NumNodes > NumBuckets*2) {
269 GrowHashTable();
270 InsertPos = GetBucketFor(NodeID(N));
271 }
Chris Lattnerdd289002006-08-12 01:07:10 +0000272
Chris Lattnera5682852006-08-07 23:03:03 +0000273 /// The insert position is actually a bucket pointer.
274 void **Bucket = static_cast<void**>(InsertPos);
275
276 void *Next = *Bucket;
277
278 // If this is the first insertion into this bucket, its next pointer will be
279 // null. Pretend as if it pointed to itself.
280 if (Next == 0)
281 Next = Bucket;
282
283 // Set the nodes next pointer, and make the bucket point to the node.
284 N->SetNextInBucket(Next);
285 *Bucket = N;
286}
287
288
289/// RemoveNode - Remove a node from the CSE map, returning true if one was
290/// removed or false if the node was not in the CSE map.
291bool SelectionDAGCSEMap::RemoveNode(SDNode *N) {
Chris Lattnerdd289002006-08-12 01:07:10 +0000292
Chris Lattnera5682852006-08-07 23:03:03 +0000293 // Because each bucket is a circular list, we don't need to compute N's hash
294 // to remove it. Chase around the list until we find the node (or bucket)
295 // which points to N.
296 void *Ptr = N->getNextInBucket();
297 if (Ptr == 0) return false; // Not in CSEMap.
Chris Lattnerdd289002006-08-12 01:07:10 +0000298
299 --NumNodes;
300
Chris Lattnera5682852006-08-07 23:03:03 +0000301 void *NodeNextPtr = Ptr;
302 N->SetNextInBucket(0);
303 while (1) {
304 if (SDNode *NodeInBucket = GetNextPtr(Ptr)) {
305 // Advance pointer.
306 Ptr = NodeInBucket->getNextInBucket();
307
308 // We found a node that points to N, change it to point to N's next node,
309 // removing N from the list.
310 if (Ptr == N) {
311 NodeInBucket->SetNextInBucket(NodeNextPtr);
312 return true;
313 }
314 } else {
315 void **Bucket = GetBucketPtr(Ptr);
316 Ptr = *Bucket;
317
318 // If we found that the bucket points to N, update the bucket to point to
319 // whatever is next.
320 if (Ptr == N) {
321 *Bucket = NodeNextPtr;
322 return true;
323 }
324 }
325 }
326}
327
328/// GetOrInsertSimpleNode - If there is an existing simple SDNode exactly
329/// equal to the specified node, return it. Otherwise, insert 'N' and it
330/// instead. This only works on *simple* SDNodes, not ConstantSDNode or any
331/// other classes derived from SDNode.
332SDNode *SelectionDAGCSEMap::GetOrInsertNode(SDNode *N) {
333 SelectionDAGCSEMap::NodeID ID(N);
334 void *IP;
335 if (SDNode *E = FindNodeOrInsertPos(ID, IP))
336 return E;
337 InsertNode(N, IP);
338 return N;
339}