blob: b42c70bb56d0de5d7b4201fc4f6de239ec850616 [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 Lattnera5682852006-08-07 23:03:03 +0000160 NumBuckets = 256;
161 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
179void **SelectionDAGCSEMap::GetBucketPtr(void *NextInBucketPtr) {
Chris Lattner7ed9ea82006-08-11 23:55:53 +0000180 //assert(NextInBucketPtr >= Buckets && NextInBucketPtr < Buckets+NumBuckets &&
181 // "NextInBucketPtr is not a bucket ptr");
Chris Lattnera5682852006-08-07 23:03:03 +0000182 return static_cast<void**>(NextInBucketPtr);
183}
184
185/// GetBucketFor - Hash the specified node ID and return the hash bucket for the
186/// specified ID.
187void **SelectionDAGCSEMap::GetBucketFor(const NodeID &ID) const {
188 // TODO: if load is high, resize hash table.
189
190 // NumBuckets is always a power of 2.
191 unsigned BucketNum = ID.ComputeHash() & (NumBuckets-1);
192 return Buckets+BucketNum;
193}
194
195/// FindNodeOrInsertPos - Look up the node specified by ID. If it exists,
196/// return it. If not, return the insertion token that will make insertion
197/// faster.
198SDNode *SelectionDAGCSEMap::FindNodeOrInsertPos(const NodeID &ID,
199 void *&InsertPos) {
200 void **Bucket = GetBucketFor(ID);
201 void *Probe = *Bucket;
202
203 InsertPos = 0;
204
205 unsigned Opc = ID.getOpcode();
206 while (SDNode *NodeInBucket = GetNextPtr(Probe)) {
207 // If we found a node with the same opcode, it might be a matching node.
208 // Because it is in the same bucket as this one, we know the hash values
209 // match. Compute the NodeID for the possible match and do a final compare.
210 if (NodeInBucket->getOpcode() == Opc) {
211 NodeID OtherID(NodeInBucket);
212 if (OtherID == ID)
213 return NodeInBucket;
214 }
215
216 Probe = NodeInBucket->getNextInBucket();
217 }
218
219 // Didn't find the node, return null with the bucket as the InsertPos.
220 InsertPos = Bucket;
221 return 0;
222}
223
224/// InsertNode - Insert the specified node into the CSE Map, knowing that it
225/// is not already in the map. InsertPos must be obtained from
226/// FindNodeOrInsertPos.
227void SelectionDAGCSEMap::InsertNode(SDNode *N, void *InsertPos) {
Chris Lattnerdd289002006-08-12 01:07:10 +0000228 ++NumNodes;
229
Chris Lattnera5682852006-08-07 23:03:03 +0000230 /// The insert position is actually a bucket pointer.
231 void **Bucket = static_cast<void**>(InsertPos);
232
233 void *Next = *Bucket;
234
235 // If this is the first insertion into this bucket, its next pointer will be
236 // null. Pretend as if it pointed to itself.
237 if (Next == 0)
238 Next = Bucket;
239
240 // Set the nodes next pointer, and make the bucket point to the node.
241 N->SetNextInBucket(Next);
242 *Bucket = N;
243}
244
245
246/// RemoveNode - Remove a node from the CSE map, returning true if one was
247/// removed or false if the node was not in the CSE map.
248bool SelectionDAGCSEMap::RemoveNode(SDNode *N) {
Chris Lattnerdd289002006-08-12 01:07:10 +0000249
Chris Lattnera5682852006-08-07 23:03:03 +0000250 // Because each bucket is a circular list, we don't need to compute N's hash
251 // to remove it. Chase around the list until we find the node (or bucket)
252 // which points to N.
253 void *Ptr = N->getNextInBucket();
254 if (Ptr == 0) return false; // Not in CSEMap.
Chris Lattnerdd289002006-08-12 01:07:10 +0000255
256 --NumNodes;
257
Chris Lattnera5682852006-08-07 23:03:03 +0000258 void *NodeNextPtr = Ptr;
259 N->SetNextInBucket(0);
260 while (1) {
261 if (SDNode *NodeInBucket = GetNextPtr(Ptr)) {
262 // Advance pointer.
263 Ptr = NodeInBucket->getNextInBucket();
264
265 // We found a node that points to N, change it to point to N's next node,
266 // removing N from the list.
267 if (Ptr == N) {
268 NodeInBucket->SetNextInBucket(NodeNextPtr);
269 return true;
270 }
271 } else {
272 void **Bucket = GetBucketPtr(Ptr);
273 Ptr = *Bucket;
274
275 // If we found that the bucket points to N, update the bucket to point to
276 // whatever is next.
277 if (Ptr == N) {
278 *Bucket = NodeNextPtr;
279 return true;
280 }
281 }
282 }
283}
284
285/// GetOrInsertSimpleNode - If there is an existing simple SDNode exactly
286/// equal to the specified node, return it. Otherwise, insert 'N' and it
287/// instead. This only works on *simple* SDNodes, not ConstantSDNode or any
288/// other classes derived from SDNode.
289SDNode *SelectionDAGCSEMap::GetOrInsertNode(SDNode *N) {
290 SelectionDAGCSEMap::NodeID ID(N);
291 void *IP;
292 if (SDNode *E = FindNodeOrInsertPos(ID, IP))
293 return E;
294 InsertNode(N, IP);
295 return N;
296}