blob: 0a02333522a1216b594ccddb9a69676705b63814 [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 {
129 // FIXME: this hash function sucks.
130 unsigned Hash = 0;
131 for (unsigned i = 0, e = Bits.size(); i != e; ++i)
Chris Lattner7ed9ea82006-08-11 23:55:53 +0000132 Hash = Hash+Bits[i];
Chris Lattnera5682852006-08-07 23:03:03 +0000133 return Hash;
134}
135
136bool SelectionDAGCSEMap::NodeID::operator==(const NodeID &RHS) const {
137 if (Bits.size() != RHS.Bits.size()) return false;
Chris Lattner7ed9ea82006-08-11 23:55:53 +0000138 return memcmp(&Bits[0], &RHS.Bits[0], Bits.size()*sizeof(Bits[0])) == 0;
Chris Lattnera5682852006-08-07 23:03:03 +0000139}
140
141
142//===----------------------------------------------------------------------===//
143// SelectionDAGCSEMap Implementation
144
145SelectionDAGCSEMap::SelectionDAGCSEMap() {
146 NumBuckets = 256;
147 Buckets = new void*[NumBuckets];
148 memset(Buckets, 0, NumBuckets*sizeof(void*));
149}
150SelectionDAGCSEMap::~SelectionDAGCSEMap() {
151 delete [] Buckets;
152}
153
154/// GetNextPtr - In order to save space, each bucket is a singly-linked-list. In
155/// order to make deletion more efficient, we make the list circular, so we can
156/// delete a node without computing its hash. The problem with this is that the
157/// start of the hash buckets are not SDNodes. If NextInBucketPtr is a bucket
158/// pointer, this method returns null: use GetBucketPtr when this happens.
159SDNode *SelectionDAGCSEMap::GetNextPtr(void *NextInBucketPtr) {
160 if (NextInBucketPtr >= Buckets && NextInBucketPtr < Buckets+NumBuckets)
161 return 0;
162 return static_cast<SDNode*>(NextInBucketPtr);
163}
164
165void **SelectionDAGCSEMap::GetBucketPtr(void *NextInBucketPtr) {
Chris Lattner7ed9ea82006-08-11 23:55:53 +0000166 //assert(NextInBucketPtr >= Buckets && NextInBucketPtr < Buckets+NumBuckets &&
167 // "NextInBucketPtr is not a bucket ptr");
Chris Lattnera5682852006-08-07 23:03:03 +0000168 return static_cast<void**>(NextInBucketPtr);
169}
170
171/// GetBucketFor - Hash the specified node ID and return the hash bucket for the
172/// specified ID.
173void **SelectionDAGCSEMap::GetBucketFor(const NodeID &ID) const {
174 // TODO: if load is high, resize hash table.
175
176 // NumBuckets is always a power of 2.
177 unsigned BucketNum = ID.ComputeHash() & (NumBuckets-1);
178 return Buckets+BucketNum;
179}
180
181/// FindNodeOrInsertPos - Look up the node specified by ID. If it exists,
182/// return it. If not, return the insertion token that will make insertion
183/// faster.
184SDNode *SelectionDAGCSEMap::FindNodeOrInsertPos(const NodeID &ID,
185 void *&InsertPos) {
186 void **Bucket = GetBucketFor(ID);
187 void *Probe = *Bucket;
188
189 InsertPos = 0;
190
191 unsigned Opc = ID.getOpcode();
192 while (SDNode *NodeInBucket = GetNextPtr(Probe)) {
193 // If we found a node with the same opcode, it might be a matching node.
194 // Because it is in the same bucket as this one, we know the hash values
195 // match. Compute the NodeID for the possible match and do a final compare.
196 if (NodeInBucket->getOpcode() == Opc) {
197 NodeID OtherID(NodeInBucket);
198 if (OtherID == ID)
199 return NodeInBucket;
200 }
201
202 Probe = NodeInBucket->getNextInBucket();
203 }
204
205 // Didn't find the node, return null with the bucket as the InsertPos.
206 InsertPos = Bucket;
207 return 0;
208}
209
210/// InsertNode - Insert the specified node into the CSE Map, knowing that it
211/// is not already in the map. InsertPos must be obtained from
212/// FindNodeOrInsertPos.
213void SelectionDAGCSEMap::InsertNode(SDNode *N, void *InsertPos) {
214 /// The insert position is actually a bucket pointer.
215 void **Bucket = static_cast<void**>(InsertPos);
216
217 void *Next = *Bucket;
218
219 // If this is the first insertion into this bucket, its next pointer will be
220 // null. Pretend as if it pointed to itself.
221 if (Next == 0)
222 Next = Bucket;
223
224 // Set the nodes next pointer, and make the bucket point to the node.
225 N->SetNextInBucket(Next);
226 *Bucket = N;
227}
228
229
230/// RemoveNode - Remove a node from the CSE map, returning true if one was
231/// removed or false if the node was not in the CSE map.
232bool SelectionDAGCSEMap::RemoveNode(SDNode *N) {
233 // Because each bucket is a circular list, we don't need to compute N's hash
234 // to remove it. Chase around the list until we find the node (or bucket)
235 // which points to N.
236 void *Ptr = N->getNextInBucket();
237 if (Ptr == 0) return false; // Not in CSEMap.
238
239 void *NodeNextPtr = Ptr;
240 N->SetNextInBucket(0);
241 while (1) {
242 if (SDNode *NodeInBucket = GetNextPtr(Ptr)) {
243 // Advance pointer.
244 Ptr = NodeInBucket->getNextInBucket();
245
246 // We found a node that points to N, change it to point to N's next node,
247 // removing N from the list.
248 if (Ptr == N) {
249 NodeInBucket->SetNextInBucket(NodeNextPtr);
250 return true;
251 }
252 } else {
253 void **Bucket = GetBucketPtr(Ptr);
254 Ptr = *Bucket;
255
256 // If we found that the bucket points to N, update the bucket to point to
257 // whatever is next.
258 if (Ptr == N) {
259 *Bucket = NodeNextPtr;
260 return true;
261 }
262 }
263 }
264}
265
266/// GetOrInsertSimpleNode - If there is an existing simple SDNode exactly
267/// equal to the specified node, return it. Otherwise, insert 'N' and it
268/// instead. This only works on *simple* SDNodes, not ConstantSDNode or any
269/// other classes derived from SDNode.
270SDNode *SelectionDAGCSEMap::GetOrInsertNode(SDNode *N) {
271 SelectionDAGCSEMap::NodeID ID(N);
272 void *IP;
273 if (SDNode *E = FindNodeOrInsertPos(ID, IP))
274 return E;
275 InsertNode(N, IP);
276 return N;
277}