[esan|cfrag] Add the struct field offset array in StructInfo

Summary:
Adds the struct field offset array in struct StructInfo.

Updates test struct_field_count_basic.ll.

Reviewers: aizatsky

Subscribers: llvm-commits, bruening, eugenis, kcc, zhaoqin, vitalybuka

Differential Revision: http://reviews.llvm.org/D21192

llvm-svn: 272362
diff --git a/llvm/lib/Transforms/Instrumentation/EfficiencySanitizer.cpp b/llvm/lib/Transforms/Instrumentation/EfficiencySanitizer.cpp
index 63391b3..83ae3d5 100644
--- a/llvm/lib/Transforms/Instrumentation/EfficiencySanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/EfficiencySanitizer.cpp
@@ -158,8 +158,9 @@
   bool shouldIgnoreStructType(StructType *StructTy);
   void createStructCounterName(
       StructType *StructTy, SmallString<MaxStructCounterNameSize> &NameStr);
-  GlobalVariable *createCacheFragInfoGV(Module &M, Constant *UnitName);
-  Constant *createEsanInitToolInfoArg(Module &M);
+  GlobalVariable *createCacheFragInfoGV(Module &M, const DataLayout &DL,
+                                        Constant *UnitName);
+  Constant *createEsanInitToolInfoArg(Module &M, const DataLayout &DL);
   void createDestructor(Module &M, Constant *ToolInfoArg);
   bool runOnFunction(Function &F, Module &M);
   bool instrumentLoadOrStore(Instruction *I, const DataLayout &DL);
@@ -287,24 +288,28 @@
 
 // Create the global variable for the cache-fragmentation tool.
 GlobalVariable *EfficiencySanitizer::createCacheFragInfoGV(
-    Module &M, Constant *UnitName) {
+    Module &M, const DataLayout &DL, Constant *UnitName) {
   assert(Options.ToolType == EfficiencySanitizerOptions::ESAN_CacheFrag);
 
   auto *Int8PtrTy = Type::getInt8PtrTy(*Ctx);
   auto *Int8PtrPtrTy = Int8PtrTy->getPointerTo();
   auto *Int32Ty = Type::getInt32Ty(*Ctx);
+  auto *Int32PtrTy = Type::getInt32PtrTy(*Ctx);
   auto *Int64Ty = Type::getInt64Ty(*Ctx);
   auto *Int64PtrTy = Type::getInt64PtrTy(*Ctx);
   // This structure should be kept consistent with the StructInfo struct
   // in the runtime library.
   // struct StructInfo {
   //   const char *StructName;
+  //   u32 Size;
   //   u32 NumFields;
+  //   u32 *FieldOffsets;
   //   u64 *FieldCounters;
   //   const char **FieldTypeNames;
   // };
   auto *StructInfoTy =
-    StructType::get(Int8PtrTy, Int32Ty, Int64PtrTy, Int8PtrPtrTy, nullptr);
+    StructType::get(Int8PtrTy, Int32Ty, Int32Ty, Int32PtrTy, Int64PtrTy,
+                    Int8PtrPtrTy, nullptr);
   auto *StructInfoPtrTy = StructInfoTy->getPointerTo();
   // This structure should be kept consistent with the CacheFragInfo struct
   // in the runtime library.
@@ -347,13 +352,21 @@
     // Remember the counter variable for each struct type.
     StructTyMap.insert(std::pair<Type *, GlobalVariable *>(StructTy, Counters));
 
+    // We pass the field type name array and offset array to the runtime for
+    // better reporting.
     // FieldTypeNames.
-    // We pass the field type name array to the runtime for better reporting.
     auto *TypeNameArrayTy = ArrayType::get(Int8PtrTy, StructTy->getNumElements());
-    GlobalVariable *TypeName =
+    GlobalVariable *TypeNames =
       new GlobalVariable(M, TypeNameArrayTy, true,
                          GlobalVariable::InternalLinkage, nullptr);
     SmallVector<Constant *, 16> TypeNameVec;
+    // FieldOffsets.
+    const StructLayout *SL = DL.getStructLayout(StructTy);
+    auto *OffsetArrayTy = ArrayType::get(Int32Ty, StructTy->getNumElements());
+    GlobalVariable *Offsets =
+      new GlobalVariable(M, OffsetArrayTy, true,
+                         GlobalVariable::InternalLinkage, nullptr);
+    SmallVector<Constant *, 16> OffsetVec;
     for (unsigned i = 0; i < StructTy->getNumElements(); ++i) {
       Type *Ty = StructTy->getElementType(i);
       std::string Str;
@@ -363,16 +376,20 @@
           ConstantExpr::getPointerCast(
               createPrivateGlobalForString(M, StrOS.str(), true),
               Int8PtrTy));
+      OffsetVec.push_back(ConstantInt::get(Int32Ty, SL->getElementOffset(i)));
     }
-    TypeName->setInitializer(ConstantArray::get(TypeNameArrayTy, TypeNameVec));
+    TypeNames->setInitializer(ConstantArray::get(TypeNameArrayTy, TypeNameVec));
+    Offsets->setInitializer(ConstantArray::get(OffsetArrayTy, OffsetVec));
 
     Initializers.push_back(
         ConstantStruct::get(
             StructInfoTy,
             ConstantExpr::getPointerCast(StructCounterName, Int8PtrTy),
+            ConstantInt::get(Int32Ty, SL->getSizeInBytes()),
             ConstantInt::get(Int32Ty, StructTy->getNumElements()),
+            ConstantExpr::getPointerCast(Offsets, Int32PtrTy),
             ConstantExpr::getPointerCast(Counters, Int64PtrTy),
-            ConstantExpr::getPointerCast(TypeName, Int8PtrPtrTy),
+            ConstantExpr::getPointerCast(TypeNames, Int8PtrPtrTy),
             nullptr));
   }
   // Structs.
@@ -399,7 +416,8 @@
 }
 
 // Create the tool-specific argument passed to EsanInit and EsanExit.
-Constant *EfficiencySanitizer::createEsanInitToolInfoArg(Module &M) {
+Constant *EfficiencySanitizer::createEsanInitToolInfoArg(Module &M,
+                                                         const DataLayout &DL) {
   // This structure contains tool-specific information about each compilation
   // unit (module) and is passed to the runtime library.
   GlobalVariable *ToolInfoGV = nullptr;
@@ -412,7 +430,7 @@
 
   // Create the tool-specific variable.
   if (Options.ToolType == EfficiencySanitizerOptions::ESAN_CacheFrag)
-    ToolInfoGV = createCacheFragInfoGV(M, UnitName);
+    ToolInfoGV = createCacheFragInfoGV(M, DL, UnitName);
 
   if (ToolInfoGV != nullptr)
     return ConstantExpr::getPointerCast(ToolInfoGV, Int8PtrTy);
@@ -445,7 +463,7 @@
   PointerType *Int8PtrTy = Type::getInt8PtrTy(*Ctx);
   IntptrTy = DL.getIntPtrType(M.getContext());
   // Create the variable passed to EsanInit and EsanExit.
-  Constant *ToolInfoArg = createEsanInitToolInfoArg(M);
+  Constant *ToolInfoArg = createEsanInitToolInfoArg(M, DL);
   // Constructor
   // We specify the tool type both in the EsanWhichToolName global
   // and as an arg to the init routine as a sanity check.