blob: de5302adeaf71112cca0fabe5f8f79fd06edfccf [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());
67 break;
Chris Lattner61b09412006-08-11 21:01:22 +000068 }
69 }
Chris Lattnera5682852006-08-07 23:03:03 +000070}
71
72SelectionDAGCSEMap::NodeID::NodeID(unsigned short ID, const void *VTList) {
73 SetOpcode(ID);
74 SetValueTypes(VTList);
75 SetOperands();
76}
77SelectionDAGCSEMap::NodeID::NodeID(unsigned short ID, const void *VTList,
78 SDOperand Op) {
79 SetOpcode(ID);
80 SetValueTypes(VTList);
81 SetOperands(Op);
82}
83SelectionDAGCSEMap::NodeID::NodeID(unsigned short ID, const void *VTList,
84 SDOperand Op1, SDOperand Op2) {
85 SetOpcode(ID);
86 SetValueTypes(VTList);
87 SetOperands(Op1, Op2);
88}
89SelectionDAGCSEMap::NodeID::NodeID(unsigned short ID, const void *VTList,
90 SDOperand Op1, SDOperand Op2,
91 SDOperand Op3) {
92 SetOpcode(ID);
93 SetValueTypes(VTList);
94 SetOperands(Op1, Op2, Op3);
95}
96SelectionDAGCSEMap::NodeID::NodeID(unsigned short ID, const void *VTList,
97 const SDOperand *OpList, unsigned N) {
98 SetOpcode(ID);
99 SetValueTypes(VTList);
100 SetOperands(OpList, N);
101}
102
103void SelectionDAGCSEMap::NodeID::AddPointer(const void *Ptr) {
104 // Note: this adds pointers to the hash using sizes and endianness that depend
105 // on the host. It doesn't matter however, because hashing on pointer values
106 // in inherently unstable. Nothing in the SelectionDAG should depend on the
107 // ordering of nodes in the CSEMap.
Chris Lattner7ed9ea82006-08-11 23:55:53 +0000108 intptr_t PtrI = (intptr_t)Ptr;
109 Bits.push_back(unsigned(PtrI));
110 if (sizeof(intptr_t) > sizeof(unsigned))
111 Bits.push_back(unsigned(uint64_t(PtrI) >> 32));
Chris Lattnera5682852006-08-07 23:03:03 +0000112}
113
114void SelectionDAGCSEMap::NodeID::AddOperand(SDOperand Op) {
115 AddPointer(Op.Val);
Chris Lattner7ed9ea82006-08-11 23:55:53 +0000116 Bits.push_back(Op.ResNo);
Chris Lattnera5682852006-08-07 23:03:03 +0000117}
118
119void SelectionDAGCSEMap::NodeID::SetOperands(const SDOperand *Ops,
120 unsigned NumOps) {
121 for (; NumOps; --NumOps, ++Ops)
122 AddOperand(*Ops);
123}
124
125
126/// ComputeHash - Compute a strong hash value for this NodeID, for lookup in
127/// the SelectionDAGCSEMap.
128unsigned SelectionDAGCSEMap::NodeID::ComputeHash() const {
Chris Lattnerdd289002006-08-12 01:07:10 +0000129 // This is adapted from SuperFastHash by Paul Hsieh.
130 unsigned Hash = Bits.size();
131 for (const unsigned *BP = &Bits[0], *E = BP+Bits.size(); BP != E; ++BP) {
132 unsigned Data = *BP;
133 Hash += Data & 0xFFFF;
134 unsigned Tmp = ((Data >> 16) << 11) ^ Hash;
135 Hash = (Hash << 16) ^ Tmp;
136 Hash += Hash >> 11;
137 }
138
139 // Force "avalanching" of final 127 bits.
140 Hash ^= Hash << 3;
141 Hash += Hash >> 5;
142 Hash ^= Hash << 4;
143 Hash += Hash >> 17;
144 Hash ^= Hash << 25;
145 Hash += Hash >> 6;
Chris Lattnera5682852006-08-07 23:03:03 +0000146 return Hash;
147}
148
149bool SelectionDAGCSEMap::NodeID::operator==(const NodeID &RHS) const {
150 if (Bits.size() != RHS.Bits.size()) return false;
Chris Lattner7ed9ea82006-08-11 23:55:53 +0000151 return memcmp(&Bits[0], &RHS.Bits[0], Bits.size()*sizeof(Bits[0])) == 0;
Chris Lattnera5682852006-08-07 23:03:03 +0000152}
153
154
155//===----------------------------------------------------------------------===//
156// SelectionDAGCSEMap Implementation
157
Chris Lattnerdd289002006-08-12 01:07:10 +0000158SelectionDAGCSEMap::SelectionDAGCSEMap() : NumNodes(0) {
Chris Lattnera5682852006-08-07 23:03:03 +0000159 NumBuckets = 256;
160 Buckets = new void*[NumBuckets];
161 memset(Buckets, 0, NumBuckets*sizeof(void*));
162}
163SelectionDAGCSEMap::~SelectionDAGCSEMap() {
164 delete [] Buckets;
165}
166
167/// GetNextPtr - In order to save space, each bucket is a singly-linked-list. In
168/// order to make deletion more efficient, we make the list circular, so we can
169/// delete a node without computing its hash. The problem with this is that the
170/// start of the hash buckets are not SDNodes. If NextInBucketPtr is a bucket
171/// pointer, this method returns null: use GetBucketPtr when this happens.
172SDNode *SelectionDAGCSEMap::GetNextPtr(void *NextInBucketPtr) {
173 if (NextInBucketPtr >= Buckets && NextInBucketPtr < Buckets+NumBuckets)
174 return 0;
175 return static_cast<SDNode*>(NextInBucketPtr);
176}
177
178void **SelectionDAGCSEMap::GetBucketPtr(void *NextInBucketPtr) {
Chris Lattner7ed9ea82006-08-11 23:55:53 +0000179 //assert(NextInBucketPtr >= Buckets && NextInBucketPtr < Buckets+NumBuckets &&
180 // "NextInBucketPtr is not a bucket ptr");
Chris Lattnera5682852006-08-07 23:03:03 +0000181 return static_cast<void**>(NextInBucketPtr);
182}
183
184/// GetBucketFor - Hash the specified node ID and return the hash bucket for the
185/// specified ID.
186void **SelectionDAGCSEMap::GetBucketFor(const NodeID &ID) const {
187 // TODO: if load is high, resize hash table.
188
189 // NumBuckets is always a power of 2.
190 unsigned BucketNum = ID.ComputeHash() & (NumBuckets-1);
191 return Buckets+BucketNum;
192}
193
194/// FindNodeOrInsertPos - Look up the node specified by ID. If it exists,
195/// return it. If not, return the insertion token that will make insertion
196/// faster.
197SDNode *SelectionDAGCSEMap::FindNodeOrInsertPos(const NodeID &ID,
198 void *&InsertPos) {
199 void **Bucket = GetBucketFor(ID);
200 void *Probe = *Bucket;
201
202 InsertPos = 0;
203
204 unsigned Opc = ID.getOpcode();
205 while (SDNode *NodeInBucket = GetNextPtr(Probe)) {
206 // If we found a node with the same opcode, it might be a matching node.
207 // Because it is in the same bucket as this one, we know the hash values
208 // match. Compute the NodeID for the possible match and do a final compare.
209 if (NodeInBucket->getOpcode() == Opc) {
210 NodeID OtherID(NodeInBucket);
211 if (OtherID == ID)
212 return NodeInBucket;
213 }
214
215 Probe = NodeInBucket->getNextInBucket();
216 }
217
218 // Didn't find the node, return null with the bucket as the InsertPos.
219 InsertPos = Bucket;
220 return 0;
221}
222
223/// InsertNode - Insert the specified node into the CSE Map, knowing that it
224/// is not already in the map. InsertPos must be obtained from
225/// FindNodeOrInsertPos.
226void SelectionDAGCSEMap::InsertNode(SDNode *N, void *InsertPos) {
Chris Lattnerdd289002006-08-12 01:07:10 +0000227 ++NumNodes;
228
Chris Lattnera5682852006-08-07 23:03:03 +0000229 /// The insert position is actually a bucket pointer.
230 void **Bucket = static_cast<void**>(InsertPos);
231
232 void *Next = *Bucket;
233
234 // If this is the first insertion into this bucket, its next pointer will be
235 // null. Pretend as if it pointed to itself.
236 if (Next == 0)
237 Next = Bucket;
238
239 // Set the nodes next pointer, and make the bucket point to the node.
240 N->SetNextInBucket(Next);
241 *Bucket = N;
242}
243
244
245/// RemoveNode - Remove a node from the CSE map, returning true if one was
246/// removed or false if the node was not in the CSE map.
247bool SelectionDAGCSEMap::RemoveNode(SDNode *N) {
Chris Lattnerdd289002006-08-12 01:07:10 +0000248
Chris Lattnera5682852006-08-07 23:03:03 +0000249 // Because each bucket is a circular list, we don't need to compute N's hash
250 // to remove it. Chase around the list until we find the node (or bucket)
251 // which points to N.
252 void *Ptr = N->getNextInBucket();
253 if (Ptr == 0) return false; // Not in CSEMap.
Chris Lattnerdd289002006-08-12 01:07:10 +0000254
255 --NumNodes;
256
Chris Lattnera5682852006-08-07 23:03:03 +0000257 void *NodeNextPtr = Ptr;
258 N->SetNextInBucket(0);
259 while (1) {
260 if (SDNode *NodeInBucket = GetNextPtr(Ptr)) {
261 // Advance pointer.
262 Ptr = NodeInBucket->getNextInBucket();
263
264 // We found a node that points to N, change it to point to N's next node,
265 // removing N from the list.
266 if (Ptr == N) {
267 NodeInBucket->SetNextInBucket(NodeNextPtr);
268 return true;
269 }
270 } else {
271 void **Bucket = GetBucketPtr(Ptr);
272 Ptr = *Bucket;
273
274 // If we found that the bucket points to N, update the bucket to point to
275 // whatever is next.
276 if (Ptr == N) {
277 *Bucket = NodeNextPtr;
278 return true;
279 }
280 }
281 }
282}
283
284/// GetOrInsertSimpleNode - If there is an existing simple SDNode exactly
285/// equal to the specified node, return it. Otherwise, insert 'N' and it
286/// instead. This only works on *simple* SDNodes, not ConstantSDNode or any
287/// other classes derived from SDNode.
288SDNode *SelectionDAGCSEMap::GetOrInsertNode(SDNode *N) {
289 SelectionDAGCSEMap::NodeID ID(N);
290 void *IP;
291 if (SDNode *E = FindNodeOrInsertPos(ID, IP))
292 return E;
293 InsertNode(N, IP);
294 return N;
295}