blob: 498e9efc81b6e327fe236a1546e5d82f6c0567f5 [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"
Evan Chengd6594ae2006-09-12 21:00:35 +000015#include "llvm/CodeGen/MachineConstantPool.h"
Chris Lattnerc9f8f412006-08-11 21:55:30 +000016#include "llvm/Support/MathExtras.h"
Chris Lattnera5682852006-08-07 23:03:03 +000017using namespace llvm;
18
19//===----------------------------------------------------------------------===//
20// SelectionDAGCSEMap::NodeID Implementation
21
Chris Lattner0b3e5252006-08-15 19:11:05 +000022/// SetValueTypes - Value type lists are intern'd so we can represent them
23/// solely with their pointer.
24void SelectionDAGCSEMap::NodeID::SetValueTypes(SDVTList VTList) {
25 AddPointer(VTList.VTs);
26}
27
Chris Lattnera5682852006-08-07 23:03:03 +000028SelectionDAGCSEMap::NodeID::NodeID(SDNode *N) {
29 SetOpcode(N->getOpcode());
30 // Add the return value info.
Chris Lattner0b3e5252006-08-15 19:11:05 +000031 SetValueTypes(N->getVTList());
Chris Lattnera5682852006-08-07 23:03:03 +000032 // Add the operand info.
33 SetOperands(N->op_begin(), N->getNumOperands());
Chris Lattner61b09412006-08-11 21:01:22 +000034
35 // Handle SDNode leafs with special info.
36 if (N->getNumOperands() == 0) {
37 switch (N->getOpcode()) {
38 default: break; // Normal nodes don't need extra info.
39 case ISD::TargetConstant:
40 case ISD::Constant:
41 AddInteger(cast<ConstantSDNode>(N)->getValue());
42 break;
Chris Lattnerc9f8f412006-08-11 21:55:30 +000043 case ISD::TargetConstantFP:
44 case ISD::ConstantFP:
45 AddInteger(DoubleToBits(cast<ConstantFPSDNode>(N)->getValue()));
46 break;
Chris Lattner61b09412006-08-11 21:01:22 +000047 case ISD::TargetGlobalAddress:
48 case ISD::GlobalAddress:
49 AddPointer(cast<GlobalAddressSDNode>(N)->getGlobal());
50 AddInteger(cast<GlobalAddressSDNode>(N)->getOffset());
51 break;
52 case ISD::BasicBlock:
53 AddPointer(cast<BasicBlockSDNode>(N)->getBasicBlock());
54 break;
55 case ISD::Register:
56 AddInteger(cast<RegisterSDNode>(N)->getReg());
57 break;
58 case ISD::SRCVALUE:
59 AddPointer(cast<SrcValueSDNode>(N)->getValue());
60 AddInteger(cast<SrcValueSDNode>(N)->getOffset());
61 break;
Chris Lattnerc9f8f412006-08-11 21:55:30 +000062 case ISD::FrameIndex:
63 case ISD::TargetFrameIndex:
64 AddInteger(cast<FrameIndexSDNode>(N)->getIndex());
65 break;
66 case ISD::JumpTable:
67 case ISD::TargetJumpTable:
68 AddInteger(cast<JumpTableSDNode>(N)->getIndex());
69 break;
70 case ISD::ConstantPool:
71 case ISD::TargetConstantPool:
72 AddInteger(cast<ConstantPoolSDNode>(N)->getAlignment());
73 AddInteger(cast<ConstantPoolSDNode>(N)->getOffset());
Evan Chengd6594ae2006-09-12 21:00:35 +000074 if (cast<ConstantPoolSDNode>(N)->isMachineConstantPoolEntry())
75 cast<ConstantPoolSDNode>(N)->getMachineCPVal()->
76 AddSelectionDAGCSEId(this);
77 else
78 AddPointer(cast<ConstantPoolSDNode>(N)->getConstVal());
Chris Lattnerc9f8f412006-08-11 21:55:30 +000079 break;
Chris Lattner61b09412006-08-11 21:01:22 +000080 }
81 }
Chris Lattnera5682852006-08-07 23:03:03 +000082}
83
Chris Lattner0b3e5252006-08-15 19:11:05 +000084SelectionDAGCSEMap::NodeID::NodeID(unsigned short ID, SDVTList VTList) {
Chris Lattnera5682852006-08-07 23:03:03 +000085 SetOpcode(ID);
86 SetValueTypes(VTList);
87 SetOperands();
88}
Chris Lattner0b3e5252006-08-15 19:11:05 +000089SelectionDAGCSEMap::NodeID::NodeID(unsigned short ID, SDVTList VTList,
Chris Lattnera5682852006-08-07 23:03:03 +000090 SDOperand Op) {
91 SetOpcode(ID);
92 SetValueTypes(VTList);
93 SetOperands(Op);
94}
Chris Lattner0b3e5252006-08-15 19:11:05 +000095SelectionDAGCSEMap::NodeID::NodeID(unsigned short ID, SDVTList VTList,
Chris Lattnera5682852006-08-07 23:03:03 +000096 SDOperand Op1, SDOperand Op2) {
97 SetOpcode(ID);
98 SetValueTypes(VTList);
99 SetOperands(Op1, Op2);
100}
Chris Lattner0b3e5252006-08-15 19:11:05 +0000101SelectionDAGCSEMap::NodeID::NodeID(unsigned short ID, SDVTList VTList,
Chris Lattnera5682852006-08-07 23:03:03 +0000102 SDOperand Op1, SDOperand Op2,
103 SDOperand Op3) {
104 SetOpcode(ID);
105 SetValueTypes(VTList);
106 SetOperands(Op1, Op2, Op3);
107}
Chris Lattner0b3e5252006-08-15 19:11:05 +0000108SelectionDAGCSEMap::NodeID::NodeID(unsigned short ID, SDVTList VTList,
Chris Lattnera5682852006-08-07 23:03:03 +0000109 const SDOperand *OpList, unsigned N) {
110 SetOpcode(ID);
111 SetValueTypes(VTList);
112 SetOperands(OpList, N);
113}
114
115void SelectionDAGCSEMap::NodeID::AddPointer(const void *Ptr) {
116 // Note: this adds pointers to the hash using sizes and endianness that depend
117 // on the host. It doesn't matter however, because hashing on pointer values
118 // in inherently unstable. Nothing in the SelectionDAG should depend on the
119 // ordering of nodes in the CSEMap.
Chris Lattner7ed9ea82006-08-11 23:55:53 +0000120 intptr_t PtrI = (intptr_t)Ptr;
121 Bits.push_back(unsigned(PtrI));
122 if (sizeof(intptr_t) > sizeof(unsigned))
123 Bits.push_back(unsigned(uint64_t(PtrI) >> 32));
Chris Lattnera5682852006-08-07 23:03:03 +0000124}
125
126void SelectionDAGCSEMap::NodeID::AddOperand(SDOperand Op) {
127 AddPointer(Op.Val);
Chris Lattner7ed9ea82006-08-11 23:55:53 +0000128 Bits.push_back(Op.ResNo);
Chris Lattnera5682852006-08-07 23:03:03 +0000129}
130
131void SelectionDAGCSEMap::NodeID::SetOperands(const SDOperand *Ops,
132 unsigned NumOps) {
133 for (; NumOps; --NumOps, ++Ops)
134 AddOperand(*Ops);
135}
136
137
138/// ComputeHash - Compute a strong hash value for this NodeID, for lookup in
139/// the SelectionDAGCSEMap.
140unsigned SelectionDAGCSEMap::NodeID::ComputeHash() const {
Chris Lattnerdd289002006-08-12 01:07:10 +0000141 // This is adapted from SuperFastHash by Paul Hsieh.
142 unsigned Hash = Bits.size();
143 for (const unsigned *BP = &Bits[0], *E = BP+Bits.size(); BP != E; ++BP) {
144 unsigned Data = *BP;
145 Hash += Data & 0xFFFF;
146 unsigned Tmp = ((Data >> 16) << 11) ^ Hash;
147 Hash = (Hash << 16) ^ Tmp;
148 Hash += Hash >> 11;
149 }
150
151 // Force "avalanching" of final 127 bits.
152 Hash ^= Hash << 3;
153 Hash += Hash >> 5;
154 Hash ^= Hash << 4;
155 Hash += Hash >> 17;
156 Hash ^= Hash << 25;
157 Hash += Hash >> 6;
Chris Lattnera5682852006-08-07 23:03:03 +0000158 return Hash;
159}
160
161bool SelectionDAGCSEMap::NodeID::operator==(const NodeID &RHS) const {
162 if (Bits.size() != RHS.Bits.size()) return false;
Chris Lattner7ed9ea82006-08-11 23:55:53 +0000163 return memcmp(&Bits[0], &RHS.Bits[0], Bits.size()*sizeof(Bits[0])) == 0;
Chris Lattnera5682852006-08-07 23:03:03 +0000164}
165
166
167//===----------------------------------------------------------------------===//
168// SelectionDAGCSEMap Implementation
169
Chris Lattnerdd289002006-08-12 01:07:10 +0000170SelectionDAGCSEMap::SelectionDAGCSEMap() : NumNodes(0) {
Chris Lattner213a16c2006-08-14 22:19:25 +0000171 NumBuckets = 64;
Chris Lattnera5682852006-08-07 23:03:03 +0000172 Buckets = new void*[NumBuckets];
173 memset(Buckets, 0, NumBuckets*sizeof(void*));
174}
175SelectionDAGCSEMap::~SelectionDAGCSEMap() {
176 delete [] Buckets;
177}
178
179/// GetNextPtr - In order to save space, each bucket is a singly-linked-list. In
180/// order to make deletion more efficient, we make the list circular, so we can
181/// delete a node without computing its hash. The problem with this is that the
182/// start of the hash buckets are not SDNodes. If NextInBucketPtr is a bucket
183/// pointer, this method returns null: use GetBucketPtr when this happens.
184SDNode *SelectionDAGCSEMap::GetNextPtr(void *NextInBucketPtr) {
185 if (NextInBucketPtr >= Buckets && NextInBucketPtr < Buckets+NumBuckets)
186 return 0;
187 return static_cast<SDNode*>(NextInBucketPtr);
188}
189
Chris Lattner213a16c2006-08-14 22:19:25 +0000190/// GetNextPtr - This is just like the previous GetNextPtr implementation, but
191/// allows a bucket array to be specified.
192SDNode *SelectionDAGCSEMap::GetNextPtr(void *NextInBucketPtr, void **Bucks,
193 unsigned NumBuck) {
194 if (NextInBucketPtr >= Bucks && NextInBucketPtr < Bucks+NumBuck)
195 return 0;
196 return static_cast<SDNode*>(NextInBucketPtr);
197}
198
Chris Lattnera5682852006-08-07 23:03:03 +0000199void **SelectionDAGCSEMap::GetBucketPtr(void *NextInBucketPtr) {
Chris Lattner7ed9ea82006-08-11 23:55:53 +0000200 //assert(NextInBucketPtr >= Buckets && NextInBucketPtr < Buckets+NumBuckets &&
201 // "NextInBucketPtr is not a bucket ptr");
Chris Lattnera5682852006-08-07 23:03:03 +0000202 return static_cast<void**>(NextInBucketPtr);
203}
204
205/// GetBucketFor - Hash the specified node ID and return the hash bucket for the
206/// specified ID.
207void **SelectionDAGCSEMap::GetBucketFor(const NodeID &ID) const {
Chris Lattnera5682852006-08-07 23:03:03 +0000208 // NumBuckets is always a power of 2.
209 unsigned BucketNum = ID.ComputeHash() & (NumBuckets-1);
210 return Buckets+BucketNum;
211}
212
Chris Lattner213a16c2006-08-14 22:19:25 +0000213/// GrowHashTable - Double the size of the hash table and rehash everything.
214///
215void SelectionDAGCSEMap::GrowHashTable() {
216 void **OldBuckets = Buckets;
217 unsigned OldNumBuckets = NumBuckets;
218 NumBuckets <<= 1;
219
220 // Reset the node count to zero: we're going to reinsert everything.
221 NumNodes = 0;
222
223 // Clear out new buckets.
224 Buckets = new void*[NumBuckets];
225 memset(Buckets, 0, NumBuckets*sizeof(void*));
226
227 // Walk the old buckets, rehashing nodes into their new place.
228 for (unsigned i = 0; i != OldNumBuckets; ++i) {
229 void *Probe = OldBuckets[i];
230 if (!Probe) continue;
231 while (SDNode *NodeInBucket = GetNextPtr(Probe, OldBuckets, OldNumBuckets)){
232 // Figure out the next link, remove NodeInBucket from the old link.
233 Probe = NodeInBucket->getNextInBucket();
234 NodeInBucket->SetNextInBucket(0);
235
236 // Insert the node into the new bucket, after recomputing the hash.
237 InsertNode(NodeInBucket, GetBucketFor(NodeID(NodeInBucket)));
238 }
239 }
240
241 delete[] OldBuckets;
242}
243
Chris Lattnera5682852006-08-07 23:03:03 +0000244/// FindNodeOrInsertPos - Look up the node specified by ID. If it exists,
245/// return it. If not, return the insertion token that will make insertion
246/// faster.
247SDNode *SelectionDAGCSEMap::FindNodeOrInsertPos(const NodeID &ID,
248 void *&InsertPos) {
249 void **Bucket = GetBucketFor(ID);
250 void *Probe = *Bucket;
251
252 InsertPos = 0;
253
254 unsigned Opc = ID.getOpcode();
255 while (SDNode *NodeInBucket = GetNextPtr(Probe)) {
256 // If we found a node with the same opcode, it might be a matching node.
257 // Because it is in the same bucket as this one, we know the hash values
258 // match. Compute the NodeID for the possible match and do a final compare.
259 if (NodeInBucket->getOpcode() == Opc) {
260 NodeID OtherID(NodeInBucket);
261 if (OtherID == ID)
262 return NodeInBucket;
263 }
264
265 Probe = NodeInBucket->getNextInBucket();
266 }
267
268 // Didn't find the node, return null with the bucket as the InsertPos.
269 InsertPos = Bucket;
270 return 0;
271}
272
273/// InsertNode - Insert the specified node into the CSE Map, knowing that it
274/// is not already in the map. InsertPos must be obtained from
275/// FindNodeOrInsertPos.
276void SelectionDAGCSEMap::InsertNode(SDNode *N, void *InsertPos) {
Chris Lattnerdd289002006-08-12 01:07:10 +0000277 ++NumNodes;
Chris Lattner213a16c2006-08-14 22:19:25 +0000278 // Do we need to grow the hashtable?
279 if (NumNodes > NumBuckets*2) {
280 GrowHashTable();
281 InsertPos = GetBucketFor(NodeID(N));
282 }
Chris Lattnerdd289002006-08-12 01:07:10 +0000283
Chris Lattnera5682852006-08-07 23:03:03 +0000284 /// The insert position is actually a bucket pointer.
285 void **Bucket = static_cast<void**>(InsertPos);
286
287 void *Next = *Bucket;
288
289 // If this is the first insertion into this bucket, its next pointer will be
290 // null. Pretend as if it pointed to itself.
291 if (Next == 0)
292 Next = Bucket;
293
294 // Set the nodes next pointer, and make the bucket point to the node.
295 N->SetNextInBucket(Next);
296 *Bucket = N;
297}
298
299
300/// RemoveNode - Remove a node from the CSE map, returning true if one was
301/// removed or false if the node was not in the CSE map.
302bool SelectionDAGCSEMap::RemoveNode(SDNode *N) {
Chris Lattnerdd289002006-08-12 01:07:10 +0000303
Chris Lattnera5682852006-08-07 23:03:03 +0000304 // Because each bucket is a circular list, we don't need to compute N's hash
305 // to remove it. Chase around the list until we find the node (or bucket)
306 // which points to N.
307 void *Ptr = N->getNextInBucket();
308 if (Ptr == 0) return false; // Not in CSEMap.
Chris Lattnerdd289002006-08-12 01:07:10 +0000309
310 --NumNodes;
311
Chris Lattnera5682852006-08-07 23:03:03 +0000312 void *NodeNextPtr = Ptr;
313 N->SetNextInBucket(0);
314 while (1) {
315 if (SDNode *NodeInBucket = GetNextPtr(Ptr)) {
316 // Advance pointer.
317 Ptr = NodeInBucket->getNextInBucket();
318
319 // We found a node that points to N, change it to point to N's next node,
320 // removing N from the list.
321 if (Ptr == N) {
322 NodeInBucket->SetNextInBucket(NodeNextPtr);
323 return true;
324 }
325 } else {
326 void **Bucket = GetBucketPtr(Ptr);
327 Ptr = *Bucket;
328
329 // If we found that the bucket points to N, update the bucket to point to
330 // whatever is next.
331 if (Ptr == N) {
332 *Bucket = NodeNextPtr;
333 return true;
334 }
335 }
336 }
337}
338
339/// GetOrInsertSimpleNode - If there is an existing simple SDNode exactly
340/// equal to the specified node, return it. Otherwise, insert 'N' and it
341/// instead. This only works on *simple* SDNodes, not ConstantSDNode or any
342/// other classes derived from SDNode.
343SDNode *SelectionDAGCSEMap::GetOrInsertNode(SDNode *N) {
344 SelectionDAGCSEMap::NodeID ID(N);
345 void *IP;
346 if (SDNode *E = FindNodeOrInsertPos(ID, IP))
347 return E;
348 InsertNode(N, IP);
349 return N;
350}