Skip to content

Commit

Permalink
[StackSafety] Run ThinLTO
Browse files Browse the repository at this point in the history
Summary:
ThinLTO linking runs dataflow processing on collected
function parameters. Then StackSafetyGlobalInfoWrapperPass
in ThinLTO backend will run as usual looking up to external
symbol in the summary if needed.

Depends on D80985.

Reviewers: eugenis, pcc

Reviewed By: eugenis

Subscribers: inglorion, hiraditya, steven_wu, dexonsmith, cfe-commits, llvm-commits

Tags: #clang, #llvm

Differential Revision: https://reviews.llvm.org/D81242
  • Loading branch information
vitalybuka committed Jun 13, 2020
1 parent e6ce0dc commit c1e47b4
Show file tree
Hide file tree
Showing 6 changed files with 274 additions and 13 deletions.
8 changes: 4 additions & 4 deletions clang/test/Driver/memtag_lto.c
Expand Up @@ -85,7 +85,7 @@
// RUN: -r %t.ltonewpm2.bc,use,plx \
// RUN: -r %t.ltonewpm2.bc,z, 2>&1 | FileCheck %s -check-prefixes=SSI,XSAFE,YSAFE

// FIXME: Thin LTO: both are safe.
// Thin LTO: both are safe.
// RUN: %clang -fno-experimental-new-pass-manager -O1 -target aarch64-unknown-linux -march=armv8+memtag -fsanitize=memtag -c %s -flto=thin -o %t.thinlto1.bc
// RUN: %clang -fno-experimental-new-pass-manager -O1 -target aarch64-unknown-linux -march=armv8+memtag -fsanitize=memtag -c -DBUILD2 %s -flto=thin -o %t.thinlto2.bc
// RUN: llvm-lto2 run -o %t.thinlto %t.thinlto1.bc %t.thinlto2.bc -save-temps -stack-safety-print -thinlto-threads 1 -O1 \
Expand All @@ -94,9 +94,9 @@
// RUN: -r %t.thinlto1.bc,use_local,plx \
// RUN: -r %t.thinlto1.bc,w, \
// RUN: -r %t.thinlto2.bc,use,plx \
// RUN: -r %t.thinlto2.bc,z, 2>&1 | FileCheck %s -check-prefixes=SSI,XUNSAFE,YSAFE
// RUN: -r %t.thinlto2.bc,z, 2>&1 | FileCheck %s -check-prefixes=SSI,XSAFE,YSAFE

// FIXME: Thin LTO, new PM: both are safe.
// Thin LTO, new PM: both are safe.
// RUN: %clang -fexperimental-new-pass-manager -O1 -target aarch64-unknown-linux -march=armv8+memtag -fsanitize=memtag -c %s -flto=thin -o %t.thinltonewpm1.bc
// RUN: %clang -fexperimental-new-pass-manager -O1 -target aarch64-unknown-linux -march=armv8+memtag -fsanitize=memtag -c -DBUILD2 %s -flto=thin -o %t.thinltonewpm2.bc
// RUN: llvm-lto2 run -use-new-pm -o %t.thinltonewpm %t.thinltonewpm1.bc %t.thinltonewpm2.bc -save-temps -stack-safety-print -thinlto-threads 1 -O1 \
Expand All @@ -105,7 +105,7 @@
// RUN: -r %t.thinltonewpm1.bc,use_local,plx \
// RUN: -r %t.thinltonewpm1.bc,w, \
// RUN: -r %t.thinltonewpm2.bc,use,plx \
// RUN: -r %t.thinltonewpm2.bc,z, 2>&1 | FileCheck %s -check-prefixes=SSI,XUNSAFE,YSAFE
// RUN: -r %t.thinltonewpm2.bc,z, 2>&1 | FileCheck %s -check-prefixes=SSI,XSAFE,YSAFE

void use(int *p);

Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/Analysis/StackSafetyAnalysis.h
Expand Up @@ -151,6 +151,8 @@ class StackSafetyGlobalInfoWrapperPass : public ModulePass {

bool needsParamAccessSummary(const Module &M);

void generateParamAccessSummary(ModuleSummaryIndex &Index);

} // end namespace llvm

#endif // LLVM_ANALYSIS_STACKSAFETYANALYSIS_H
115 changes: 111 additions & 4 deletions llvm/lib/Analysis/StackSafetyAnalysis.cpp
Expand Up @@ -544,6 +544,22 @@ StackSafetyDataFlowAnalysis<CalleeTy>::run() {
return Functions;
}

FunctionSummary *resolveCallee(GlobalValueSummary *S) {
while (S) {
if (!S->isLive() || !S->isDSOLocal())
return nullptr;
if (FunctionSummary *FS = dyn_cast<FunctionSummary>(S))
return FS;
AliasSummary *AS = dyn_cast<AliasSummary>(S);
if (!AS)
return nullptr;
S = AS->getBaseObject();
if (S == AS)
return nullptr;
}
return nullptr;
}

const Function *findCalleeInModule(const GlobalValue *GV) {
while (GV) {
if (GV->isDeclaration() || GV->isInterposable() || !GV->isDSOLocal())
Expand All @@ -560,7 +576,28 @@ const Function *findCalleeInModule(const GlobalValue *GV) {
return nullptr;
}

template <typename CalleeTy> void resolveAllCalls(UseInfo<CalleeTy> &Use) {
GlobalValueSummary *getGlobalValueSummary(const ModuleSummaryIndex *Index,
uint64_t ValueGUID) {
auto VI = Index->getValueInfo(ValueGUID);
if (!VI || VI.getSummaryList().empty())
return nullptr;
assert(VI.getSummaryList().size() == 1);
auto &Summary = VI.getSummaryList()[0];
return Summary.get();
}

const ConstantRange *findParamAccess(const FunctionSummary &FS,
uint32_t ParamNo) {
assert(FS.isLive());
assert(FS.isDSOLocal());
for (auto &PS : FS.paramAccesses())
if (ParamNo == PS.ParamNo)
return &PS.Use;
return nullptr;
}

void resolveAllCalls(UseInfo<GlobalValue> &Use,
const ModuleSummaryIndex *Index) {
ConstantRange FullSet(Use.Range.getBitWidth(), true);
for (auto &C : Use.Calls) {
const Function *F = findCalleeInModule(C.Callee);
Expand All @@ -569,8 +606,24 @@ template <typename CalleeTy> void resolveAllCalls(UseInfo<CalleeTy> &Use) {
continue;
}

return Use.updateRange(FullSet);
if (!Index)
return Use.updateRange(FullSet);
GlobalValueSummary *GVS = getGlobalValueSummary(Index, C.Callee->getGUID());

FunctionSummary *FS = resolveCallee(GVS);
if (!FS)
return Use.updateRange(FullSet);
const ConstantRange *Found = findParamAccess(*FS, C.ParamNo);
if (!Found)
return Use.updateRange(FullSet);
ConstantRange Access = Found->sextOrTrunc(Use.Range.getBitWidth());
Use.updateRange(addOverflowNever(Access, C.Offset));
C.Callee = nullptr;
}

Use.Calls.erase(std::remove_if(Use.Calls.begin(), Use.Calls.end(),
[](auto &T) { return !T.Callee; }),
Use.Calls.end());
}

GVToSSI createGlobalStackSafetyInfo(
Expand All @@ -585,7 +638,7 @@ GVToSSI createGlobalStackSafetyInfo(

for (auto &FnKV : Copy)
for (auto &KV : FnKV.second.Params)
resolveAllCalls(KV.second);
resolveAllCalls(KV.second, Index);

uint32_t PointerSize = Copy.begin()
->first->getParent()
Expand All @@ -598,7 +651,7 @@ GVToSSI createGlobalStackSafetyInfo(
auto &SrcF = Functions[F.first];
for (auto &KV : FI.Allocas) {
auto &A = KV.second;
resolveAllCalls(A);
resolveAllCalls(A, Index);
for (auto &C : A.Calls) {
A.updateRange(
SSDFA.getArgumentAccessRange(C.Callee, C.ParamNo, C.Offset));
Expand Down Expand Up @@ -836,6 +889,60 @@ bool llvm::needsParamAccessSummary(const Module &M) {
return false;
}

void llvm::generateParamAccessSummary(ModuleSummaryIndex &Index) {
const ConstantRange FullSet(FunctionSummary::ParamAccess::RangeWidth, true);
std::map<const FunctionSummary *, FunctionInfo<FunctionSummary>> Functions;

// Convert the ModuleSummaryIndex to a FunctionMap
for (auto &GVS : Index) {
for (auto &GV : GVS.second.SummaryList) {
FunctionSummary *FS = dyn_cast<FunctionSummary>(GV.get());
if (!FS)
continue;
if (FS->isLive() && FS->isDSOLocal()) {
FunctionInfo<FunctionSummary> FI;
for (auto &PS : FS->paramAccesses()) {
auto &US =
FI.Params
.emplace(PS.ParamNo, FunctionSummary::ParamAccess::RangeWidth)
.first->second;
US.Range = PS.Use;
for (auto &Call : PS.Calls) {
assert(!Call.Offsets.isFullSet());
FunctionSummary *S = resolveCallee(
Index.findSummaryInModule(Call.Callee, FS->modulePath()));
if (!S) {
US.Range = FullSet;
US.Calls.clear();
break;
}
US.Calls.emplace_back(S, Call.ParamNo, Call.Offsets);
}
}
Functions.emplace(FS, std::move(FI));
}
// Reset data for all summaries. Alive and DSO local will be set back from
// of data flow results below. Anything else will not be accessed
// by ThinLTO backend, so we can save on bitcode size.
FS->setParamAccesses({});
}
}
StackSafetyDataFlowAnalysis<FunctionSummary> SSDFA(
FunctionSummary::ParamAccess::RangeWidth, std::move(Functions));
for (auto &KV : SSDFA.run()) {
std::vector<FunctionSummary::ParamAccess> NewParams;
NewParams.reserve(KV.second.Params.size());
for (auto &KV : KV.second.Params) {
NewParams.emplace_back();
FunctionSummary::ParamAccess &New = NewParams.back();
New.ParamNo = KV.first;
New.Use = KV.second.Range; // Only range is needed.
}
const_cast<FunctionSummary *>(KV.first)->setParamAccesses(
std::move(NewParams));
}
}

static const char LocalPassArg[] = "stack-safety-local";
static const char LocalPassName[] = "Stack Safety Local Analysis";
INITIALIZE_PASS_BEGIN(StackSafetyInfoWrapperPass, LocalPassArg, LocalPassName,
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/LTO/LTO.cpp
Expand Up @@ -13,6 +13,7 @@
#include "llvm/LTO/LTO.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/Analysis/StackSafetyAnalysis.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Bitcode/BitcodeReader.h"
Expand Down Expand Up @@ -1433,6 +1434,8 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache,
thinLTOResolvePrevailingInIndex(ThinLTO.CombinedIndex, isPrevailing,
recordNewLinkage, GUIDPreservedSymbols);

generateParamAccessSummary(ThinLTO.CombinedIndex);

std::unique_ptr<ThinBackendProc> BackendProc =
ThinLTO.Backend(Conf, ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries,
AddStream, Cache);
Expand Down
43 changes: 43 additions & 0 deletions llvm/test/Analysis/StackSafetyAnalysis/ipa-alias.ll
Expand Up @@ -11,6 +11,48 @@
; RUN: opt -S -analyze -stack-safety %t.combined.bc | FileCheck %s --check-prefixes=CHECK,GLOBAL,NOLTO
; RUN: opt -S -passes="print-stack-safety" -disable-output %t.combined.bc 2>&1 | FileCheck %s --check-prefixes=CHECK,GLOBAL,NOLTO

; Do an end-to-test using the new LTO API
; RUN: opt -module-summary %s -o %t.summ0.bc
; RUN: opt -module-summary %S/Inputs/ipa-alias.ll -o %t.summ1.bc

; RUN: llvm-lto2 run %t.summ0.bc %t.summ1.bc -o %t.lto -stack-safety-print -stack-safety-run -save-temps -thinlto-threads 1 -O0 \
; RUN: -r %t.summ0.bc,PreemptableAliasWrite1, \
; RUN: -r %t.summ0.bc,AliasToPreemptableAliasWrite1, \
; RUN: -r %t.summ0.bc,InterposableAliasWrite1, \
; RUN: -r %t.summ0.bc,AliasWrite1, \
; RUN: -r %t.summ0.bc,BitcastAliasWrite1, \
; RUN: -r %t.summ0.bc,AliasToBitcastAliasWrite1, \
; RUN: -r %t.summ0.bc,PreemptableAliasCall,px \
; RUN: -r %t.summ0.bc,InterposableAliasCall,px \
; RUN: -r %t.summ0.bc,AliasCall,px \
; RUN: -r %t.summ0.bc,BitcastAliasCall,px \
; RUN: -r %t.summ1.bc,PreemptableAliasWrite1,px \
; RUN: -r %t.summ1.bc,AliasToPreemptableAliasWrite1,px \
; RUN: -r %t.summ1.bc,InterposableAliasWrite1,px \
; RUN: -r %t.summ1.bc,AliasWrite1,px \
; RUN: -r %t.summ1.bc,BitcastAliasWrite1,px \
; RUN: -r %t.summ1.bc,AliasToBitcastAliasWrite1,px \
; RUN: -r %t.summ1.bc,Write1,px 2>&1 | FileCheck %s --check-prefixes=CHECK,GLOBAL,LTO

; RUN: llvm-lto2 run %t.summ0.bc %t.summ1.bc -o %t-newpm.lto -stack-safety-print -stack-safety-run -save-temps -use-new-pm -thinlto-threads 1 -O0 \
; RUN: -r %t.summ0.bc,PreemptableAliasWrite1, \
; RUN: -r %t.summ0.bc,AliasToPreemptableAliasWrite1, \
; RUN: -r %t.summ0.bc,InterposableAliasWrite1, \
; RUN: -r %t.summ0.bc,AliasWrite1, \
; RUN: -r %t.summ0.bc,BitcastAliasWrite1, \
; RUN: -r %t.summ0.bc,AliasToBitcastAliasWrite1, \
; RUN: -r %t.summ0.bc,PreemptableAliasCall,px \
; RUN: -r %t.summ0.bc,InterposableAliasCall,px \
; RUN: -r %t.summ0.bc,AliasCall,px \
; RUN: -r %t.summ0.bc,BitcastAliasCall,px \
; RUN: -r %t.summ1.bc,PreemptableAliasWrite1,px \
; RUN: -r %t.summ1.bc,AliasToPreemptableAliasWrite1,px \
; RUN: -r %t.summ1.bc,InterposableAliasWrite1,px \
; RUN: -r %t.summ1.bc,AliasWrite1,px \
; RUN: -r %t.summ1.bc,BitcastAliasWrite1,px \
; RUN: -r %t.summ1.bc,AliasToBitcastAliasWrite1,px \
; RUN: -r %t.summ1.bc,Write1,px 2>&1 | FileCheck %s --check-prefixes=CHECK,GLOBAL,LTO

target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
target triple = "aarch64-unknown-linux"

Expand Down Expand Up @@ -54,6 +96,7 @@ define void @InterposableAliasCall() #0 {
; CHECK-NEXT: allocas uses:
; LOCAL-NEXT: x[1]: empty-set, @InterposableAliasWrite1(arg0, [0,1)){{$}}
; NOLTO-NEXT: x[1]: full-set, @InterposableAliasWrite1(arg0, [0,1)){{$}}
; LTO-NEXT: x[1]: [0,1), @InterposableAliasWrite1(arg0, [0,1)){{$}}
; CHECK-NOT: ]:
entry:
%x = alloca i8
Expand Down

0 comments on commit c1e47b4

Please sign in to comment.