diff options
| author | Qin Zhao <zhaoqin@google.com> | 2016-06-10 22:28:55 +0000 |
|---|---|---|
| committer | Qin Zhao <zhaoqin@google.com> | 2016-06-10 22:28:55 +0000 |
| commit | bc8fbeacf31c574a4fce48cbbbb4688da506aa6f (patch) | |
| tree | 66c8f24fb07a8a429280f7cb815488c1534fd63c | |
| parent | 3f199664419785005845d8ea95ee65a6e533b53d (diff) | |
| download | bcm5719-llvm-bc8fbeacf31c574a4fce48cbbbb4688da506aa6f.tar.gz bcm5719-llvm-bc8fbeacf31c574a4fce48cbbbb4688da506aa6f.zip | |
[esan|cfrag] Handle complex GEP instr in the cfrag tool
Summary:
Iterates all (except the first and the last) operands within each GEP
instruction for instrumentation.
Adds test struct_field_gep.ll.
Reviewers: aizatsky
Subscribers: vitalybuka, zhaoqin, kcc, eugenis, bruening, llvm-commits
Differential Revision: http://reviews.llvm.org/D21242
llvm-svn: 272442
| -rw-r--r-- | llvm/lib/Transforms/Instrumentation/EfficiencySanitizer.cpp | 77 | ||||
| -rw-r--r-- | llvm/test/Instrumentation/EfficiencySanitizer/struct_field_gep.ll | 38 |
2 files changed, 80 insertions, 35 deletions
diff --git a/llvm/lib/Transforms/Instrumentation/EfficiencySanitizer.cpp b/llvm/lib/Transforms/Instrumentation/EfficiencySanitizer.cpp index 83ae3d516f8..40a9fce7b0b 100644 --- a/llvm/lib/Transforms/Instrumentation/EfficiencySanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/EfficiencySanitizer.cpp @@ -656,45 +656,52 @@ bool EfficiencySanitizer::instrumentMemIntrinsic(MemIntrinsic *MI) { bool EfficiencySanitizer::instrumentGetElementPtr(Instruction *I, Module &M) { GetElementPtrInst *GepInst = dyn_cast<GetElementPtrInst>(I); - if (GepInst == nullptr || !isa<StructType>(GepInst->getSourceElementType()) || - StructTyMap.count(GepInst->getSourceElementType()) == 0 || - !GepInst->hasAllConstantIndices() || - // Only handle simple struct field GEP. - GepInst->getNumIndices() != 2) { + bool Res = false; + if (GepInst == nullptr || GepInst->getNumIndices() == 1) { ++NumIgnoredGEPs; return false; } - StructType *StructTy = dyn_cast<StructType>(GepInst->getSourceElementType()); - if (shouldIgnoreStructType(StructTy)) { - ++NumIgnoredGEPs; - return false; + Type *SourceTy = GepInst->getSourceElementType(); + // Iterate all (except the first and the last) idx within each GEP instruction + // for possible nested struct field address calculation. + for (unsigned i = 1; i < GepInst->getNumIndices(); ++i) { + SmallVector<Value *, 8> IdxVec(GepInst->idx_begin(), + GepInst->idx_begin() + i); + StructType *StructTy = dyn_cast<StructType>( + GetElementPtrInst::getIndexedType(SourceTy, IdxVec)); + if (StructTy == nullptr || shouldIgnoreStructType(StructTy) || + StructTyMap.count(StructTy) == 0) + continue; + // Get the StructTy's subfield index. + ConstantInt *Idx = dyn_cast<ConstantInt>(GepInst->getOperand(i+1)); + if (Idx == nullptr || Idx->getZExtValue() > StructTy->getNumElements()) + continue; + GlobalVariable *CounterArray = StructTyMap[StructTy]; + if (CounterArray == nullptr) + return false; + IRBuilder<> IRB(I); + Constant *Indices[2]; + // Xref http://llvm.org/docs/LangRef.html#i-getelementptr and + // http://llvm.org/docs/GetElementPtr.html. + // The first index of the GEP instruction steps through the first operand, + // i.e., the array itself. + Indices[0] = ConstantInt::get(IRB.getInt32Ty(), 0); + // The second index is the index within the array. + Indices[1] = ConstantInt::get(IRB.getInt32Ty(), Idx->getZExtValue()); + Constant *Counter = + ConstantExpr::getGetElementPtr( + ArrayType::get(IRB.getInt64Ty(), StructTy->getNumElements()), + CounterArray, Indices); + Value *Load = IRB.CreateLoad(Counter); + IRB.CreateStore(IRB.CreateAdd(Load, ConstantInt::get(IRB.getInt64Ty(), 1)), + Counter); + Res = true; } - ++NumInstrumentedGEPs; - // Use the last index as the index within the struct. - ConstantInt *Idx = dyn_cast<ConstantInt>(GepInst->getOperand(2)); - if (Idx == nullptr || Idx->getZExtValue() > StructTy->getNumElements()) - return false; - - GlobalVariable *CounterArray = StructTyMap[StructTy]; - if (CounterArray == nullptr) - return false; - IRBuilder<> IRB(I); - Constant *Indices[2]; - // Xref http://llvm.org/docs/LangRef.html#i-getelementptr and - // http://llvm.org/docs/GetElementPtr.html. - // The first index of the GEP instruction steps through the first operand, - // i.e., the array itself. - Indices[0] = ConstantInt::get(IRB.getInt32Ty(), 0); - // The second index is the index within the array. - Indices[1] = ConstantInt::get(IRB.getInt32Ty(), Idx->getZExtValue()); - Constant *Counter = - ConstantExpr::getGetElementPtr(ArrayType::get(IRB.getInt64Ty(), - StructTy->getNumElements()), - CounterArray, Indices); - Value *Load = IRB.CreateLoad(Counter); - IRB.CreateStore(IRB.CreateAdd(Load, ConstantInt::get(IRB.getInt64Ty(), 1)), - Counter); - return true; + if (Res) + ++NumInstrumentedGEPs; + else + ++NumIgnoredGEPs; + return Res; } int EfficiencySanitizer::getMemoryAccessFuncIndex(Value *Addr, diff --git a/llvm/test/Instrumentation/EfficiencySanitizer/struct_field_gep.ll b/llvm/test/Instrumentation/EfficiencySanitizer/struct_field_gep.ll new file mode 100644 index 00000000000..5365df4273e --- /dev/null +++ b/llvm/test/Instrumentation/EfficiencySanitizer/struct_field_gep.ll @@ -0,0 +1,38 @@ +; Test the complex GetElementPtr instruction handling in the EfficiencySanitizer +; cache fragmentation tool. +; +; RUN: opt < %s -esan -esan-cache-frag -S | FileCheck %s + +; Code from http://llvm.org/docs/LangRef.html#getelementptr-instruction +; struct RT { +; char A; +; int B[10][20]; +; char C; +; }; +; struct ST { +; int X; +; double Y; +; struct RT Z; +; }; +; +; int *foo(struct ST *s) { +; return &s[1].Z.B[5][13]; +; } + +%struct.RT = type { i8, [10 x [20 x i32]], i8 } +%struct.ST = type { i32, double, %struct.RT } + +define i32* @foo(%struct.ST* %s) nounwind uwtable readnone optsize ssp { +entry: + %arrayidx = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 1, i32 2, i32 1, i64 5, i64 13 + ret i32* %arrayidx +} + +; CHECK: %0 = load i64, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.ST#3#13#3#11", i32 0, i32 2) +; CHECK-NEXT: %1 = add i64 %0, 1 +; CHECK-NEXT: store i64 %1, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.ST#3#13#3#11", i32 0, i32 2) +; CHECK-NEXT: %2 = load i64, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.RT#3#11#14#11", i32 0, i32 1) +; CHECK-NEXT: %3 = add i64 %2, 1 +; CHECK-NEXT: store i64 %3, i64* getelementptr inbounds ([3 x i64], [3 x i64]* @"struct.RT#3#11#14#11", i32 0, i32 1) +; CHECK-NEXT: %arrayidx = getelementptr inbounds %struct.ST, %struct.ST* %s, i64 1, i32 2, i32 1, i64 5, i64 13 +; CHECK-NEXT: ret i32* %arrayidx |

