diff options
author | Evan Cheng <evan.cheng@apple.com> | 2008-06-30 07:31:25 +0000 |
---|---|---|
committer | Evan Cheng <evan.cheng@apple.com> | 2008-06-30 07:31:25 +0000 |
commit | 0ff39b3feb10477c224138156941234f5fa46f58 (patch) | |
tree | 20267b5f7f46defb6c887c64b9b6e6af5ec59c85 /lib | |
parent | 2ca698df93421327a459987b33b045756cb47d4d (diff) | |
download | external_llvm-0ff39b3feb10477c224138156941234f5fa46f58.zip external_llvm-0ff39b3feb10477c224138156941234f5fa46f58.tar.gz external_llvm-0ff39b3feb10477c224138156941234f5fa46f58.tar.bz2 |
- Re-apply 52748 and friends with fix. GetConstantStringInfo() returns an empty string for ConstantAggregateZero case which surprises selectiondag.
- Correctly handle memcpy from constant string which is zero-initialized.
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@52891 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Analysis/ValueTracking.cpp | 100 | ||||
-rw-r--r-- | lib/CodeGen/MachineModuleInfo.cpp | 5 | ||||
-rw-r--r-- | lib/CodeGen/SelectionDAG/SelectionDAG.cpp | 63 | ||||
-rw-r--r-- | lib/Debugger/ProgramInfo.cpp | 10 | ||||
-rw-r--r-- | lib/Transforms/Scalar/InstructionCombining.cpp | 4 | ||||
-rw-r--r-- | lib/Transforms/Scalar/SimplifyLibCalls.cpp | 83 | ||||
-rw-r--r-- | lib/VMCore/Constants.cpp | 42 | ||||
-rw-r--r-- | lib/VMCore/IntrinsicInst.cpp | 13 |
8 files changed, 156 insertions, 164 deletions
diff --git a/lib/Analysis/ValueTracking.cpp b/lib/Analysis/ValueTracking.cpp index 32a77e6..e7e291f 100644 --- a/lib/Analysis/ValueTracking.cpp +++ b/lib/Analysis/ValueTracking.cpp @@ -15,6 +15,7 @@ #include "llvm/Analysis/ValueTracking.h" #include "llvm/Constants.h" #include "llvm/Instructions.h" +#include "llvm/GlobalVariable.h" #include "llvm/IntrinsicInst.h" #include "llvm/Target/TargetData.h" #include "llvm/Support/GetElementPtrTypeIterator.h" @@ -930,3 +931,102 @@ Value *llvm::FindInsertedValue(Value *V, const unsigned *idx_begin, // or load instruction) return 0; } + +/// GetConstantStringInfo - This function computes the length of a +/// null-terminated C string pointed to by V. If successful, it returns true +/// and returns the string in Str. If unsuccessful, it returns false. +bool llvm::GetConstantStringInfo(Value *V, std::string &Str, uint64_t Offset, + bool StopAtNul) { + // If V is NULL then return false; + if (V == NULL) return false; + + // Look through bitcast instructions. + if (BitCastInst *BCI = dyn_cast<BitCastInst>(V)) + return GetConstantStringInfo(BCI->getOperand(0), Str, Offset, StopAtNul); + + // If the value is not a GEP instruction nor a constant expression with a + // GEP instruction, then return false because ConstantArray can't occur + // any other way + User *GEP = 0; + if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(V)) { + GEP = GEPI; + } else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(V)) { + if (CE->getOpcode() == Instruction::BitCast) + return GetConstantStringInfo(CE->getOperand(0), Str, Offset, StopAtNul); + if (CE->getOpcode() != Instruction::GetElementPtr) + return false; + GEP = CE; + } + + if (GEP) { + // Make sure the GEP has exactly three arguments. + if (GEP->getNumOperands() != 3) + return false; + + // Make sure the index-ee is a pointer to array of i8. + const PointerType *PT = cast<PointerType>(GEP->getOperand(0)->getType()); + const ArrayType *AT = dyn_cast<ArrayType>(PT->getElementType()); + if (AT == 0 || AT->getElementType() != Type::Int8Ty) + return false; + + // Check to make sure that the first operand of the GEP is an integer and + // has value 0 so that we are sure we're indexing into the initializer. + ConstantInt *FirstIdx = dyn_cast<ConstantInt>(GEP->getOperand(1)); + if (FirstIdx == 0 || !FirstIdx->isZero()) + return false; + + // If the second index isn't a ConstantInt, then this is a variable index + // into the array. If this occurs, we can't say anything meaningful about + // the string. + uint64_t StartIdx = 0; + if (ConstantInt *CI = dyn_cast<ConstantInt>(GEP->getOperand(2))) + StartIdx = CI->getZExtValue(); + else + return false; + return GetConstantStringInfo(GEP->getOperand(0), Str, StartIdx+Offset, + StopAtNul); + } + + // The GEP instruction, constant or instruction, must reference a global + // variable that is a constant and is initialized. The referenced constant + // initializer is the array that we'll use for optimization. + GlobalVariable* GV = dyn_cast<GlobalVariable>(V); + if (!GV || !GV->isConstant() || !GV->hasInitializer()) + return false; + Constant *GlobalInit = GV->getInitializer(); + + // Handle the ConstantAggregateZero case + if (isa<ConstantAggregateZero>(GlobalInit)) { + // This is a degenerate case. The initializer is constant zero so the + // length of the string must be zero. + Str.clear(); + return true; + } + + // Must be a Constant Array + ConstantArray *Array = dyn_cast<ConstantArray>(GlobalInit); + if (Array == 0 || Array->getType()->getElementType() != Type::Int8Ty) + return false; + + // Get the number of elements in the array + uint64_t NumElts = Array->getType()->getNumElements(); + + if (Offset > NumElts) + return false; + + // Traverse the constant array from 'Offset' which is the place the GEP refers + // to in the array. + Str.reserve(NumElts-Offset); + for (unsigned i = Offset; i != NumElts; ++i) { + Constant *Elt = Array->getOperand(i); + ConstantInt *CI = dyn_cast<ConstantInt>(Elt); + if (!CI) // This array isn't suitable, non-int initializer. + return false; + if (StopAtNul && CI->isZero()) + return true; // we found end of string, success! + Str += (char)CI->getZExtValue(); + } + + // The array isn't null terminated, but maybe this is a memcpy, not a strcpy. + return true; +} diff --git a/lib/CodeGen/MachineModuleInfo.cpp b/lib/CodeGen/MachineModuleInfo.cpp index 123ad6d..52737a6 100644 --- a/lib/CodeGen/MachineModuleInfo.cpp +++ b/lib/CodeGen/MachineModuleInfo.cpp @@ -10,6 +10,7 @@ #include "llvm/CodeGen/MachineModuleInfo.h" #include "llvm/Constants.h" +#include "llvm/Analysis/ValueTracking.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineLocation.h" @@ -206,7 +207,9 @@ public: } virtual void Apply(std::string &Field) { Constant *C = CI->getOperand(I++); - Field = C->getStringValue(); + // Fills in the string if it succeeds + if (!GetConstantStringInfo(C, Field)) + Field.clear(); } virtual void Apply(DebugInfoDesc *&Field) { Constant *C = CI->getOperand(I++); diff --git a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index f1c2ecf..023be5c 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/Constants.h" +#include "llvm/Analysis/ValueTracking.h" #include "llvm/GlobalAlias.h" #include "llvm/GlobalVariable.h" #include "llvm/Intrinsics.h" @@ -747,18 +748,14 @@ SDOperand SelectionDAG::getString(const std::string &Val) { } SDOperand SelectionDAG::getConstant(uint64_t Val, MVT VT, bool isT) { - MVT EltVT = - VT.isVector() ? VT.getVectorElementType() : VT; - + MVT EltVT = VT.isVector() ? VT.getVectorElementType() : VT; return getConstant(APInt(EltVT.getSizeInBits(), Val), VT, isT); } SDOperand SelectionDAG::getConstant(const APInt &Val, MVT VT, bool isT) { assert(VT.isInteger() && "Cannot create FP integer constant!"); - MVT EltVT = - VT.isVector() ? VT.getVectorElementType() : VT; - + MVT EltVT = VT.isVector() ? VT.getVectorElementType() : VT; assert(Val.getBitWidth() == EltVT.getSizeInBits() && "APInt size does not match type size!"); @@ -2554,6 +2551,16 @@ static SDOperand getMemsetValue(SDOperand Value, MVT VT, SelectionDAG &DAG) { static SDOperand getMemsetStringVal(MVT VT, SelectionDAG &DAG, const TargetLowering &TLI, std::string &Str, unsigned Offset) { + // Handle vector with all elements zero. + if (Str.empty()) { + if (VT.isInteger()) + return DAG.getConstant(0, VT); + unsigned NumElts = VT.getVectorNumElements(); + MVT EltVT = (VT.getVectorElementType() == MVT::f32) ? MVT::i32 : MVT::i64; + return DAG.getNode(ISD::BIT_CONVERT, VT, + DAG.getConstant(0, MVT::getVectorVT(EltVT, NumElts))); + } + assert(!VT.isVector() && "Can't handle vector type here!"); unsigned NumBits = VT.getSizeInBits(); unsigned MSB = NumBits / 8; @@ -2577,8 +2584,7 @@ static SDOperand getMemBasePlusOffset(SDOperand Base, unsigned Offset, /// isMemSrcFromString - Returns true if memcpy source is a string constant. /// -static bool isMemSrcFromString(SDOperand Src, std::string &Str, - uint64_t &SrcOff) { +static bool isMemSrcFromString(SDOperand Src, std::string &Str) { unsigned SrcDelta = 0; GlobalAddressSDNode *G = NULL; if (Src.getOpcode() == ISD::GlobalAddress) @@ -2593,13 +2599,8 @@ static bool isMemSrcFromString(SDOperand Src, std::string &Str, return false; GlobalVariable *GV = dyn_cast<GlobalVariable>(G->getGlobal()); - if (GV && GV->isConstant()) { - Str = GV->getStringValue(false); - if (!Str.empty()) { - SrcOff += SrcDelta; - return true; - } - } + if (GV && GetConstantStringInfo(GV, Str, SrcDelta, false)) + return true; return false; } @@ -2611,14 +2612,12 @@ static bool MeetsMaxMemopRequirement(std::vector<MVT> &MemOps, SDOperand Dst, SDOperand Src, unsigned Limit, uint64_t Size, unsigned &Align, + std::string &Str, bool &isSrcStr, SelectionDAG &DAG, const TargetLowering &TLI) { - bool AllowUnalign = TLI.allowsUnalignedMemoryAccesses(); - - std::string Str; - uint64_t SrcOff = 0; - bool isSrcStr = isMemSrcFromString(Src, Str, SrcOff); + isSrcStr = isMemSrcFromString(Src, Str); bool isSrcConst = isa<ConstantSDNode>(Src); + bool AllowUnalign = TLI.allowsUnalignedMemoryAccesses(); MVT VT= TLI.getOptimalMemOpType(Size, Align, isSrcConst, isSrcStr); if (VT != MVT::iAny) { unsigned NewAlign = (unsigned) @@ -2707,26 +2706,28 @@ static SDOperand getMemcpyLoadsAndStores(SelectionDAG &DAG, if (!AlwaysInline) Limit = TLI.getMaxStoresPerMemcpy(); unsigned DstAlign = Align; // Destination alignment can change. + std::string Str; + bool CopyFromStr; if (!MeetsMaxMemopRequirement(MemOps, Dst, Src, Limit, Size, DstAlign, - DAG, TLI)) + Str, CopyFromStr, DAG, TLI)) return SDOperand(); - std::string Str; - uint64_t SrcOff = 0, DstOff = 0; - bool CopyFromStr = isMemSrcFromString(Src, Str, SrcOff); + bool isZeroStr = CopyFromStr && Str.empty(); SmallVector<SDOperand, 8> OutChains; unsigned NumMemOps = MemOps.size(); + uint64_t SrcOff = 0, DstOff = 0; for (unsigned i = 0; i < NumMemOps; i++) { MVT VT = MemOps[i]; unsigned VTSize = VT.getSizeInBits() / 8; SDOperand Value, Store; - if (CopyFromStr && !VT.isVector()) { + if (CopyFromStr && (isZeroStr || !VT.isVector())) { // It's unlikely a store of a vector immediate can be done in a single // instruction. It would require a load from a constantpool first. - // FIXME: Handle cases where store of vector immediate is done in a - // single instruction. + // We also handle store a vector with all zero's. + // FIXME: Handle other cases where store of vector immediate is done in + // a single instruction. Value = getMemsetStringVal(VT, DAG, TLI, Str, SrcOff); Store = DAG.getStore(Chain, Value, getMemBasePlusOffset(Dst, DstOff, DAG), @@ -2763,8 +2764,10 @@ static SDOperand getMemmoveLoadsAndStores(SelectionDAG &DAG, if (!AlwaysInline) Limit = TLI.getMaxStoresPerMemmove(); unsigned DstAlign = Align; // Destination alignment can change. + std::string Str; + bool CopyFromStr; if (!MeetsMaxMemopRequirement(MemOps, Dst, Src, Limit, Size, DstAlign, - DAG, TLI)) + Str, CopyFromStr, DAG, TLI)) return SDOperand(); uint64_t SrcOff = 0, DstOff = 0; @@ -2814,8 +2817,10 @@ static SDOperand getMemsetStores(SelectionDAG &DAG, // Expand memset to a series of load/store ops if the size operand // falls below a certain threshold. std::vector<MVT> MemOps; + std::string Str; + bool CopyFromStr; if (!MeetsMaxMemopRequirement(MemOps, Dst, Src, TLI.getMaxStoresPerMemset(), - Size, Align, DAG, TLI)) + Size, Align, Str, CopyFromStr, DAG, TLI)) return SDOperand(); SmallVector<SDOperand, 8> OutChains; diff --git a/lib/Debugger/ProgramInfo.cpp b/lib/Debugger/ProgramInfo.cpp index e4380ea..408704d 100644 --- a/lib/Debugger/ProgramInfo.cpp +++ b/lib/Debugger/ProgramInfo.cpp @@ -14,6 +14,7 @@ #include "llvm/Debugger/ProgramInfo.h" #include "llvm/Constants.h" +#include "llvm/Analysis/ValueTracking.h" #include "llvm/DerivedTypes.h" #include "llvm/Intrinsics.h" #include "llvm/IntrinsicInst.h" @@ -115,8 +116,10 @@ SourceFileInfo::SourceFileInfo(const GlobalVariable *Desc, if (ConstantInt *CUI = dyn_cast<ConstantInt>(CS->getOperand(1))) Version = CUI->getZExtValue(); - BaseName = CS->getOperand(3)->getStringValue(); - Directory = CS->getOperand(4)->getStringValue(); + if (!GetConstantStringInfo(CS->getOperand(3), BaseName)) + BaseName = ""; + if (!GetConstantStringInfo(CS->getOperand(4), Directory)) + Directory = ""; } } @@ -156,7 +159,8 @@ SourceFunctionInfo::SourceFunctionInfo(ProgramInfo &PI, SourceFile = &PI.getSourceFile(GV); // Entry #2 is the function name. - Name = CS->getOperand(2)->getStringValue(); + if (!GetConstantStringInfo(CS->getOperand(2), Name)) + Name = ""; } } diff --git a/lib/Transforms/Scalar/InstructionCombining.cpp b/lib/Transforms/Scalar/InstructionCombining.cpp index d45eb99..5d75489 100644 --- a/lib/Transforms/Scalar/InstructionCombining.cpp +++ b/lib/Transforms/Scalar/InstructionCombining.cpp @@ -9973,8 +9973,8 @@ static Instruction *InstCombineLoadCast(InstCombiner &IC, LoadInst &LI, if (ConstantExpr *CE = dyn_cast<ConstantExpr>(CI)) { // Instead of loading constant c string, use corresponding integer value // directly if string length is small enough. - const std::string &Str = CE->getOperand(0)->getStringValue(); - if (!Str.empty()) { + std::string Str; + if (GetConstantStringInfo(CE->getOperand(0), Str) && !Str.empty()) { unsigned len = Str.length(); const Type *Ty = cast<PointerType>(CE->getType())->getElementType(); unsigned numBits = Ty->getPrimitiveSizeInBits(); diff --git a/lib/Transforms/Scalar/SimplifyLibCalls.cpp b/lib/Transforms/Scalar/SimplifyLibCalls.cpp index 79ec3d9..6bc6ad4 100644 --- a/lib/Transforms/Scalar/SimplifyLibCalls.cpp +++ b/lib/Transforms/Scalar/SimplifyLibCalls.cpp @@ -23,6 +23,7 @@ #include "llvm/Module.h" #include "llvm/Pass.h" #include "llvm/Support/IRBuilder.h" +#include "llvm/Analysis/ValueTracking.h" #include "llvm/Target/TargetData.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/StringMap.h" @@ -229,88 +230,6 @@ void LibCallOptimization::EmitFWrite(Value *Ptr, Value *Size, Value *File, // Helper Functions //===----------------------------------------------------------------------===// -/// GetConstantStringInfo - This function computes the length of a -/// null-terminated C string pointed to by V. If successful, it returns true -/// and returns the string in Str. If unsuccessful, it returns false. -static bool GetConstantStringInfo(Value *V, std::string &Str) { - // Look bitcast instructions. - if (BitCastInst *BCI = dyn_cast<BitCastInst>(V)) - return GetConstantStringInfo(BCI->getOperand(0), Str); - - // If the value is not a GEP instruction nor a constant expression with a - // GEP instruction, then return false because ConstantArray can't occur - // any other way - User *GEP = 0; - if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(V)) { - GEP = GEPI; - } else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(V)) { - if (CE->getOpcode() != Instruction::GetElementPtr) - return false; - GEP = CE; - } else { - return false; - } - - // Make sure the GEP has exactly three arguments. - if (GEP->getNumOperands() != 3) - return false; - - // Check to make sure that the first operand of the GEP is an integer and - // has value 0 so that we are sure we're indexing into the initializer. - if (ConstantInt *Idx = dyn_cast<ConstantInt>(GEP->getOperand(1))) { - if (!Idx->isZero()) - return false; - } else - return false; - - // If the second index isn't a ConstantInt, then this is a variable index - // into the array. If this occurs, we can't say anything meaningful about - // the string. - uint64_t StartIdx = 0; - if (ConstantInt *CI = dyn_cast<ConstantInt>(GEP->getOperand(2))) - StartIdx = CI->getZExtValue(); - else - return false; - - // The GEP instruction, constant or instruction, must reference a global - // variable that is a constant and is initialized. The referenced constant - // initializer is the array that we'll use for optimization. - GlobalVariable* GV = dyn_cast<GlobalVariable>(GEP->getOperand(0)); - if (!GV || !GV->isConstant() || !GV->hasInitializer()) - return false; - Constant *GlobalInit = GV->getInitializer(); - - // Handle the ConstantAggregateZero case - if (isa<ConstantAggregateZero>(GlobalInit)) { - // This is a degenerate case. The initializer is constant zero so the - // length of the string must be zero. - Str.clear(); - return true; - } - - // Must be a Constant Array - ConstantArray *Array = dyn_cast<ConstantArray>(GlobalInit); - if (Array == 0 || Array->getType()->getElementType() != Type::Int8Ty) - return false; - - // Get the number of elements in the array - uint64_t NumElts = Array->getType()->getNumElements(); - - // Traverse the constant array from StartIdx (derived above) which is - // the place the GEP refers to in the array. - for (unsigned i = StartIdx; i < NumElts; ++i) { - Constant *Elt = Array->getOperand(i); - ConstantInt *CI = dyn_cast<ConstantInt>(Elt); - if (!CI) // This array isn't suitable, non-int initializer. - return false; - if (CI->isZero()) - return true; // we found end of string, success! - Str += (char)CI->getZExtValue(); - } - - return false; // The array isn't null terminated. -} - /// GetStringLengthH - If we can compute the length of the string pointed to by /// the specified pointer, return 'len+1'. If we can't, return 0. static uint64_t GetStringLengthH(Value *V, SmallPtrSet<PHINode*, 32> &PHIs) { diff --git a/lib/VMCore/Constants.cpp b/lib/VMCore/Constants.cpp index b9976a7..7a08b5f 100644 --- a/lib/VMCore/Constants.cpp +++ b/lib/VMCore/Constants.cpp @@ -2658,44 +2658,4 @@ void ConstantExpr::replaceUsesOfWithOnConstant(Value *From, Value *ToV, // Delete the old constant! destroyConstant(); -} - - -/// getStringValue - Turn an LLVM constant pointer that eventually points to a -/// global into a string value. Return an empty string if we can't do it. -/// Parameter Chop determines if the result is chopped at the first null -/// terminator. -/// -std::string Constant::getStringValue(bool Chop, unsigned Offset) { - if (GlobalVariable *GV = dyn_cast<GlobalVariable>(this)) { - if (GV->hasInitializer() && isa<ConstantArray>(GV->getInitializer())) { - ConstantArray *Init = cast<ConstantArray>(GV->getInitializer()); - if (Init->isString()) { - std::string Result = Init->getAsString(); - if (Offset < Result.size()) { - // If we are pointing INTO The string, erase the beginning... - Result.erase(Result.begin(), Result.begin()+Offset); - - // Take off the null terminator, and any string fragments after it. - if (Chop) { - std::string::size_type NullPos = Result.find_first_of((char)0); - if (NullPos != std::string::npos) - Result.erase(Result.begin()+NullPos, Result.end()); - } - return Result; - } - } - } - } else if (ConstantExpr *CE = dyn_cast<ConstantExpr>(this)) { - if (CE->getOpcode() == Instruction::GetElementPtr) { - // Turn a gep into the specified offset. - if (CE->getNumOperands() == 3 && - cast<Constant>(CE->getOperand(1))->isNullValue() && - isa<ConstantInt>(CE->getOperand(2))) { - Offset += cast<ConstantInt>(CE->getOperand(2))->getZExtValue(); - return CE->getOperand(0)->getStringValue(Chop, Offset); - } - } - } - return ""; -} +}
\ No newline at end of file diff --git a/lib/VMCore/IntrinsicInst.cpp b/lib/VMCore/IntrinsicInst.cpp index eca6062..6bd9431 100644 --- a/lib/VMCore/IntrinsicInst.cpp +++ b/lib/VMCore/IntrinsicInst.cpp @@ -28,6 +28,7 @@ #include "llvm/IntrinsicInst.h" #include "llvm/Constants.h" #include "llvm/GlobalVariable.h" +#include "llvm/Analysis/ValueTracking.h" #include "llvm/CodeGen/MachineDebugInfoDesc.h" #include "llvm/CodeGen/MachineModuleInfo.h" using namespace llvm; @@ -58,20 +59,20 @@ Value *DbgInfoIntrinsic::StripCast(Value *C) { /// DbgStopPointInst - This represents the llvm.dbg.stoppoint instruction. /// -std::string DbgStopPointInst::getFileName() const { +Value *DbgStopPointInst::getFileName() const { // Once the operand indices are verified, update this assert assert(LLVMDebugVersion == (6 << 16) && "Verify operand indices"); GlobalVariable *GV = cast<GlobalVariable>(getContext()); - if (!GV->hasInitializer()) return ""; + if (!GV->hasInitializer()) return NULL; ConstantStruct *CS = cast<ConstantStruct>(GV->getInitializer()); - return CS->getOperand(3)->getStringValue(); + return CS->getOperand(4); } -std::string DbgStopPointInst::getDirectory() const { +Value *DbgStopPointInst::getDirectory() const { // Once the operand indices are verified, update this assert assert(LLVMDebugVersion == (6 << 16) && "Verify operand indices"); GlobalVariable *GV = cast<GlobalVariable>(getContext()); - if (!GV->hasInitializer()) return ""; + if (!GV->hasInitializer()) return NULL; ConstantStruct *CS = cast<ConstantStruct>(GV->getInitializer()); - return CS->getOperand(4)->getStringValue(); + return CS->getOperand(4); } |