Chris Lattner | f4066b3 | 2002-03-27 19:45:12 +0000 | [diff] [blame] | 1 | //===- FunctionRepBuilder.cpp - Build the local datastructure graph -------===// |
Chris Lattner | bb2a28f | 2002-03-26 22:39:06 +0000 | [diff] [blame] | 2 | // |
| 3 | // Build the local datastructure graph for a single method. |
| 4 | // |
| 5 | //===----------------------------------------------------------------------===// |
| 6 | |
| 7 | #include "FunctionRepBuilder.h" |
| 8 | #include "llvm/Function.h" |
| 9 | #include "llvm/iMemory.h" |
| 10 | #include "llvm/iPHINode.h" |
| 11 | #include "llvm/iOther.h" |
| 12 | #include "llvm/iTerminators.h" |
| 13 | #include "llvm/DerivedTypes.h" |
| 14 | #include "Support/STLExtras.h" |
| 15 | #include <algorithm> |
| 16 | |
| 17 | // synthesizeNode - Create a new shadow node that is to be linked into this |
| 18 | // chain.. |
| 19 | // FIXME: This should not take a FunctionRepBuilder as an argument! |
| 20 | // |
| 21 | ShadowDSNode *ShadowDSNode::synthesizeNode(const Type *Ty, |
| 22 | FunctionRepBuilder *Rep) { |
| 23 | // If we are a derived shadow node, defer to our parent to synthesize the node |
| 24 | if (ShadowParent) return ShadowParent->synthesizeNode(Ty, Rep); |
| 25 | |
| 26 | // See if we have already synthesized a node of this type... |
| 27 | for (unsigned i = 0, e = SynthNodes.size(); i != e; ++i) |
| 28 | if (SynthNodes[i].first == Ty) return SynthNodes[i].second; |
| 29 | |
| 30 | // No we haven't. Do so now and add it to our list of saved nodes... |
| 31 | ShadowDSNode *SN = new ShadowDSNode(Ty, Mod, this); |
| 32 | SynthNodes.push_back(make_pair(Ty, SN)); |
| 33 | Rep->addShadowNode(SN); |
| 34 | return SN; |
| 35 | } |
| 36 | |
| 37 | |
| 38 | |
| 39 | |
| 40 | // visitOperand - If the specified instruction operand is a global value, add |
| 41 | // a node for it... |
| 42 | // |
| 43 | void InitVisitor::visitOperand(Value *V) { |
| 44 | if (!Rep->ValueMap.count(V)) // Only process it once... |
| 45 | if (GlobalValue *GV = dyn_cast<GlobalValue>(V)) { |
| 46 | GlobalDSNode *N = new GlobalDSNode(GV); |
Chris Lattner | 1120c8b | 2002-03-28 17:56:03 +0000 | [diff] [blame] | 47 | Rep->GlobalNodes.push_back(N); |
Chris Lattner | bb2a28f | 2002-03-26 22:39:06 +0000 | [diff] [blame] | 48 | Rep->ValueMap[V].add(N); |
| 49 | Rep->addAllUsesToWorkList(GV); |
Chris Lattner | f4066b3 | 2002-03-27 19:45:12 +0000 | [diff] [blame] | 50 | |
| 51 | // FIXME: If the global variable has fields, we should add critical |
| 52 | // shadow nodes to represent them! |
Chris Lattner | bb2a28f | 2002-03-26 22:39:06 +0000 | [diff] [blame] | 53 | } |
| 54 | } |
| 55 | |
| 56 | |
| 57 | // visitCallInst - Create a call node for the callinst, and create as shadow |
| 58 | // node if the call returns a pointer value. Check to see if the call node |
| 59 | // uses any global variables... |
| 60 | // |
| 61 | void InitVisitor::visitCallInst(CallInst *CI) { |
| 62 | CallDSNode *C = new CallDSNode(CI); |
Chris Lattner | 1120c8b | 2002-03-28 17:56:03 +0000 | [diff] [blame] | 63 | Rep->CallNodes.push_back(C); |
Chris Lattner | bb2a28f | 2002-03-26 22:39:06 +0000 | [diff] [blame] | 64 | Rep->CallMap[CI] = C; |
| 65 | |
Chris Lattner | 3feaf02 | 2002-04-01 00:14:41 +0000 | [diff] [blame] | 66 | if (PointerType *PT = dyn_cast<PointerType>(CI->getType())) { |
Chris Lattner | f4066b3 | 2002-03-27 19:45:12 +0000 | [diff] [blame] | 67 | // Create a critical shadow node to represent the memory object that the |
| 68 | // return value points to... |
Chris Lattner | 3feaf02 | 2002-04-01 00:14:41 +0000 | [diff] [blame] | 69 | ShadowDSNode *Shad = new ShadowDSNode(PT->getElementType(), |
| 70 | Func->getParent(), true); |
Chris Lattner | bb2a28f | 2002-03-26 22:39:06 +0000 | [diff] [blame] | 71 | Rep->ShadowNodes.push_back(Shad); |
| 72 | |
| 73 | // The return value of the function is a pointer to the shadow value |
| 74 | // just created... |
| 75 | // |
| 76 | C->getLink(0).add(Shad); |
| 77 | |
| 78 | // The call instruction returns a pointer to the shadow block... |
| 79 | Rep->ValueMap[CI].add(Shad, CI); |
| 80 | |
| 81 | // If the call returns a value with pointer type, add all of the users |
| 82 | // of the call instruction to the work list... |
| 83 | Rep->addAllUsesToWorkList(CI); |
| 84 | } |
| 85 | |
| 86 | // Loop over all of the operands of the call instruction (except the first |
| 87 | // one), to look for global variable references... |
| 88 | // |
| 89 | for_each(CI->op_begin()+1, CI->op_end(), // Skip first arg |
| 90 | bind_obj(this, &InitVisitor::visitOperand)); |
| 91 | } |
| 92 | |
| 93 | |
| 94 | // visitAllocationInst - Create an allocation node for the allocation. Since |
| 95 | // allocation instructions do not take pointer arguments, they cannot refer to |
| 96 | // global vars... |
| 97 | // |
| 98 | void InitVisitor::visitAllocationInst(AllocationInst *AI) { |
Chris Lattner | 1120c8b | 2002-03-28 17:56:03 +0000 | [diff] [blame] | 99 | AllocDSNode *N = new AllocDSNode(AI); |
| 100 | Rep->AllocNodes.push_back(N); |
Chris Lattner | bb2a28f | 2002-03-26 22:39:06 +0000 | [diff] [blame] | 101 | |
| 102 | Rep->ValueMap[AI].add(N, AI); |
| 103 | |
| 104 | // Add all of the users of the malloc instruction to the work list... |
| 105 | Rep->addAllUsesToWorkList(AI); |
| 106 | } |
| 107 | |
| 108 | |
| 109 | // Visit all other instruction types. Here we just scan, looking for uses of |
| 110 | // global variables... |
| 111 | // |
| 112 | void InitVisitor::visitInstruction(Instruction *I) { |
| 113 | for_each(I->op_begin(), I->op_end(), |
| 114 | bind_obj(this, &InitVisitor::visitOperand)); |
| 115 | } |
| 116 | |
| 117 | |
| 118 | // addAllUsesToWorkList - Add all of the instructions users of the specified |
| 119 | // value to the work list for further processing... |
| 120 | // |
| 121 | void FunctionRepBuilder::addAllUsesToWorkList(Value *V) { |
| 122 | //cerr << "Adding all uses of " << V << "\n"; |
| 123 | for (Value::use_iterator I = V->use_begin(), E = V->use_end(); I != E; ++I) { |
| 124 | Instruction *Inst = cast<Instruction>(*I); |
| 125 | // When processing global values, it's possible that the instructions on |
| 126 | // the use list are not all in this method. Only add the instructions |
| 127 | // that _are_ in this method. |
| 128 | // |
| 129 | if (Inst->getParent()->getParent() == F->getFunction()) |
| 130 | // Only let an instruction occur on the work list once... |
| 131 | if (std::find(WorkList.begin(), WorkList.end(), Inst) == WorkList.end()) |
| 132 | WorkList.push_back(Inst); |
| 133 | } |
| 134 | } |
| 135 | |
| 136 | |
| 137 | |
| 138 | |
| 139 | void FunctionRepBuilder::initializeWorkList(Function *Func) { |
| 140 | // Add all of the arguments to the method to the graph and add all users to |
| 141 | // the worklists... |
| 142 | // |
| 143 | for (Function::ArgumentListType::iterator I = Func->getArgumentList().begin(), |
| 144 | E = Func->getArgumentList().end(); I != E; ++I) |
| 145 | // Only process arguments that are of pointer type... |
Chris Lattner | 3feaf02 | 2002-04-01 00:14:41 +0000 | [diff] [blame] | 146 | if (PointerType *PT = dyn_cast<PointerType>((*I)->getType())) { |
Chris Lattner | bb2a28f | 2002-03-26 22:39:06 +0000 | [diff] [blame] | 147 | ArgDSNode *Arg = new ArgDSNode(*I); |
Chris Lattner | 1120c8b | 2002-03-28 17:56:03 +0000 | [diff] [blame] | 148 | ArgNodes.push_back(Arg); |
Chris Lattner | bb2a28f | 2002-03-26 22:39:06 +0000 | [diff] [blame] | 149 | |
Chris Lattner | f4066b3 | 2002-03-27 19:45:12 +0000 | [diff] [blame] | 150 | // Add a critical shadow value for it to represent what it is pointing |
Chris Lattner | bb2a28f | 2002-03-26 22:39:06 +0000 | [diff] [blame] | 151 | // to and add this to the value map... |
Chris Lattner | 3feaf02 | 2002-04-01 00:14:41 +0000 | [diff] [blame] | 152 | ShadowDSNode *Shad = new ShadowDSNode(PT->getElementType(), |
| 153 | Func->getParent(), true); |
Chris Lattner | bb2a28f | 2002-03-26 22:39:06 +0000 | [diff] [blame] | 154 | ShadowNodes.push_back(Shad); |
| 155 | ValueMap[*I].add(PointerVal(Shad), *I); |
| 156 | |
| 157 | // The value of the argument is the shadow value... |
| 158 | Arg->getLink(0).add(Shad); |
| 159 | |
| 160 | // Make sure that all users of the argument are processed... |
| 161 | addAllUsesToWorkList(*I); |
| 162 | } |
| 163 | |
| 164 | // Iterate over the instructions in the method. Create nodes for malloc and |
| 165 | // call instructions. Add all uses of these to the worklist of instructions |
| 166 | // to process. |
| 167 | // |
| 168 | InitVisitor IV(this, Func); |
| 169 | IV.visit(Func); |
| 170 | } |
| 171 | |
| 172 | |
| 173 | |
| 174 | |
| 175 | PointerVal FunctionRepBuilder::getIndexedPointerDest(const PointerVal &InP, |
| 176 | const MemAccessInst *MAI) { |
| 177 | unsigned Index = InP.Index; |
| 178 | const Type *SrcTy = MAI->getPointerOperand()->getType(); |
| 179 | |
| 180 | for (MemAccessInst::const_op_iterator I = MAI->idx_begin(), |
| 181 | E = MAI->idx_end(); I != E; ++I) |
| 182 | if ((*I)->getType() == Type::UByteTy) { // Look for struct indices... |
| 183 | StructType *STy = cast<StructType>(SrcTy); |
| 184 | unsigned StructIdx = cast<ConstantUInt>(*I)->getValue(); |
| 185 | for (unsigned i = 0; i != StructIdx; ++i) |
| 186 | Index += countPointerFields(STy->getContainedType(i)); |
| 187 | |
| 188 | // Advance SrcTy to be the new element type... |
| 189 | SrcTy = STy->getContainedType(StructIdx); |
| 190 | } else { |
| 191 | // Otherwise, stepping into array or initial pointer, just increment type |
| 192 | SrcTy = cast<SequentialType>(SrcTy)->getElementType(); |
| 193 | } |
| 194 | |
| 195 | return PointerVal(InP.Node, Index); |
| 196 | } |
| 197 | |
| 198 | static PointerValSet &getField(const PointerVal &DestPtr) { |
| 199 | assert(DestPtr.Node != 0); |
| 200 | |
| 201 | return DestPtr.Node->getLink(DestPtr.Index); |
| 202 | } |
| 203 | |
| 204 | |
| 205 | // Reprocessing a GEP instruction is the result of the pointer operand |
| 206 | // changing. This means that the set of possible values for the GEP |
| 207 | // needs to be expanded. |
| 208 | // |
| 209 | void FunctionRepBuilder::visitGetElementPtrInst(GetElementPtrInst *GEP) { |
| 210 | PointerValSet &GEPPVS = ValueMap[GEP]; // PointerValSet to expand |
| 211 | |
| 212 | // Get the input pointer val set... |
| 213 | const PointerValSet &SrcPVS = ValueMap[GEP->getOperand(0)]; |
| 214 | |
| 215 | bool Changed = false; // Process each input value... propogating it. |
| 216 | for (unsigned i = 0, e = SrcPVS.size(); i != e; ++i) { |
| 217 | // Calculate where the resulting pointer would point based on an |
| 218 | // input of 'Val' as the pointer type... and add it to our outgoing |
| 219 | // value set. Keep track of whether or not we actually changed |
| 220 | // anything. |
| 221 | // |
| 222 | Changed |= GEPPVS.add(getIndexedPointerDest(SrcPVS[i], GEP)); |
| 223 | } |
| 224 | |
| 225 | // If our current value set changed, notify all of the users of our |
| 226 | // value. |
| 227 | // |
| 228 | if (Changed) addAllUsesToWorkList(GEP); |
| 229 | } |
| 230 | |
| 231 | void FunctionRepBuilder::visitReturnInst(ReturnInst *RI) { |
| 232 | RetNode.add(ValueMap[RI->getOperand(0)]); |
| 233 | } |
| 234 | |
| 235 | void FunctionRepBuilder::visitLoadInst(LoadInst *LI) { |
| 236 | // Only loads that return pointers are interesting... |
| 237 | if (!isa<PointerType>(LI->getType())) return; |
| 238 | const PointerType *DestTy = cast<PointerType>(LI->getType()); |
| 239 | |
| 240 | const PointerValSet &SrcPVS = ValueMap[LI->getOperand(0)]; |
| 241 | PointerValSet &LIPVS = ValueMap[LI]; |
| 242 | |
| 243 | bool Changed = false; |
| 244 | for (unsigned si = 0, se = SrcPVS.size(); si != se; ++si) { |
| 245 | PointerVal Ptr = getIndexedPointerDest(SrcPVS[si], LI); |
| 246 | PointerValSet &Field = getField(Ptr); |
| 247 | |
| 248 | if (Field.size()) { // Field loaded wasn't null? |
| 249 | Changed |= LIPVS.add(Field); |
Chris Lattner | 3feaf02 | 2002-04-01 00:14:41 +0000 | [diff] [blame] | 250 | } else if (ShadowDSNode *Shad = dyn_cast<ShadowDSNode>(Ptr.Node)) { |
Chris Lattner | bb2a28f | 2002-03-26 22:39:06 +0000 | [diff] [blame] | 251 | // If we are loading a null field out of a shadow node, we need to |
| 252 | // synthesize a new shadow node and link it in... |
| 253 | // |
Chris Lattner | bb2a28f | 2002-03-26 22:39:06 +0000 | [diff] [blame] | 254 | ShadowDSNode *SynthNode = |
| 255 | Shad->synthesizeNode(DestTy->getElementType(), this); |
| 256 | Field.add(SynthNode); |
| 257 | |
| 258 | Changed |= LIPVS.add(Field); |
| 259 | } |
| 260 | } |
| 261 | |
| 262 | if (Changed) addAllUsesToWorkList(LI); |
| 263 | } |
| 264 | |
| 265 | void FunctionRepBuilder::visitStoreInst(StoreInst *SI) { |
| 266 | // The only stores that are interesting are stores the store pointers |
| 267 | // into data structures... |
| 268 | // |
| 269 | if (!isa<PointerType>(SI->getOperand(0)->getType())) return; |
Chris Lattner | e0d1d1a | 2002-04-01 00:45:09 +0000 | [diff] [blame^] | 270 | if (!ValueMap.count(SI->getOperand(0))) return; // Src scalar has no values! |
Chris Lattner | bb2a28f | 2002-03-26 22:39:06 +0000 | [diff] [blame] | 271 | |
| 272 | const PointerValSet &SrcPVS = ValueMap[SI->getOperand(0)]; |
| 273 | const PointerValSet &PtrPVS = ValueMap[SI->getOperand(1)]; |
| 274 | |
| 275 | for (unsigned si = 0, se = SrcPVS.size(); si != se; ++si) { |
| 276 | const PointerVal &SrcPtr = SrcPVS[si]; |
| 277 | for (unsigned pi = 0, pe = PtrPVS.size(); pi != pe; ++pi) { |
| 278 | PointerVal Dest = getIndexedPointerDest(PtrPVS[pi], SI); |
| 279 | |
| 280 | #if 0 |
| 281 | cerr << "Setting Dest:\n"; |
| 282 | Dest.print(cerr); |
| 283 | cerr << "to point to Src:\n"; |
| 284 | SrcPtr.print(cerr); |
| 285 | #endif |
| 286 | |
| 287 | // Add SrcPtr into the Dest field... |
| 288 | if (getField(Dest).add(SrcPtr)) { |
| 289 | // If we modified the dest field, then invalidate everyone that points |
| 290 | // to Dest. |
| 291 | const std::vector<Value*> &Ptrs = Dest.Node->getPointers(); |
| 292 | for (unsigned i = 0, e = Ptrs.size(); i != e; ++i) |
| 293 | addAllUsesToWorkList(Ptrs[i]); |
| 294 | } |
| 295 | } |
| 296 | } |
| 297 | } |
| 298 | |
| 299 | void FunctionRepBuilder::visitCallInst(CallInst *CI) { |
| 300 | CallDSNode *DSN = CallMap[CI]; |
| 301 | |
| 302 | unsigned PtrNum = 0, i = 0; |
| 303 | if (isa<Function>(CI->getOperand(0))) |
| 304 | ++i; // Not an Indirect function call? Skip the function pointer... |
| 305 | |
| 306 | for (unsigned e = CI->getNumOperands(); i != e; ++i) |
| 307 | if (isa<PointerType>(CI->getOperand(i)->getType())) |
| 308 | DSN->addArgValue(PtrNum++, ValueMap[CI->getOperand(i)]); |
| 309 | } |
| 310 | |
| 311 | void FunctionRepBuilder::visitPHINode(PHINode *PN) { |
| 312 | assert(isa<PointerType>(PN->getType()) && "Should only update ptr phis"); |
| 313 | |
| 314 | PointerValSet &PN_PVS = ValueMap[PN]; |
| 315 | bool Changed = false; |
| 316 | for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) |
| 317 | Changed |= PN_PVS.add(ValueMap[PN->getIncomingValue(i)], |
| 318 | PN->getIncomingValue(i)); |
| 319 | |
| 320 | if (Changed) addAllUsesToWorkList(PN); |
| 321 | } |
| 322 | |
| 323 | |
| 324 | |
| 325 | |
| 326 | // FunctionDSGraph constructor - Perform the global analysis to determine |
| 327 | // what the data structure usage behavior or a method looks like. |
| 328 | // |
| 329 | FunctionDSGraph::FunctionDSGraph(Function *F) : Func(F) { |
| 330 | FunctionRepBuilder Builder(this); |
Chris Lattner | 1120c8b | 2002-03-28 17:56:03 +0000 | [diff] [blame] | 331 | ArgNodes = Builder.getArgNodes(); |
| 332 | AllocNodes = Builder.getAllocNodes(); |
Chris Lattner | bb2a28f | 2002-03-26 22:39:06 +0000 | [diff] [blame] | 333 | ShadowNodes = Builder.getShadowNodes(); |
Chris Lattner | 1120c8b | 2002-03-28 17:56:03 +0000 | [diff] [blame] | 334 | GlobalNodes = Builder.getGlobalNodes(); |
| 335 | CallNodes = Builder.getCallNodes(); |
| 336 | RetNode = Builder.getRetNode(); |
| 337 | ValueMap = Builder.getValueMap(); |
Chris Lattner | f4066b3 | 2002-03-27 19:45:12 +0000 | [diff] [blame] | 338 | |
| 339 | bool Changed = true; |
| 340 | while (Changed) { |
| 341 | // Eliminate shadow nodes that are not distinguishable from some other |
| 342 | // node in the graph... |
| 343 | // |
Chris Lattner | 7d093d4 | 2002-03-28 19:16:48 +0000 | [diff] [blame] | 344 | Changed = UnlinkUndistinguishableNodes(); |
Chris Lattner | f4066b3 | 2002-03-27 19:45:12 +0000 | [diff] [blame] | 345 | |
| 346 | // Eliminate shadow nodes that are now extraneous due to linking... |
Chris Lattner | 7d093d4 | 2002-03-28 19:16:48 +0000 | [diff] [blame] | 347 | Changed |= RemoveUnreachableNodes(); |
Chris Lattner | f4066b3 | 2002-03-27 19:45:12 +0000 | [diff] [blame] | 348 | } |
Chris Lattner | bb2a28f | 2002-03-26 22:39:06 +0000 | [diff] [blame] | 349 | } |
| 350 | |