[llvm] r230724 - [asan] Skip promotable allocas to improve performance at -O0

Anna Zaks ganna at apple.com
Thu Feb 26 19:12:36 PST 2015


Author: zaks
Date: Thu Feb 26 21:12:36 2015
New Revision: 230724

URL: http://llvm.org/viewvc/llvm-project?rev=230724&view=rev
Log:
[asan] Skip promotable allocas to improve performance at -O0

Currently, the ASan executables built with -O0 are unnecessarily slow.
The main reason is that ASan instrumentation pass inserts redundant
checks around promotable allocas. These allocas do not get instrumented
under -O1 because they get converted to virtual registered by mem2reg.
With this patch, ASan instrumentation pass will only instrument non
promotable allocas, giving us a speedup of 39% on a collection of
benchmarks with -O0. (There is no measurable speedup at -O1.)

Added:
    llvm/trunk/test/Instrumentation/AddressSanitizer/do-not-instrument-promotable-allocas.ll
Modified:
    llvm/trunk/lib/Transforms/Instrumentation/AddressSanitizer.cpp
    llvm/trunk/test/Instrumentation/AddressSanitizer/debug_info.ll
    llvm/trunk/test/Instrumentation/AddressSanitizer/instrument-dynamic-allocas.ll
    llvm/trunk/test/Instrumentation/AddressSanitizer/lifetime-uar.ll
    llvm/trunk/test/Instrumentation/AddressSanitizer/lifetime.ll
    llvm/trunk/test/Instrumentation/AddressSanitizer/stack_dynamic_alloca.ll
    llvm/trunk/test/Instrumentation/AddressSanitizer/stack_layout.ll

Modified: llvm/trunk/lib/Transforms/Instrumentation/AddressSanitizer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Instrumentation/AddressSanitizer.cpp?rev=230724&r1=230723&r2=230724&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/Instrumentation/AddressSanitizer.cpp (original)
+++ llvm/trunk/lib/Transforms/Instrumentation/AddressSanitizer.cpp Thu Feb 26 21:12:36 2015
@@ -49,6 +49,7 @@
 #include "llvm/Transforms/Utils/Cloning.h"
 #include "llvm/Transforms/Utils/Local.h"
 #include "llvm/Transforms/Utils/ModuleUtils.h"
+#include "llvm/Transforms/Utils/PromoteMemToReg.h"
 #include <algorithm>
 #include <string>
 #include <system_error>
@@ -165,6 +166,9 @@ static cl::opt<std::string> ClMemoryAcce
        cl::init("__asan_"));
 static cl::opt<bool> ClInstrumentAllocas("asan-instrument-allocas",
        cl::desc("instrument dynamic allocas"), cl::Hidden, cl::init(false));
+static cl::opt<bool> ClSkipPromotableAllocas("asan-skip-promotable-allocas",
+       cl::desc("Do not instrument promotable allocas"),
+       cl::Hidden, cl::init(true));
 
 // These flags allow to change the shadow mapping.
 // The shadow mapping looks like
@@ -372,6 +376,17 @@ struct AddressSanitizer : public Functio
   void getAnalysisUsage(AnalysisUsage &AU) const override {
     AU.addRequired<DominatorTreeWrapperPass>();
   }
+  uint64_t getAllocaSizeInBytes(AllocaInst *AI) const {
+    Type *Ty = AI->getAllocatedType();
+    uint64_t SizeInBytes = DL->getTypeAllocSize(Ty);
+    return SizeInBytes;
+  }
+  /// Check if we want (and can) handle this alloca.
+  bool isInterestingAlloca(AllocaInst &AI) const;
+  /// If it is an interesting memory access, return the PointerOperand
+  /// and set IsWrite/Alignment. Otherwise return nullptr.
+  Value *isInterestingMemoryAccess(Instruction *I, bool *IsWrite,
+                                   unsigned *Alignment) const;
   void instrumentMop(Instruction *I, bool UseCalls);
   void instrumentPointerComparisonOrSubtraction(Instruction *I);
   void instrumentAddress(Instruction *OrigIns, Instruction *InsertBefore,
@@ -599,7 +614,7 @@ struct FunctionStackPoisoner : public In
 
   /// \brief Collect Alloca instructions we want (and can) handle.
   void visitAllocaInst(AllocaInst &AI) {
-    if (!isInterestingAlloca(AI)) return;
+    if (!ASan.isInterestingAlloca(AI)) return;
 
     StackAlignment = std::max(StackAlignment, AI.getAlignment());
     if (isDynamicAlloca(AI))
@@ -653,19 +668,6 @@ struct FunctionStackPoisoner : public In
   bool isDynamicAlloca(AllocaInst &AI) const {
     return AI.isArrayAllocation() || !AI.isStaticAlloca();
   }
-
-  // Check if we want (and can) handle this alloca.
-  bool isInterestingAlloca(AllocaInst &AI) const {
-    return (AI.getAllocatedType()->isSized() &&
-            // alloca() may be called with 0 size, ignore it.
-            getAllocaSizeInBytes(&AI) > 0);
-  }
-
-  uint64_t getAllocaSizeInBytes(AllocaInst *AI) const {
-    Type *Ty = AI->getAllocatedType();
-    uint64_t SizeInBytes = ASan.DL->getTypeAllocSize(Ty);
-    return SizeInBytes;
-  }
   /// Finds alloca where the value comes from.
   AllocaInst *findAllocaForValue(Value *V);
   void poisonRedZones(ArrayRef<uint8_t> ShadowBytes, IRBuilder<> &IRB,
@@ -775,38 +777,56 @@ void AddressSanitizer::instrumentMemIntr
   MI->eraseFromParent();
 }
 
-// If I is an interesting memory access, return the PointerOperand
-// and set IsWrite/Alignment. Otherwise return nullptr.
-static Value *isInterestingMemoryAccess(Instruction *I, bool *IsWrite,
-                                        unsigned *Alignment) {
+/// Check if we want (and can) handle this alloca.
+bool AddressSanitizer::isInterestingAlloca(AllocaInst &AI) const {
+  return (AI.getAllocatedType()->isSized() &&
+          // alloca() may be called with 0 size, ignore it.
+          getAllocaSizeInBytes(&AI) > 0 &&
+          // We are only interested in allocas not promotable to registers.
+          // Promotable allocas are common under -O0.
+          (!ClSkipPromotableAllocas || !isAllocaPromotable(&AI)));
+}
+
+/// If I is an interesting memory access, return the PointerOperand
+/// and set IsWrite/Alignment. Otherwise return nullptr.
+Value *AddressSanitizer::isInterestingMemoryAccess(Instruction *I,
+                                                   bool *IsWrite,
+                                                   unsigned *Alignment) const {
   // Skip memory accesses inserted by another instrumentation.
   if (I->getMetadata("nosanitize"))
     return nullptr;
+
+  Value *PtrOperand = nullptr;
   if (LoadInst *LI = dyn_cast<LoadInst>(I)) {
     if (!ClInstrumentReads) return nullptr;
     *IsWrite = false;
     *Alignment = LI->getAlignment();
-    return LI->getPointerOperand();
-  }
-  if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
+    PtrOperand = LI->getPointerOperand();
+  } else if (StoreInst *SI = dyn_cast<StoreInst>(I)) {
     if (!ClInstrumentWrites) return nullptr;
     *IsWrite = true;
     *Alignment = SI->getAlignment();
-    return SI->getPointerOperand();
-  }
-  if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) {
+    PtrOperand = SI->getPointerOperand();
+  } else if (AtomicRMWInst *RMW = dyn_cast<AtomicRMWInst>(I)) {
     if (!ClInstrumentAtomics) return nullptr;
     *IsWrite = true;
     *Alignment = 0;
-    return RMW->getPointerOperand();
-  }
-  if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I)) {
+    PtrOperand = RMW->getPointerOperand();
+  } else if (AtomicCmpXchgInst *XCHG = dyn_cast<AtomicCmpXchgInst>(I)) {
     if (!ClInstrumentAtomics) return nullptr;
     *IsWrite = true;
     *Alignment = 0;
-    return XCHG->getPointerOperand();
+    PtrOperand = XCHG->getPointerOperand();
   }
-  return nullptr;
+
+  // Treat memory accesses to promotable allocas as non-interesting since they
+  // will not cause memory violations. This greatly speeds up the instrumented
+  // executable at -O0.
+  if (ClSkipPromotableAllocas)
+    if (auto AI = dyn_cast_or_null<AllocaInst>(PtrOperand))
+      return isInterestingAlloca(*AI) ? AI : nullptr;
+
+  return PtrOperand;
 }
 
 static bool isPointerOperand(Value *V) {
@@ -1665,7 +1685,7 @@ void FunctionStackPoisoner::poisonStack(
   SVD.reserve(AllocaVec.size());
   for (AllocaInst *AI : AllocaVec) {
     ASanStackVariableDescription D = { AI->getName().data(),
-                                   getAllocaSizeInBytes(AI),
+                                   ASan.getAllocaSizeInBytes(AI),
                                    AI->getAlignment(), AI, 0};
     SVD.push_back(D);
   }
@@ -1856,7 +1876,7 @@ void FunctionStackPoisoner::poisonAlloca
 AllocaInst *FunctionStackPoisoner::findAllocaForValue(Value *V) {
   if (AllocaInst *AI = dyn_cast<AllocaInst>(V))
     // We're intested only in allocas we can handle.
-    return isInterestingAlloca(*AI) ? AI : nullptr;
+    return ASan.isInterestingAlloca(*AI) ? AI : nullptr;
   // See if we've already calculated (or started to calculate) alloca for a
   // given value.
   AllocaForValueMapTy::iterator I = AllocaForValue.find(V);

Modified: llvm/trunk/test/Instrumentation/AddressSanitizer/debug_info.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Instrumentation/AddressSanitizer/debug_info.ll?rev=230724&r1=230723&r2=230724&view=diff
==============================================================================
--- llvm/trunk/test/Instrumentation/AddressSanitizer/debug_info.ll (original)
+++ llvm/trunk/test/Instrumentation/AddressSanitizer/debug_info.ll Thu Feb 26 21:12:36 2015
@@ -10,12 +10,12 @@ define i32 @_Z3zzzi(i32 %p) nounwind uwt
 entry:
   %p.addr = alloca i32, align 4
   %r = alloca i32, align 4
-  store i32 %p, i32* %p.addr, align 4
+  store volatile i32 %p, i32* %p.addr, align 4
   call void @llvm.dbg.declare(metadata i32* %p.addr, metadata !10, metadata !{!"0x102"}), !dbg !11
   call void @llvm.dbg.declare(metadata i32* %r, metadata !12, metadata !{!"0x102"}), !dbg !14
   %0 = load i32* %p.addr, align 4, !dbg !14
   %add = add nsw i32 %0, 1, !dbg !14
-  store i32 %add, i32* %r, align 4, !dbg !14
+  store volatile i32 %add, i32* %r, align 4, !dbg !14
   %1 = load i32* %r, align 4, !dbg !15
   ret i32 %1, !dbg !15
 }

Added: llvm/trunk/test/Instrumentation/AddressSanitizer/do-not-instrument-promotable-allocas.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Instrumentation/AddressSanitizer/do-not-instrument-promotable-allocas.ll?rev=230724&view=auto
==============================================================================
--- llvm/trunk/test/Instrumentation/AddressSanitizer/do-not-instrument-promotable-allocas.ll (added)
+++ llvm/trunk/test/Instrumentation/AddressSanitizer/do-not-instrument-promotable-allocas.ll Thu Feb 26 21:12:36 2015
@@ -0,0 +1,21 @@
+; RUN: opt < %s -asan -asan-module -asan-instrument-allocas=1 -S | FileCheck %s --check-prefix=CHECK
+
+target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-apple-macosx10.10.0"
+
+define i32 @test_promotable_allocas() sanitize_address {
+entry:
+; CHECK: %0 = alloca i32, align 4
+; CHECK: store i32 0, i32* %0, align 4
+; CHECK: %1 = load i32* %0, align 4
+; CHECK: ret i32 %1
+
+; CHECK-NOT: __asan_stack_malloc_0
+; CHECK-NOT: icmp
+; CHECK-NOT: call void @__asan_report_store4
+
+  %0 = alloca i32, align 4
+  store i32 0, i32* %0, align 4
+  %1 = load i32* %0, align 4
+  ret i32 %1
+}

Modified: llvm/trunk/test/Instrumentation/AddressSanitizer/instrument-dynamic-allocas.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Instrumentation/AddressSanitizer/instrument-dynamic-allocas.ll?rev=230724&r1=230723&r2=230724&view=diff
==============================================================================
--- llvm/trunk/test/Instrumentation/AddressSanitizer/instrument-dynamic-allocas.ll (original)
+++ llvm/trunk/test/Instrumentation/AddressSanitizer/instrument-dynamic-allocas.ll Thu Feb 26 21:12:36 2015
@@ -15,10 +15,11 @@ entry:
 ; CHECK-NOALLOCA-NOT: store i32 -875836469
   %0 = alloca i32, align 4
   %1 = alloca i8*
-  store i32 %len, i32* %0, align 4
+  store volatile i32 %len, i32* %0, align 4
   %2 = load i32* %0, align 4
   %3 = zext i32 %2 to i64
   %4 = alloca i8, i64 %3, align 32
+  store volatile i8 0, i8* %4
   ret void
 }
 

Modified: llvm/trunk/test/Instrumentation/AddressSanitizer/lifetime-uar.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Instrumentation/AddressSanitizer/lifetime-uar.ll?rev=230724&r1=230723&r2=230724&view=diff
==============================================================================
--- llvm/trunk/test/Instrumentation/AddressSanitizer/lifetime-uar.ll (original)
+++ llvm/trunk/test/Instrumentation/AddressSanitizer/lifetime-uar.ll Thu Feb 26 21:12:36 2015
@@ -17,8 +17,8 @@ entry:
   ; Memory is unpoisoned at llvm.lifetime.start
   ; CHECK: call void @__asan_unpoison_stack_memory(i64 %{{[^ ]+}}, i64 1)
 
-  store i32 0, i32* %retval
-  store i8 0, i8* %c, align 1
+  store volatile i32 0, i32* %retval
+  store volatile i8 0, i8* %c, align 1
 
   call void @llvm.lifetime.end(i64 1, i8* %c)
   ; Memory is poisoned at llvm.lifetime.end

Modified: llvm/trunk/test/Instrumentation/AddressSanitizer/lifetime.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Instrumentation/AddressSanitizer/lifetime.ll?rev=230724&r1=230723&r2=230724&view=diff
==============================================================================
--- llvm/trunk/test/Instrumentation/AddressSanitizer/lifetime.ll (original)
+++ llvm/trunk/test/Instrumentation/AddressSanitizer/lifetime.ll Thu Feb 26 21:12:36 2015
@@ -12,6 +12,7 @@ entry:
   %i = alloca i32, align 4
   %i.ptr = bitcast i32* %i to i8*
   call void @llvm.lifetime.start(i64 -1, i8* %i.ptr)
+  store volatile i8 0, i8* %i.ptr
   call void @llvm.lifetime.end(i64 -1, i8* %i.ptr)
 
 ; Check that lifetime with no size are ignored.
@@ -30,6 +31,7 @@ define void @lifetime() sanitize_address
   %i = alloca i32, align 4
   %i.ptr = bitcast i32* %i to i8*
   call void @llvm.lifetime.start(i64 3, i8* %i.ptr)
+  store volatile i8 0, i8* %i.ptr
   ; Memory is unpoisoned at llvm.lifetime.start
   ; CHECK: %[[VAR:[^ ]*]] = ptrtoint i32* %{{[^ ]+}} to i64
   ; CHECK-NEXT: call void @__asan_unpoison_stack_memory(i64 %[[VAR]], i64 3)
@@ -43,12 +45,14 @@ define void @lifetime() sanitize_address
   %arr = alloca [10 x i32], align 16
   %arr.ptr = bitcast [10 x i32]* %arr to i8*
   call void @llvm.lifetime.start(i64 40, i8* %arr.ptr)
+  store volatile i8 0, i8* %arr.ptr
   ; CHECK: call void @__asan_unpoison_stack_memory(i64 %{{[^ ]+}}, i64 40)
   call void @llvm.lifetime.end(i64 40, i8* %arr.ptr)
   ; CHECK: call void @__asan_poison_stack_memory(i64 %{{[^ ]+}}, i64 40)
 
   ; One more lifetime start/end for the same variable %i.
   call void @llvm.lifetime.start(i64 4, i8* %i.ptr)
+  store volatile i8 0, i8* %i.ptr
   ; CHECK: call void @__asan_unpoison_stack_memory(i64 %{{[^ ]+}}, i64 4)
   call void @llvm.lifetime.end(i64 4, i8* %i.ptr)
   ; CHECK: call void @__asan_poison_stack_memory(i64 %{{[^ ]+}}, i64 4)
@@ -68,6 +72,7 @@ entry:
   %i = alloca i64, align 4
   %i.ptr = bitcast i64* %i to i8*
   call void @llvm.lifetime.start(i64 8, i8* %i.ptr)
+  store volatile i8 0, i8* %i.ptr
   ; CHECK: __asan_unpoison_stack_memory
   br i1 %x, label %bb0, label %bb1
 

Modified: llvm/trunk/test/Instrumentation/AddressSanitizer/stack_dynamic_alloca.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Instrumentation/AddressSanitizer/stack_dynamic_alloca.ll?rev=230724&r1=230723&r2=230724&view=diff
==============================================================================
--- llvm/trunk/test/Instrumentation/AddressSanitizer/stack_dynamic_alloca.ll (original)
+++ llvm/trunk/test/Instrumentation/AddressSanitizer/stack_dynamic_alloca.ll Thu Feb 26 21:12:36 2015
@@ -26,6 +26,8 @@ entry:
 ; CHECK: ret void
 
   %XXX = alloca [20 x i8], align 1
+  %arr.ptr = bitcast [20 x i8]* %XXX to i8*
+  store volatile i8 0, i8* %arr.ptr
   ret void
 }
 
@@ -37,6 +39,8 @@ entry:
 ; CHECK: ret void
 
   %XXX = alloca [20 x i8], align 1
+  %arr.ptr = bitcast [20 x i8]* %XXX to i8*
+  store volatile i8 0, i8* %arr.ptr
   call void asm sideeffect "mov %%rbx, %%rcx", "~{dirflag},~{fpsr},~{flags}"() nounwind
   ret void
 }

Modified: llvm/trunk/test/Instrumentation/AddressSanitizer/stack_layout.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Instrumentation/AddressSanitizer/stack_layout.ll?rev=230724&r1=230723&r2=230724&view=diff
==============================================================================
--- llvm/trunk/test/Instrumentation/AddressSanitizer/stack_layout.ll (original)
+++ llvm/trunk/test/Instrumentation/AddressSanitizer/stack_layout.ll Thu Feb 26 21:12:36 2015
@@ -26,6 +26,12 @@ entry:
   %XXX = alloca [10 x i8], align 1
   %YYY = alloca [20 x i8], align 1
   %ZZZ = alloca [30 x i8], align 1
+  %arr1.ptr = bitcast [10 x i8]* %XXX to i8*
+  store volatile i8 0, i8* %arr1.ptr
+  %arr2.ptr = bitcast [20 x i8]* %YYY to i8*
+  store volatile i8 0, i8* %arr2.ptr
+  %arr3.ptr = bitcast [30 x i8]* %ZZZ to i8*
+  store volatile i8 0, i8* %arr3.ptr
   ret void
 }
 
@@ -41,6 +47,12 @@ entry:
   %AAA = alloca [5 x i8], align 1
   %BBB = alloca [55 x i8], align 1
   %CCC = alloca [555 x i8], align 1
+  %arr1.ptr = bitcast [5 x i8]* %AAA to i8*
+  store volatile i8 0, i8* %arr1.ptr
+  %arr2.ptr = bitcast [55 x i8]* %BBB to i8*
+  store volatile i8 0, i8* %arr2.ptr
+  %arr3.ptr = bitcast [555 x i8]* %CCC to i8*
+  store volatile i8 0, i8* %arr3.ptr
   ret void
 }
 
@@ -57,5 +69,11 @@ entry:
   %AAA = alloca [128 x i8], align 16
   %BBB = alloca [128 x i8], align 64
   %CCC = alloca [128 x i8], align 256
+  %arr1.ptr = bitcast [128 x i8]* %AAA to i8*
+  store volatile i8 0, i8* %arr1.ptr
+  %arr2.ptr = bitcast [128 x i8]* %BBB to i8*
+  store volatile i8 0, i8* %arr2.ptr
+  %arr3.ptr = bitcast [128 x i8]* %CCC to i8*
+  store volatile i8 0, i8* %arr3.ptr
   ret void
 }





More information about the llvm-commits mailing list