Add pass to add !annotate metadata from @llvm.global.annotations.

This patch adds a new pass to add !annotation metadata for entries in
@llvm.global.anotations, which is generated  using
__attribute__((annotate("_name"))) on functions in Clang.

This has been discussed on llvm-dev as part of
    RFC: Combining Annotation Metadata and Remarks
    http://lists.llvm.org/pipermail/llvm-dev/2020-November/146393.html

Reviewed By: thegameg

Differential Revision: https://reviews.llvm.org/D91195
This commit is contained in:
Florian Hahn 2020-11-16 09:49:04 +00:00
parent 47fd19f22e
commit 8dbe44cb29
25 changed files with 245 additions and 4 deletions

View File

@ -18,10 +18,10 @@
// NEWPM: Running pass: GCOVProfilerPass
// NEWPM-O3-NOT: Running pass
// NEWPM-O3: Running pass: Annotation2MetadataPass
// NEWPM-O3: Running pass: ForceFunctionAttrsPass
// NEWPM-O3: Running pass: GCOVProfilerPass
int test1(int a) {
switch (a % 2) {
case 0:

View File

@ -90,10 +90,12 @@ public:
bool allowExtraAnalysis(StringRef PassName) const {
return OptimizationRemarkEmitter::allowExtraAnalysis(*F, PassName);
}
static bool allowExtraAnalysis(const Function &F, StringRef PassName) {
return F.getContext().getLLVMRemarkStreamer() ||
F.getContext().getDiagHandlerPtr()->isAnyRemarkEnabled(PassName);
return allowExtraAnalysis(F.getContext(), PassName);
}
static bool allowExtraAnalysis(LLVMContext &Ctx, StringRef PassName) {
return Ctx.getLLVMRemarkStreamer() ||
Ctx.getDiagHandlerPtr()->isAnyRemarkEnabled(PassName);
}
private:

View File

@ -73,6 +73,7 @@ void initializeAlignmentFromAssumptionsPass(PassRegistry&);
void initializeAlwaysInlinerLegacyPassPass(PassRegistry&);
void initializeAssumeSimplifyPassLegacyPassPass(PassRegistry &);
void initializeAssumeBuilderPassLegacyPassPass(PassRegistry &);
void initializeAnnotation2MetadataLegacyPass(PassRegistry &);
void initializeAnnotationRemarksLegacyPass(PassRegistry &);
void initializeOpenMPOptLegacyPassPass(PassRegistry &);
void initializeArgPromotionPass(PassRegistry&);

View File

@ -29,6 +29,13 @@ class BasicBlock;
class GlobalValue;
class raw_ostream;
//===----------------------------------------------------------------------===//
//
// This pass adds !annotation metadata to entries in the
// @llvm.global.annotations global constant.
//
ModulePass *createAnnotation2MetadataLegacyPass();
//===----------------------------------------------------------------------===//
//
// These functions removes symbols from functions and modules. If OnlyDebugInfo

View File

@ -0,0 +1,30 @@
//===- Annotation2Metadata.h - Add !annotation metadata. --------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// New pass manager pass to convert @llvm.global.annotations to !annotation
// metadata.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_TRANSFORMS_IPO_ANNOTATION2METADATA_H
#define LLVM_TRANSFORMS_IPO_ANNOTATION2METADATA_H
#include "llvm/IR/PassManager.h"
namespace llvm {
class Module;
/// Pass to convert @llvm.global.annotations to !annotation metadata.
struct Annotation2MetadataPass : public PassInfoMixin<Annotation2MetadataPass> {
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
};
} // end namespace llvm
#endif // LLVM_TRANSFORMS_IPO_SCCP_H

View File

@ -83,6 +83,7 @@
#include "llvm/Transforms/Coroutines/CoroSplit.h"
#include "llvm/Transforms/HelloNew/HelloWorld.h"
#include "llvm/Transforms/IPO/AlwaysInliner.h"
#include "llvm/Transforms/IPO/Annotation2Metadata.h"
#include "llvm/Transforms/IPO/ArgumentPromotion.h"
#include "llvm/Transforms/IPO/Attributor.h"
#include "llvm/Transforms/IPO/BlockExtractor.h"
@ -1326,6 +1327,9 @@ PassBuilder::buildPerModuleDefaultPipeline(OptimizationLevel Level,
ModulePassManager MPM(DebugLogging);
// Convert @llvm.global.annotations to !annotation metadata.
MPM.addPass(Annotation2MetadataPass());
// Force any function attributes we want the rest of the pipeline to observe.
MPM.addPass(ForceFunctionAttrsPass());
@ -1355,6 +1359,9 @@ PassBuilder::buildThinLTOPreLinkDefaultPipeline(OptimizationLevel Level) {
ModulePassManager MPM(DebugLogging);
// Convert @llvm.global.annotations to !annotation metadata.
MPM.addPass(Annotation2MetadataPass());
// Force any function attributes we want the rest of the pipeline to observe.
MPM.addPass(ForceFunctionAttrsPass());
@ -1399,6 +1406,9 @@ ModulePassManager PassBuilder::buildThinLTODefaultPipeline(
OptimizationLevel Level, const ModuleSummaryIndex *ImportSummary) {
ModulePassManager MPM(DebugLogging);
// Convert @llvm.global.annotations to !annotation metadata.
MPM.addPass(Annotation2MetadataPass());
if (ImportSummary) {
// These passes import type identifier resolutions for whole-program
// devirtualization and CFI. They must run early because other passes may
@ -1451,6 +1461,9 @@ PassBuilder::buildLTODefaultPipeline(OptimizationLevel Level,
ModuleSummaryIndex *ExportSummary) {
ModulePassManager MPM(DebugLogging);
// Convert @llvm.global.annotations to !annotation metadata.
MPM.addPass(Annotation2MetadataPass());
if (Level == OptimizationLevel::O0) {
// The WPD and LowerTypeTest passes need to run at -O0 to lower type
// metadata and intrinsics.

View File

@ -43,6 +43,7 @@ MODULE_ALIAS_ANALYSIS("globals-aa", GlobalsAA())
#endif
MODULE_PASS("always-inline", AlwaysInlinerPass())
MODULE_PASS("attributor", AttributorPass())
MODULE_PASS("annotation2metadata", Annotation2MetadataPass())
MODULE_PASS("called-value-propagation", CalledValuePropagationPass())
MODULE_PASS("canonicalize-aliases", CanonicalizeAliasesPass())
MODULE_PASS("cg-profile", CGProfilePass())

View File

@ -0,0 +1,106 @@
//===-- Annotation2Metadata.cpp - Add !annotation metadata. ---------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Add !annotation metadata for entries in @llvm.global.anotations, generated
// using __attribute__((annotate("_name"))) on functions in Clang.
//
//===----------------------------------------------------------------------===//
#include "llvm/Transforms/IPO/Annotation2Metadata.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Module.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/Transforms/IPO.h"
using namespace llvm;
#define DEBUG_TYPE "annotation2metadata"
static bool convertAnnotation2Metadata(Module &M) {
// Only add !annotation metadata if the corresponding remarks pass is also
// enabled.
if (!OptimizationRemarkEmitter::allowExtraAnalysis(M.getContext(),
"annotation-remarks"))
return false;
auto *Annotations = M.getGlobalVariable("llvm.global.annotations");
auto *C = dyn_cast_or_null<Constant>(Annotations);
if (!C || C->getNumOperands() != 1)
return false;
C = cast<Constant>(C->getOperand(0));
// Iterate over all entries in C and attach !annotation metadata to suitable
// entries.
for (auto &Op : C->operands()) {
// Look at the operands to check if we can use the entry to generate
// !annotation metadata.
auto *OpC = dyn_cast<ConstantStruct>(&Op);
if (!OpC || OpC->getNumOperands() != 4)
continue;
auto *StrGEP = dyn_cast<ConstantExpr>(OpC->getOperand(1));
if (!StrGEP || StrGEP->getNumOperands() < 2)
continue;
auto *StrC = dyn_cast<GlobalValue>(StrGEP->getOperand(0));
if (!StrC)
continue;
auto *StrData = dyn_cast<ConstantDataSequential>(StrC->getOperand(0));
if (!StrData)
continue;
// Look through bitcast.
auto *Bitcast = dyn_cast<ConstantExpr>(OpC->getOperand(0));
if (!Bitcast || Bitcast->getOpcode() != Instruction::BitCast)
continue;
auto *Fn = dyn_cast<Function>(Bitcast->getOperand(0));
if (!Fn)
continue;
// Add annotation to all instructions in the function.
for (auto &I : instructions(Fn))
I.addAnnotationMetadata(StrData->getAsCString());
}
return true;
}
namespace {
struct Annotation2MetadataLegacy : public ModulePass {
static char ID;
Annotation2MetadataLegacy() : ModulePass(ID) {
initializeAnnotation2MetadataLegacyPass(*PassRegistry::getPassRegistry());
}
bool runOnModule(Module &M) override { return convertAnnotation2Metadata(M); }
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesAll();
}
};
} // end anonymous namespace
char Annotation2MetadataLegacy::ID = 0;
INITIALIZE_PASS_BEGIN(Annotation2MetadataLegacy, DEBUG_TYPE,
"Annotation2Metadata", false, false)
INITIALIZE_PASS_END(Annotation2MetadataLegacy, DEBUG_TYPE,
"Annotation2Metadata", false, false)
ModulePass *llvm::createAnnotation2MetadataLegacyPass() {
return new Annotation2MetadataLegacy();
}
PreservedAnalyses Annotation2MetadataPass::run(Module &M,
ModuleAnalysisManager &AM) {
convertAnnotation2Metadata(M);
return PreservedAnalyses::all();
}

View File

@ -1,5 +1,6 @@
add_llvm_component_library(LLVMipo
AlwaysInliner.cpp
Annotation2Metadata.cpp
ArgumentPromotion.cpp
Attributor.cpp
AttributorAttributes.cpp

View File

@ -25,6 +25,7 @@ using namespace llvm;
void llvm::initializeIPO(PassRegistry &Registry) {
initializeOpenMPOptLegacyPassPass(Registry);
initializeArgPromotionPass(Registry);
initializeAnnotation2MetadataLegacyPass(Registry);
initializeCalledValuePropagationLegacyPassPass(Registry);
initializeConstantMergeLegacyPassPass(Registry);
initializeCrossDSOCFIPass(Registry);

View File

@ -512,6 +512,8 @@ void PassManagerBuilder::populateModulePassManager(
// is handled separately, so just check this is not the ThinLTO post-link.
bool DefaultOrPreLinkPipeline = !PerformThinLTO;
MPM.add(createAnnotation2MetadataLegacyPass());
if (!PGOSampleUse.empty()) {
MPM.add(createPruneEHPass());
// In ThinLTO mode, when flattened profile is used, all the available

View File

@ -19,6 +19,7 @@
; GCN-O0-NEXT: Assumption Cache Tracker
; GCN-O0-NEXT: Profile summary info
; GCN-O0-NEXT: ModulePass Manager
; GCN-O0-NEXT: Annotation2Metadata
; GCN-O0-NEXT: Force set function attributes
; GCN-O0-NEXT: CallGraph Construction
; GCN-O0-NEXT: Call Graph SCC Pass Manager
@ -59,6 +60,7 @@
; GCN-O1-NEXT: Assumption Cache Tracker
; GCN-O1-NEXT: Profile summary info
; GCN-O1-NEXT: ModulePass Manager
; GCN-O1-NEXT: Annotation2Metadata
; GCN-O1-NEXT: Force set function attributes
; GCN-O1-NEXT: Infer set function attributes
; GCN-O1-NEXT: Unify multiple OpenCL metadata due to linking
@ -369,6 +371,7 @@
; GCN-O2-NEXT: Assumption Cache Tracker
; GCN-O2-NEXT: Profile summary info
; GCN-O2-NEXT: ModulePass Manager
; GCN-O2-NEXT: Annotation2Metadata
; GCN-O2-NEXT: Force set function attributes
; GCN-O2-NEXT: Infer set function attributes
; GCN-O2-NEXT: Unify multiple OpenCL metadata due to linking
@ -727,6 +730,7 @@
; GCN-O3-NEXT: Assumption Cache Tracker
; GCN-O3-NEXT: Profile summary info
; GCN-O3-NEXT: ModulePass Manager
; GCN-O3-NEXT: Annotation2Metadata
; GCN-O3-NEXT: Force set function attributes
; GCN-O3-NEXT: Infer set function attributes
; GCN-O3-NEXT: Unify multiple OpenCL metadata due to linking

View File

@ -92,6 +92,7 @@
; CHECK-Oz: {{^}}
; CHECK-O: Starting llvm::Module pass manager run.
; CHECK-O-NEXT: Running pass: Annotation2Metadata
; CHECK-O-NEXT: Running pass: ForceFunctionAttrsPass
; CHECK-EP-PIPELINE-START-NEXT: Running pass: NoOpModulePass
; CHECK-O-NEXT: Running pass: InferFunctionAttrsPass

View File

@ -24,6 +24,7 @@
; RUN: --check-prefix=CHECK-O3 --check-prefix=CHECK-EP-Peephole
; CHECK-O: Starting llvm::Module pass manager run.
; CHECK-O-NEXT: Running pass: Annotation2Metadata
; CHECK-O-NEXT: Running pass: GlobalDCEPass
; CHECK-O-NEXT: Running pass: ForceFunctionAttrsPass
; CHECK-O-NEXT: Running pass: InferFunctionAttrsPass

View File

@ -51,6 +51,7 @@
; CHECK-NOEXT: {{^}}
; CHECK-O: Starting llvm::Module pass manager run.
; CHECK-O-NEXT: Running pass: Annotation2Metadata
; CHECK-O-NEXT: Running pass: ForceFunctionAttrsPass
; CHECK-EP-PIPELINE-START-NEXT: Running pass: NoOpModulePass
; CHECK-DIS-NEXT: Running analysis: InnerAnalysisManagerProxy

View File

@ -24,6 +24,7 @@
; CHECK-NOEXT: {{^}}
; CHECK-O: Starting {{.*}}Module pass manager run.
; CHECK-O-NEXT: Running pass: Annotation2Metadata
; CHECK-O-NEXT: Running pass: ForceFunctionAttrsPass
; CHECK-EP-PIPELINE-START-NEXT: Running pass: NoOpModulePass
; CHECK-O-NEXT: Running pass: PGOIndirectCallPromotion

View File

@ -29,6 +29,7 @@
; CHECK-NOEXT: {{^}}
; CHECK-O: Starting {{.*}}Module pass manager run.
; CHECK-O-NEXT: Running pass: Annotation2Metadata
; CHECK-O-NEXT: Running pass: ForceFunctionAttrsPass
; CHECK-EP-PIPELINE-START-NEXT: Running pass: NoOpModulePass
; CHECK-O-NEXT: Running pass: InferFunctionAttrsPass

View File

@ -28,6 +28,7 @@
; RUN: | FileCheck %s --check-prefixes=CHECK-O,CHECK-O2,CHECK-O23SZ,CHECK-O123
;
; CHECK-O: Starting {{.*}}Module pass manager run.
; CHECK-O-NEXT: Running pass: Annotation2Metadata
; CHECK-O-NEXT: Running pass: ForceFunctionAttrsPass
; CHECK-EP-PIPELINE-START-NEXT: Running pass: NoOpModulePass
; CHECK-O-NEXT: Running pass: InferFunctionAttrsPass

View File

@ -26,6 +26,7 @@
; RUN: | FileCheck %s --check-prefixes=CHECK-O,CHECK-O2,CHECK-O23SZ
;
; CHECK-O: Starting {{.*}}Module pass manager run.
; CHECK-O-NEXT: Running pass: Annotation2Metadata
; CHECK-O-NEXT: Running pass: ForceFunctionAttrsPass
; CHECK-O-NEXT: Running analysis: InnerAnalysisManagerProxy
; CHECK-O-NEXT: Running pass: AddDiscriminatorsPass

View File

@ -18,6 +18,7 @@
; CHECK: Assumption Cache Tracker
; CHECK-NEXT: Profile summary info
; CHECK-NEXT: ModulePass Manager
; CHECK-NEXT: Annotation2Metadata
; CHECK-NEXT: Force set function attributes
; CHECK-NEXT: CallGraph Construction
; CHECK-NEXT: Call Graph SCC Pass Manager

View File

@ -27,6 +27,7 @@
; CHECK-NEXT: Assumption Cache Tracker
; CHECK-NEXT: Profile summary info
; CHECK-NEXT: ModulePass Manager
; CHECK-NEXT: Annotation2Metadata
; CHECK-NEXT: Force set function attributes
; CHECK-NEXT: Infer set function attributes
; CHECK-NEXT: Interprocedural Sparse Conditional Constant Propagation

View File

@ -27,6 +27,7 @@
; CHECK-NEXT: Assumption Cache Tracker
; CHECK-NEXT: Profile summary info
; CHECK-NEXT: ModulePass Manager
; CHECK-NEXT: Annotation2Metadata
; CHECK-NEXT: Force set function attributes
; CHECK-NEXT: Infer set function attributes
; CHECK-NEXT: FunctionPass Manager

View File

@ -27,6 +27,7 @@
; CHECK-NEXT: Assumption Cache Tracker
; CHECK-NEXT: Profile summary info
; CHECK-NEXT: ModulePass Manager
; CHECK-NEXT: Annotation2Metadata
; CHECK-NEXT: Force set function attributes
; CHECK-NEXT: Infer set function attributes
; CHECK-NEXT: FunctionPass Manager

View File

@ -27,6 +27,7 @@
; CHECK-NEXT: Assumption Cache Tracker
; CHECK-NEXT: Profile summary info
; CHECK-NEXT: ModulePass Manager
; CHECK-NEXT: Annotation2Metadata
; CHECK-NEXT: Force set function attributes
; CHECK-NEXT: Infer set function attributes
; CHECK-NEXT: Interprocedural Sparse Conditional Constant Propagation

View File

@ -0,0 +1,61 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -annotation2metadata -pass-remarks-analysis='annotation-remarks' -S %s | FileCheck %s
; RUN: opt -passes='annotation2metadata' -pass-remarks-analysis='annotation-remarks' -S %s | FileCheck %s
@.str = private unnamed_addr constant [10 x i8] c"_remarks1\00", section "llvm.metadata"
@.str.1 = private unnamed_addr constant [6 x i8] c"ann.c\00", section "llvm.metadata"
@.str.2 = private unnamed_addr constant [10 x i8] c"_remarks2\00", section "llvm.metadata"
@llvm.global.annotations = appending global [8 x { i8*, i8*, i8*, i32 }] [
{ i8*, i8*, i8*, i32 } { i8* bitcast (void (float*)* @test1 to i8*), i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i32 2 },
{ i8*, i8*, i8*, i32 } { i8* bitcast (void (float*)* @test1 to i8*), i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.2, i32 0, i32 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i32 2 },
{ i8*, i8*, i8*, i32 } { i8* bitcast (void (float*)* @test3 to i8*), i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str, i32 0, i32 0), i8* undef, i32 4 }, ; Invalid entry, make sure we do not crash.
{ i8*, i8*, i8*, i32 } { i8* bitcast (void (float*)* @test3 to i8*), i8* undef, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i32 4 }, ; Invalid entry, make sure we do not crash.
{ i8*, i8*, i8*, i32 } { i8* undef, i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i32 4 }, ; Invalid entry, make sure we do not crash.
{ i8*, i8*, i8*, i32 } { i8* bitcast (void (float*)* undef to i8*), i8* undef, i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i32 4 }, ; Invalid entry, make sure we do not crash.
{ i8*, i8*, i8*, i32 } { i8* undef, i8* undef, i8* undef, i32 300 }, ; Invalid entry, make sure we do not crash.
{ i8*, i8*, i8*, i32 } { i8* bitcast (void (float*)* @test3 to i8*), i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i32 4 }
], section "llvm.metadata"
define void @test1(float* %a) {
; CHECK-LABEL: @test1(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A_ADDR:%.*]] = alloca float*, align 8, !annotation [[GROUP1:!.+]]
; CHECK-NEXT: store float* [[A:%.*]], float** [[A_ADDR]], align 8, !annotation [[GROUP1]]
; CHECK-NEXT: ret void, !annotation [[GROUP1]]
;
entry:
%a.addr = alloca float*, align 8
store float* %a, float** %a.addr, align 8
ret void
}
define void @test2(float* %a) {
; CHECK-LABEL: @test2(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A_ADDR:%.*]] = alloca float*, align 8
; CHECK-NEXT: store float* [[A:%.*]], float** [[A_ADDR]], align 8
; CHECK-NEXT: ret void
;
entry:
%a.addr = alloca float*, align 8
store float* %a, float** %a.addr, align 8
ret void
}
define void @test3(float* %a) {
; CHECK-LABEL: @test3(
; CHECK-NEXT: entry:
; CHECK-NEXT: [[A_ADDR:%.*]] = alloca float*, align 8, !annotation [[GROUP2:!.+]]
; CHECK-NEXT: store float* [[A:%.*]], float** [[A_ADDR]], align 8, !annotation [[GROUP2]]
; CHECK-NEXT: ret void, !annotation [[GROUP2]]
;
entry:
%a.addr = alloca float*, align 8
store float* %a, float** %a.addr, align 8
ret void
}
; CHECK: [[GROUP1]] = !{!"_remarks1", !"_remarks2"}
; CHECK-NEXT: [[GROUP2]] = !{!"_remarks1"}