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