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