void GraphBuilder::visitGetElementPtrInst(User &GEP) { // // Ensure that the indexed pointer has a DSNode. // DSNodeHandle Value = getValueDest(GEP.getOperand(0)); if (Value.isNull()) Value = createNode(); // // There are a few quick and easy cases to handle. If the DSNode of the // indexed pointer is already folded, then we know that the result of the // GEP will have the same offset into the same DSNode // as the indexed pointer. // if (!Value.isNull() && Value.getNode()->isNodeCompletelyFolded()) { setDestTo(GEP, Value); return; } // // Okay, no easy way out. Calculate the offset into the object being // indexed. // int Offset = 0; // FIXME: I am not sure if the code below is completely correct (especially // if we start doing fancy analysis on non-constant array indices). // What if the array is indexed using a larger index than its declared // size? Does the LLVM verifier catch such issues? // // // Determine the offset (in bytes) between the result of the GEP and the // GEP's pointer operand. // // Note: All of these subscripts are indexing INTO the elements we have... // // FIXME: We can do better for array indexing. First, if the array index is // constant, we can determine how much farther we're moving the // pointer. Second, we can try to use the results of other analysis // passes (e.g., ScalarEvolution) to find min/max values to do less // conservative type-folding. // for (gep_type_iterator I = gep_type_begin(GEP), E = gep_type_end(GEP); I != E; ++I) if (StructType *STy = dyn_cast<StructType>(*I)) { // indexing into a structure // next index must be a constant const ConstantInt* CUI = cast<ConstantInt>(I.getOperand()); int FieldNo = CUI->getSExtValue(); // increment the offset by the actual byte offset being accessed unsigned requiredSize = TD.getTypeAllocSize(STy) + Value.getOffset() + Offset; if(!Value.getNode()->isArrayNode() || Value.getNode()->getSize() <= 0){ if (requiredSize > Value.getNode()->getSize()) Value.getNode()->growSize(requiredSize); } Offset += (unsigned)TD.getStructLayout(STy)->getElementOffset(FieldNo); if(TypeInferenceOptimize) { if(ArrayType* AT = dyn_cast<ArrayType>(STy->getTypeAtIndex(FieldNo))) { Value.getNode()->mergeTypeInfo(AT, Value.getOffset() + Offset); if((++I) == E) { break; } // Check if we are still indexing into an array. // We only record the topmost array type of any nested array. // Keep skipping indexes till we reach a non-array type. // J is the type of the next index. // Uncomment the line below to get all the nested types. gep_type_iterator J = I; while(isa<ArrayType>(*(++J))) { // Value.getNode()->mergeTypeInfo(AT1, Value.getOffset() + Offset); if((++I) == E) { break; } J = I; } if((I) == E) { break; } } } } else if(ArrayType *ATy = dyn_cast<ArrayType>(*I)) { // indexing into an array. Value.getNode()->setArrayMarker(); Type *CurTy = ATy->getElementType(); if(!isa<ArrayType>(CurTy) && Value.getNode()->getSize() <= 0) { Value.getNode()->growSize(TD.getTypeAllocSize(CurTy)); } else if(isa<ArrayType>(CurTy) && Value.getNode()->getSize() <= 0){ Type *ETy = (cast<ArrayType>(CurTy))->getElementType(); while(isa<ArrayType>(ETy)) { ETy = (cast<ArrayType>(ETy))->getElementType(); } Value.getNode()->growSize(TD.getTypeAllocSize(ETy)); } // Find if the DSNode belongs to the array // If not fold. if((Value.getOffset() || Offset != 0) || (!isa<ArrayType>(CurTy) && (Value.getNode()->getSize() != TD.getTypeAllocSize(CurTy)))) { Value.getNode()->foldNodeCompletely(); Value.getNode(); Offset = 0; break; } } else if (const PointerType *PtrTy = dyn_cast<PointerType>(*I)) { Type *CurTy = PtrTy->getElementType(); // // Unless we're advancing the pointer by zero bytes via array indexing, // fold the node (i.e., mark it type-unknown) and indicate that we're // indexing zero bytes into the object. // // Note that we break out of the loop if we fold the node. Once // something is folded, all values within it are considered to alias. // if (!isa<Constant>(I.getOperand()) || !cast<Constant>(I.getOperand())->isNullValue()) { Value.getNode()->setArrayMarker(); if(!isa<ArrayType>(CurTy) && Value.getNode()->getSize() <= 0){ Value.getNode()->growSize(TD.getTypeAllocSize(CurTy)); } else if(isa<ArrayType>(CurTy) && Value.getNode()->getSize() <= 0){ Type *ETy = (cast<ArrayType>(CurTy))->getElementType(); while(isa<ArrayType>(ETy)) { ETy = (cast<ArrayType>(ETy))->getElementType(); } Value.getNode()->growSize(TD.getTypeAllocSize(ETy)); } if(Value.getOffset() || Offset != 0 || (!isa<ArrayType>(CurTy) && (Value.getNode()->getSize() != TD.getTypeAllocSize(CurTy)))) { Value.getNode()->foldNodeCompletely(); Value.getNode(); Offset = 0; break; } } } // Add in the offset calculated... Value.setOffset(Value.getOffset()+Offset); // Check the offset DSNode *N = Value.getNode(); if (N) N->checkOffsetFoldIfNeeded(Value.getOffset()); // Value is now the pointer we want to GEP to be... setDestTo(GEP, Value); }