operands give the execution count that each of the respective prior target
functions was called.
+.. _md_annotation:
+
+'``annotation``' Metadata
+^^^^^^^^^^^^^^^^^^^^^^^^^
+
+The ``annotation`` metadata can be used to attach a tuple of annotation strings
+to any instruction. This metadata does not impact the semantics of the program
+and may only be used to provide additional insight about the program and
+transformations to users.
+
+Example:
+
+.. code-block:: text
+
+ %a.addr = alloca float*, align 8, !annotation !0
+ !0 = !{!"auto-init"}
+
Module Flags Metadata
=====================
/// provide more context so that non-trivial false positives can be quickly
/// detected by the user.
bool allowExtraAnalysis(StringRef PassName) const {
- return (F->getContext().getLLVMRemarkStreamer() ||
- F->getContext().getDiagHandlerPtr()->isAnyRemarkEnabled(PassName));
+ return OptimizationRemarkEmitter::allowExtraAnalysis(*F, PassName);
+ }
+
+ static bool allowExtraAnalysis(const Function &F, StringRef PassName) {
+ return F.getContext().getLLVMRemarkStreamer() ||
+ F.getContext().getDiagHandlerPtr()->isAnyRemarkEnabled(PassName);
}
private:
LLVM_FIXED_MD_KIND(MD_preserve_access_index, "llvm.preserve.access.index", 27)
LLVM_FIXED_MD_KIND(MD_misexpect, "misexpect", 28)
LLVM_FIXED_MD_KIND(MD_vcall_visibility, "vcall_visibility", 29)
-LLVM_FIXED_MD_KIND(MD_noundef, "noundef", 30)
\ No newline at end of file
+LLVM_FIXED_MD_KIND(MD_noundef, "noundef", 30)
+LLVM_FIXED_MD_KIND(MD_annotation, "annotation", 31)
void initializeAlwaysInlinerLegacyPassPass(PassRegistry&);
void initializeAssumeSimplifyPassLegacyPassPass(PassRegistry &);
void initializeAssumeBuilderPassLegacyPassPass(PassRegistry &);
+void initializeAnnotationRemarksLegacyPass(PassRegistry &);
void initializeOpenMPOptLegacyPassPass(PassRegistry &);
void initializeArgPromotionPass(PassRegistry&);
void initializeAssumptionCacheTrackerPass(PassRegistry&);
//===----------------------------------------------------------------------===//
//
+// AnnotationRemarks - Emit remarks for !annotation metadata.
+//
+FunctionPass *createAnnotationRemarksLegacyPass();
+
+//===----------------------------------------------------------------------===//
+//
// SCCP - Sparse conditional constant propagation.
//
FunctionPass *createSCCPPass();
--- /dev/null
+//===- AnnotationRemarks.cpp - Emit remarks for !annotation MD --*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// \file
+// This file defines AnnotationRemarksPass for the new pass manager.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_TRANSFORMS_SCALAR_ANNOTATION_REMARKS_H
+#define LLVM_TRANSFORMS_SCALAR_ANNOTATION_REMARKS_H
+
+#include "llvm/IR/Function.h"
+#include "llvm/IR/PassManager.h"
+
+namespace llvm {
+struct AnnotationRemarksPass : public PassInfoMixin<AnnotationRemarksPass> {
+ PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
+};
+} // namespace llvm
+
+#endif // LLVM_TRANSFORMS_SCALAR_ANNOTATION_REMARKS_H
void visitRangeMetadata(Instruction &I, MDNode *Range, Type *Ty);
void visitDereferenceableMetadata(Instruction &I, MDNode *MD);
void visitProfMetadata(Instruction &I, MDNode *MD);
+ void visitAnnotationMetadata(MDNode *Annotation);
template <class Ty> bool isValidMetadataArray(const MDTuple &N);
#define HANDLE_SPECIALIZED_MDNODE_LEAF(CLASS) void visit##CLASS(const CLASS &N);
}
}
+void Verifier::visitAnnotationMetadata(MDNode *Annotation) {
+ Assert(isa<MDTuple>(Annotation), "annotation must be a tuple");
+ Assert(Annotation->getNumOperands() >= 1,
+ "annotation must have at least one operand");
+ for (const MDOperand &Op : Annotation->operands())
+ Assert(isa<MDString>(Op.get()), "operands must be strings");
+}
+
/// verifyInstruction - Verify that an instruction is well formed.
///
void Verifier::visitInstruction(Instruction &I) {
if (MDNode *MD = I.getMetadata(LLVMContext::MD_prof))
visitProfMetadata(I, MD);
+ if (MDNode *Annotation = I.getMetadata(LLVMContext::MD_annotation))
+ visitAnnotationMetadata(Annotation);
+
if (MDNode *N = I.getDebugLoc().getAsMDNode()) {
AssertDI(isa<DILocation>(N), "invalid !dbg metadata attachment", &I, N);
visitMDNode(*N, AreDebugLocsAllowed::Yes);
#include "llvm/Transforms/ObjCARC.h"
#include "llvm/Transforms/Scalar/ADCE.h"
#include "llvm/Transforms/Scalar/AlignmentFromAssumptions.h"
+#include "llvm/Transforms/Scalar/AnnotationRemarks.h"
#include "llvm/Transforms/Scalar/BDCE.h"
#include "llvm/Transforms/Scalar/CallSiteSplitting.h"
#include "llvm/Transforms/Scalar/ConstantHoisting.h"
C(LAM);
}
+// Helper to add AnnotationRemarksPass.
+static void addAnnotationRemarksPass(ModulePassManager &MPM) {
+ FunctionPassManager FPM;
+ FPM.addPass(AnnotationRemarksPass());
+ MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
+}
+
// TODO: Investigate the cost/benefit of tail call elimination on debugging.
FunctionPassManager
PassBuilder::buildO1FunctionSimplificationPipeline(OptimizationLevel Level,
// Now add the optimization pipeline.
MPM.addPass(buildModuleOptimizationPipeline(Level, LTOPreLink));
+ // Emit annotation remarks.
+ addAnnotationRemarksPass(MPM);
+
return MPM;
}
if (PTO.Coroutines)
MPM.addPass(createModuleToFunctionPassAdaptor(CoroCleanupPass()));
+ // Emit annotation remarks.
+ addAnnotationRemarksPass(MPM);
+
return MPM;
}
// Now add the optimization pipeline.
MPM.addPass(buildModuleOptimizationPipeline(Level));
+ // Emit annotation remarks.
+ addAnnotationRemarksPass(MPM);
+
return MPM;
}
// Run a second time to clean up any type tests left behind by WPD for use
// in ICP.
MPM.addPass(LowerTypeTestsPass(nullptr, nullptr, true));
+
+ // Emit annotation remarks.
+ addAnnotationRemarksPass(MPM);
+
return MPM;
}
// in ICP (which is performed earlier than this in the regular LTO
// pipeline).
MPM.addPass(LowerTypeTestsPass(nullptr, nullptr, true));
+
+ // Emit annotation remarks.
+ addAnnotationRemarksPass(MPM);
+
return MPM;
}
// Now that we have optimized the program, discard unreachable functions.
MPM.addPass(GlobalDCEPass());
+ // Emit annotation remarks.
+ addAnnotationRemarksPass(MPM);
+
// FIXME: Maybe enable MergeFuncs conditionally after it's ported.
return MPM;
}
FUNCTION_PASS("assume-builder", AssumeBuilderPass())
FUNCTION_PASS("assume-simplify", AssumeSimplifyPass())
FUNCTION_PASS("alignment-from-assumptions", AlignmentFromAssumptionsPass())
+FUNCTION_PASS("annotation-remarks", AnnotationRemarksPass())
FUNCTION_PASS("bdce", BDCEPass())
FUNCTION_PASS("bounds-checking", BoundsCheckingPass())
FUNCTION_PASS("break-crit-edges", BreakCriticalEdgesPass())
// Rename anon globals to be able to handle them in the summary
MPM.add(createNameAnonGlobalPass());
}
+
+ MPM.add(createAnnotationRemarksLegacyPass());
}
void PassManagerBuilder::addLTOOptimizationPasses(legacy::PassManagerBase &PM) {
addExtensionsToPM(EP_FullLinkTimeOptimizationLast, PM);
+ PM.add(createAnnotationRemarksLegacyPass());
+
if (VerifyOutput)
PM.add(createVerifierPass());
}
--- /dev/null
+//===-- AnnotationRemarks.cpp - Generate remarks for annotated instrs. ----===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Generate remarks for instructions marked with !annotation.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/Transforms/Scalar/AnnotationRemarks.h"
+#include "llvm/ADT/MapVector.h"
+#include "llvm/Analysis/OptimizationRemarkEmitter.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/InstIterator.h"
+#include "llvm/InitializePasses.h"
+#include "llvm/Pass.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Transforms/Scalar.h"
+
+using namespace llvm;
+using namespace llvm::ore;
+
+#define DEBUG_TYPE "annotation-remarks"
+#define REMARK_PASS DEBUG_TYPE
+
+static void runImpl(Function &F) {
+ if (!OptimizationRemarkEmitter::allowExtraAnalysis(F, REMARK_PASS))
+ return;
+
+ OptimizationRemarkEmitter ORE(&F);
+ // For now, just generate a summary of the annotated instructions.
+ MapVector<StringRef, unsigned> Mapping;
+ for (Instruction &I : instructions(F)) {
+ if (!I.hasMetadata(LLVMContext::MD_annotation))
+ continue;
+ for (const MDOperand &Op :
+ I.getMetadata(LLVMContext::MD_annotation)->operands()) {
+ auto Iter = Mapping.insert({cast<MDString>(Op.get())->getString(), 0});
+ Iter.first->second++;
+ }
+ }
+
+ Instruction *IP = &*F.begin()->begin();
+ for (const auto &KV : Mapping)
+ ORE.emit(OptimizationRemarkAnalysis(REMARK_PASS, "AnnotationSummary", IP)
+ << "Annotated " << NV("count", KV.second) << " instructions with "
+ << NV("type", KV.first));
+}
+
+namespace {
+
+struct AnnotationRemarksLegacy : public FunctionPass {
+ static char ID;
+
+ AnnotationRemarksLegacy() : FunctionPass(ID) {
+ initializeAnnotationRemarksLegacyPass(*PassRegistry::getPassRegistry());
+ }
+
+ bool runOnFunction(Function &F) override {
+ runImpl(F);
+ return false;
+ }
+
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ AU.setPreservesAll();
+ }
+};
+
+} // end anonymous namespace
+
+char AnnotationRemarksLegacy::ID = 0;
+
+INITIALIZE_PASS_BEGIN(AnnotationRemarksLegacy, "annotation-remarks",
+ "Annotation Remarks", false, false)
+INITIALIZE_PASS_END(AnnotationRemarksLegacy, "annotation-remarks",
+ "Annotation Remarks", false, false)
+
+FunctionPass *llvm::createAnnotationRemarksLegacyPass() {
+ return new AnnotationRemarksLegacy();
+}
+
+PreservedAnalyses AnnotationRemarksPass::run(Function &F,
+ FunctionAnalysisManager &AM) {
+ runImpl(F);
+ return PreservedAnalyses::all();
+}
add_llvm_component_library(LLVMScalarOpts
ADCE.cpp
AlignmentFromAssumptions.cpp
+ AnnotationRemarks.cpp
BDCE.cpp
CallSiteSplitting.cpp
ConstantHoisting.cpp
/// ScalarOpts library.
void llvm::initializeScalarOpts(PassRegistry &Registry) {
initializeADCELegacyPassPass(Registry);
+ initializeAnnotationRemarksLegacyPass(Registry);
initializeBDCELegacyPassPass(Registry);
initializeAlignmentFromAssumptionsPass(Registry);
initializeCallSiteSplittingLegacyPassPass(Registry);
; GCN-O1-NEXT: Remove redundant instructions
; GCN-O1-NEXT: Hoist/decompose integer division and remainder
; GCN-O1-NEXT: Simplify the CFG
+; GCN-O1-NEXT: Annotation Remarks
; GCN-O1-NEXT: Pass Arguments:
; GCN-O1-NEXT: FunctionPass Manager
; GCN-O2-NEXT: Remove redundant instructions
; GCN-O2-NEXT: Hoist/decompose integer division and remainder
; GCN-O2-NEXT: Simplify the CFG
+; GCN-O2-NEXT: Annotation Remarks
; GCN-O2-NEXT: Pass Arguments:
; GCN-O2-NEXT: FunctionPass Manager
; GCN-O3-NEXT: Remove redundant instructions
; GCN-O3-NEXT: Hoist/decompose integer division and remainder
; GCN-O3-NEXT: Simplify the CFG
+; GCN-O3-NEXT: Annotation Remarks
; GCN-O3-NEXT: Pass Arguments:
; GCN-O3-NEXT: FunctionPass Manager
; CHECK-O-NEXT: Running pass: CGProfilePass
; CHECK-O-NEXT: Running pass: GlobalDCEPass
; CHECK-O-NEXT: Running pass: ConstantMergePass
+; CHECK-O-NEXT: Running pass: AnnotationRemarksPass on foo
; CHECK-O-NEXT: Running pass: PrintModulePass
;
; Make sure we get the IR back out without changes when we print the module.
; CHECK-O2-NEXT: Running pass: SimplifyCFGPass
; CHECK-O2-NEXT: Running pass: EliminateAvailableExternallyPass
; CHECK-O2-NEXT: Running pass: GlobalDCEPass
+; CHECK-O-NEXT: Running pass: AnnotationRemarksPass on foo
; CHECK-O-NEXT: Running pass: PrintModulePass
; Make sure we get the IR back out without changes when we print the module.
; CHECK-POSTLINK-O-NEXT: Running pass: CGProfilePass
; CHECK-POSTLINK-O-NEXT: Running pass: GlobalDCEPass
; CHECK-POSTLINK-O-NEXT: Running pass: ConstantMergePass
+; CHECK-O-NEXT: Running pass: AnnotationRemarksPass on foo
; CHECK-PRELINK-O-NEXT: Running pass: NameAnonGlobalPass
; CHECK-O-NEXT: Running pass: PrintModulePass
; CHECK-O-NEXT: Running pass: CGProfilePass
; CHECK-O-NEXT: Running pass: GlobalDCEPass
; CHECK-O-NEXT: Running pass: ConstantMergePass
+; CHECK-O-NEXT: Running pass: AnnotationRemarksPass on foo
; CHECK-O-NEXT: Running pass: PrintModulePass
; Make sure we get the IR back out without changes when we print the module.
; CHECK-O-NEXT: Running pass: CGProfilePass
; CHECK-O-NEXT: Running pass: GlobalDCEPass
; CHECK-O-NEXT: Running pass: ConstantMergePass
+; CHECK-O-NEXT: Running pass: AnnotationRemarksPass on foo
; CHECK-O-NEXT: Running pass: PrintModulePass
; Make sure we get the IR back out without changes when we print the module.
; CHECK-O-NEXT: Running pass: GlobalOptPass
; CHECK-O-NEXT: Running analysis: TargetLibraryAnalysis on bar
; CHECK-EXT: Running pass: {{.*}}::Bye
+; CHECK-O-NEXT: Running pass: AnnotationRemarksPass on foo
; CHECK-O-NEXT: Running pass: NameAnonGlobalPass
; CHECK-O-NEXT: Running pass: PrintModulePass
; CHECK-O-NEXT: Finished CGSCC pass manager run.
; CHECK-O-NEXT: Finished {{.*}}Module pass manager run.
; CHECK-O-NEXT: Running pass: GlobalOptPass
+; CHECK-O-NEXT: Running pass: AnnotationRemarksPass on foo
; CHECK-O-NEXT: Running pass: NameAnonGlobalPass
; CHECK-O-NEXT: Running pass: PrintModulePass
; CHECK-NEXT: Eliminate Available Externally Globals
; CHECK-NEXT: Dead Global Elimination
; CHECK-NEXT: FunctionPass Manager
+; CHECK-NEXT: Annotation Remarks
; CHECK-NEXT: Module Verifier
; CHECK-NEXT: Bitcode Writer
; CHECK-NEXT: Pass Arguments:
; CHECK-NEXT: Remove redundant instructions
; CHECK-NEXT: Hoist/decompose integer division and remainder
; CHECK-NEXT: Simplify the CFG
+; CHECK-NEXT: Annotation Remarks
; CHECK-NEXT: Module Verifier
; CHECK-NEXT: Bitcode Writer
; CHECK-NEXT: Pass Arguments:
; CHECK-NEXT: Remove redundant instructions
; CHECK-NEXT: Hoist/decompose integer division and remainder
; CHECK-NEXT: Simplify the CFG
+; CHECK-NEXT: Annotation Remarks
; CHECK-NEXT: Module Verifier
; CHECK-NEXT: Bitcode Writer
; CHECK-NEXT: Pass Arguments:
; CHECK-NEXT: Remove redundant instructions
; CHECK-NEXT: Hoist/decompose integer division and remainder
; CHECK-NEXT: Simplify the CFG
+; CHECK-NEXT: Annotation Remarks
; CHECK-NEXT: Module Verifier
; CHECK-NEXT: Bitcode Writer
; CHECK-NEXT: Pass Arguments:
; CHECK-NEXT: Remove redundant instructions
; CHECK-NEXT: Hoist/decompose integer division and remainder
; CHECK-NEXT: Simplify the CFG
+; CHECK-NEXT: Annotation Remarks
; CHECK-NEXT: Module Verifier
; CHECK-NEXT: Bitcode Writer
; CHECK-NEXT: Pass Arguments:
--- /dev/null
+; RUN: opt -annotation-remarks -pass-remarks-missed='annotation-remarks' -disable-output -pass-remarks-output=%t.opt.yaml %s
+; RUN: FileCheck --input-file=%t.opt.yaml %s
+; RUN: opt -passes='annotation-remarks' -pass-remarks-missed='annotation-remarks' -disable-output -pass-remarks-output=%t.opt.yaml %s
+; RUN: FileCheck --input-file=%t.opt.yaml %s
+
+; CHECK: --- !Analysis
+; CHECK-NEXT: Pass: annotation-remarks
+; CHECK-NEXT: Name: AnnotationSummary
+; CHECK-NEXT: Function: test1
+; CHECK-NEXT: Args:
+; CHECK-NEXT: - String: 'Annotated '
+; CHECK-NEXT: - count: '4'
+; CHECK-NEXT: - String: ' instructions with '
+; CHECK-NEXT: - type: _remarks1
+; CHECK-NEXT: ...
+; CHECK-NEXT: --- !Analysis
+; CHECK-NEXT: Pass: annotation-remarks
+; CHECK-NEXT: Name: AnnotationSummary
+; CHECK-NEXT: Function: test1
+; CHECK-NEXT: Args:
+; CHECK-NEXT: - String: 'Annotated '
+; CHECK-NEXT: - count: '3'
+; CHECK-NEXT: - String: ' instructions with '
+; CHECK-NEXT: - type: _remarks2
+; CHECK-NEXT: ...
+; CHECK-NEXT: --- !Analysis
+; CHECK-NEXT: Pass: annotation-remarks
+; CHECK-NEXT: Name: AnnotationSummary
+; CHECK-NEXT: Function: test2
+; CHECK-NEXT: Args:
+; CHECK-NEXT: - String: 'Annotated '
+; CHECK-NEXT: - count: '2'
+; CHECK-NEXT: - String: ' instructions with '
+; CHECK-NEXT: - type: _remarks1
+; CHECK-NEXT: ...
+
+define void @test1(float* %a) {
+entry:
+ %a.addr = alloca float*, align 8, !annotation !0
+ store float* null, float** %a.addr, align 8, !annotation !1
+ store float* %a, float** %a.addr, align 8, !annotation !0
+ ret void, !annotation !0
+}
+
+define void @test2(float* %a) {
+entry:
+ %a.addr = alloca float*, align 8, !annotation !1
+ ret void, !annotation !1
+}
+
+!0 = !{!"_remarks1", !"_remarks2"}
+!1 = !{!"_remarks1"}
--- /dev/null
+; RUN: not llvm-as -disable-output < %s -o /dev/null 2>&1 | FileCheck %s
+
+define void @test1(float* %a) {
+entry:
+; CHECK: annotation must have at least one operand
+ %a.addr = alloca float*, align 8, !annotation !0
+
+; CHECK-NEXT: operands must be strings
+ ret void, !annotation !1
+}
+
+!0 = !{}
+!1 = !{i32 10}