Index: llvm/include/llvm/Transforms/Utils/AutoInitRemark.h =================================================================== --- /dev/null +++ llvm/include/llvm/Transforms/Utils/AutoInitRemark.h @@ -0,0 +1,44 @@ +//===- AutoInitRemark.h - Auto-init remark analysis -*- C++ -------------*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// Provide more information about instructions with a "auto-init" +// !annotation metadata. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_TRANSFORMS_UTILS_AUTOINITREMARK_H +#define LLVM_TRANSFORMS_UTILS_AUTOINITREMARK_H + +#include "llvm/ADT/StringRef.h" + +namespace llvm { + +class StoreInst; +class Instruction; +class OptimizationRemarkEmitter; +class DataLayout; + +// FIXME: Once we get to more remarks like this one, we need to re-evaluate how +// much of this logic should actually go into the remark emitter. +struct AutoInitRemark { + OptimizationRemarkEmitter &ORE; + StringRef RemarkPass; + const DataLayout &DL; + + AutoInitRemark(OptimizationRemarkEmitter &ORE, StringRef RemarkPass, + const DataLayout &DL) + : ORE(ORE), RemarkPass(RemarkPass), DL(DL) {} + + void inspectStore(StoreInst &SI); + void inspectUnknown(Instruction &I); +}; + +} // namespace llvm + +#endif Index: llvm/lib/Transforms/Scalar/AnnotationRemarks.cpp =================================================================== --- llvm/lib/Transforms/Scalar/AnnotationRemarks.cpp +++ llvm/lib/Transforms/Scalar/AnnotationRemarks.cpp @@ -16,10 +16,12 @@ #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/IR/Function.h" #include "llvm/IR/InstIterator.h" +#include "llvm/IR/Instructions.h" #include "llvm/InitializePasses.h" #include "llvm/Pass.h" #include "llvm/Support/Debug.h" #include "llvm/Transforms/Scalar.h" +#include "llvm/Transforms/Utils/AutoInitRemark.h" using namespace llvm; using namespace llvm::ore; @@ -38,9 +40,20 @@ if (cast(Op.get())->getString() != "auto-init") continue; - ORE.emit( - OptimizationRemarkMissed(REMARK_PASS, "AutoInitUnknownInstruction", I) - << "Initialization inserted by -ftrivial-auto-var-init."); + Function &F = *I->getParent()->getParent(); + const DataLayout &DL = F.getParent()->getDataLayout(); + AutoInitRemark Remark(ORE, REMARK_PASS, DL); + // For some of them, we can provide more information: + + // For stores: + // * size + // * volatile / atomic + if (auto *SI = dyn_cast(I)) { + Remark.inspectStore(*SI); + continue; + } + + Remark.inspectUnknown(*I); } } } Index: llvm/lib/Transforms/Utils/AutoInitRemark.cpp =================================================================== --- /dev/null +++ llvm/lib/Transforms/Utils/AutoInitRemark.cpp @@ -0,0 +1,49 @@ +//===-- AutoInitRemark.cpp - Auto-init remark analysis---------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// +// +// Implementation of the analysis for the "auto-init" remark. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Utils/AutoInitRemark.h" +#include "llvm/Analysis/OptimizationRemarkEmitter.h" +#include "llvm/IR/Instructions.h" + +using namespace llvm; +using namespace llvm::ore; + +void AutoInitRemark::inspectStore(StoreInst &SI) { + bool Volatile = SI.isVolatile(); + bool Atomic = SI.isAtomic(); + int64_t Size = DL.getTypeStoreSize(SI.getOperand(0)->getType()); + + OptimizationRemarkMissed R(RemarkPass.data(), "AutoInitStore", &SI); + R << "Store inserted by -ftrivial-auto-var-init.\nStore size: " + << NV("StoreSize", Size) << " bytes."; + if (Volatile) + R << " Volatile: " << NV("StoreVolatile", true) << "."; + if (Atomic) + R << " Atomic: " << NV("StoreAtomic", true) << "."; + // Emit StoreVolatile: false and StoreAtomic: false under ExtraArgs. This + // won't show them in the remark message but will end up in the serialized + // remarks. + if (!Volatile || !Atomic) + R << setExtraArgs(); + if (!Volatile) + R << " Volatile: " << NV("StoreVolatile", false) << "."; + if (!Atomic) + R << " Atomic: " << NV("StoreAtomic", false) << "."; + + ORE.emit(R); +} + +void AutoInitRemark::inspectUnknown(Instruction &I) { + ORE.emit(OptimizationRemarkMissed(RemarkPass.data(), + "AutoInitUnknownInstruction", &I) + << "Initialization inserted by -ftrivial-auto-var-init."); +} Index: llvm/lib/Transforms/Utils/CMakeLists.txt =================================================================== --- llvm/lib/Transforms/Utils/CMakeLists.txt +++ llvm/lib/Transforms/Utils/CMakeLists.txt @@ -3,6 +3,7 @@ AMDGPUEmitPrintf.cpp ASanStackFrameLayout.cpp AssumeBundleBuilder.cpp + AutoInitRemark.cpp BasicBlockUtils.cpp BreakCriticalEdges.cpp BuildLibCalls.cpp Index: llvm/test/Transforms/Util/trivial-auto-var-init-store.ll =================================================================== --- llvm/test/Transforms/Util/trivial-auto-var-init-store.ll +++ llvm/test/Transforms/Util/trivial-auto-var-init-store.ll @@ -3,14 +3,23 @@ ; Emit a remark that reports a store. define void @store(i32* %dst) { -; CHECK: Initialization inserted by -ftrivial-auto-var-init. +; CHECK: Store inserted by -ftrivial-auto-var-init. +; CHECK-NEXT: Store size: 4 bytes. ; YAML-LABEL: --- !Missed ; YAML-NEXT: Pass: annotation-remarks -; YAML-NEXT: Name: AutoInitUnknownInstruction +; YAML-NEXT: Name: AutoInitStore ; YAML-NEXT: DebugLoc: ; YAML-NEXT: Function: store ; YAML-NEXT: Args: -; YAML-NEXT: - String: Initialization inserted by -ftrivial-auto-var-init. +; YAML-NEXT: - String: "Store inserted by -ftrivial-auto-var-init.\nStore size: " +; YAML-NEXT: - StoreSize: '4' +; YAML-NEXT: - String: ' bytes.' +; YAML-NEXT: - String: ' Volatile: ' +; YAML-NEXT: - StoreVolatile: 'false' +; YAML-NEXT: - String: . +; YAML-NEXT: - String: ' Atomic: ' +; YAML-NEXT: - StoreAtomic: 'false' +; YAML-NEXT: - String: . ; YAML-NEXT: ... store i32 0, i32* %dst, !annotation !0, !dbg !DILocation(scope: !4) ret void @@ -18,14 +27,23 @@ ; Emit a remark that reports a volatile store. define void @volatile_store(i32* %dst) { -; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; CHECK-NEXT: Store inserted by -ftrivial-auto-var-init. +; CHECK-NEXT: Store size: 4 bytes. Volatile: true. ; YAML-LABEL: --- !Missed ; YAML-NEXT: Pass: annotation-remarks -; YAML-NEXT: Name: AutoInitUnknownInstruction +; YAML-NEXT: Name: AutoInitStore ; YAML-NEXT: DebugLoc: ; YAML-NEXT: Function: volatile_store ; YAML-NEXT: Args: -; YAML-NEXT: - String: Initialization inserted by -ftrivial-auto-var-init. +; YAML-NEXT: - String: "Store inserted by -ftrivial-auto-var-init.\nStore size: " +; YAML-NEXT: - StoreSize: '4' +; YAML-NEXT: - String: ' bytes.' +; YAML-NEXT: - String: ' Volatile: ' +; YAML-NEXT: - StoreVolatile: 'true' +; YAML-NEXT: - String: . +; YAML-NEXT: - String: ' Atomic: ' +; YAML-NEXT: - StoreAtomic: 'false' +; YAML-NEXT: - String: . ; YAML-NEXT: ... store volatile i32 0, i32* %dst, !annotation !0, !dbg !DILocation(scope: !4) ret void @@ -33,14 +51,23 @@ ; Emit a remark that reports an atomic store. define void @atomic_store(i32* %dst) { -; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; CHECK-NEXT: Store inserted by -ftrivial-auto-var-init. +; CHECK-NEXT: Store size: 4 bytes. Atomic: true. ; YAML-LABEL: --- !Missed ; YAML-NEXT: Pass: annotation-remarks -; YAML-NEXT: Name: AutoInitUnknownInstruction +; YAML-NEXT: Name: AutoInitStore ; YAML-NEXT: DebugLoc: ; YAML-NEXT: Function: atomic_store ; YAML-NEXT: Args: -; YAML-NEXT: - String: Initialization inserted by -ftrivial-auto-var-init. +; YAML-NEXT: - String: "Store inserted by -ftrivial-auto-var-init.\nStore size: " +; YAML-NEXT: - StoreSize: '4' +; YAML-NEXT: - String: ' bytes.' +; YAML-NEXT: - String: ' Atomic: ' +; YAML-NEXT: - StoreAtomic: 'true' +; YAML-NEXT: - String: . +; YAML-NEXT: - String: ' Volatile: ' +; YAML-NEXT: - StoreVolatile: 'false' +; YAML-NEXT: - String: . ; YAML-NEXT: ... store atomic i32 0, i32* %dst unordered, align 4, !annotation !0, !dbg !DILocation(scope: !4) ret void @@ -48,14 +75,23 @@ ; Emit a remark that reports a store to an alloca. define void @store_alloca() { -; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; CHECK-NEXT: Store inserted by -ftrivial-auto-var-init. +; CHECK-NEXT: Store size: 4 bytes. ; YAML-LABEL: --- !Missed ; YAML-NEXT: Pass: annotation-remarks -; YAML-NEXT: Name: AutoInitUnknownInstruction +; YAML-NEXT: Name: AutoInitStore ; YAML-NEXT: DebugLoc: ; YAML-NEXT: Function: store_alloca ; YAML-NEXT: Args: -; YAML-NEXT: - String: Initialization inserted by -ftrivial-auto-var-init. +; YAML-NEXT: - String: "Store inserted by -ftrivial-auto-var-init.\nStore size: " +; YAML-NEXT: - StoreSize: '4' +; YAML-NEXT: - String: ' bytes.' +; YAML-NEXT: - String: ' Volatile: ' +; YAML-NEXT: - StoreVolatile: 'false' +; YAML-NEXT: - String: . +; YAML-NEXT: - String: ' Atomic: ' +; YAML-NEXT: - StoreAtomic: 'false' +; YAML-NEXT: - String: . ; YAML-NEXT: ... %dst = alloca i32 store i32 0, i32* %dst, !annotation !0, !dbg !DILocation(scope: !4) @@ -64,7 +100,8 @@ ; Emit a remark that reports a store to an alloca through a GEP. define void @store_alloca_gep() { -; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; CHECK-NEXT: Store inserted by -ftrivial-auto-var-init. +; CHECK-NEXT: Store size: 4 bytes. %dst = alloca i32 %gep = getelementptr i32, i32* %dst, i32 0 store i32 0, i32* %gep, !annotation !0, !dbg !DILocation(scope: !4) @@ -73,7 +110,8 @@ ; Emit a remark that reports a store to an alloca through a GEP in an array. define void @store_alloca_gep_array() { -; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; CHECK-NEXT: Store inserted by -ftrivial-auto-var-init. +; CHECK-NEXT: Store size: 4 bytes. %dst = alloca [2 x i32] %gep = getelementptr [2 x i32], [2 x i32]* %dst, i64 0, i64 0 store i32 0, i32* %gep, !annotation !0, !dbg !DILocation(scope: !4) @@ -82,7 +120,8 @@ ; Emit a remark that reports a store to an alloca through a bitcast. define void @store_alloca_bitcast() { -; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; CHECK-NEXT: Store inserted by -ftrivial-auto-var-init. +; CHECK-NEXT: Store size: 4 bytes. %dst = alloca [2 x i16] %bc = bitcast [2 x i16]* %dst to i32* store i32 0, i32* %bc, !annotation !0, !dbg !DILocation(scope: !4) @@ -92,7 +131,8 @@ ; Emit a remark that reports a store to an alloca that has a DILocalVariable ; attached. define void @store_alloca_di() { -; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; CHECK-NEXT: Store inserted by -ftrivial-auto-var-init. +; CHECK-NEXT: Store size: 4 bytes. %dst = alloca i32 store i32 0, i32* %dst, !annotation !0, !dbg !DILocation(scope: !4) call void @llvm.dbg.declare(metadata i32* %dst, metadata !6, metadata !DIExpression()), !dbg !DILocation(scope: !4) @@ -102,7 +142,8 @@ ; Emit a remark that reports a store to an alloca that has more than one ; DILocalVariable attached. define void @store_alloca_di_multiple() { -; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; CHECK-NEXT: Store inserted by -ftrivial-auto-var-init. +; CHECK-NEXT: Store size: 4 bytes. %dst = alloca i32 store i32 0, i32* %dst, !annotation !0, !dbg !DILocation(scope: !4) call void @llvm.dbg.declare(metadata i32* %dst, metadata !6, metadata !DIExpression()), !dbg !DILocation(scope: !4) @@ -113,7 +154,8 @@ ; Emit a remark that reports a store to a PHI node that can be two different ; allocas. define void @store_alloca_phi() { -; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; CHECK-NEXT: Store inserted by -ftrivial-auto-var-init. +; CHECK-NEXT: Store size: 4 bytes. entry: %dst = alloca i32 %dst2 = alloca i32 @@ -132,7 +174,8 @@ ; Emit a remark that reports a store to a PHI node that can be two different ; allocas, where one of it has multiple DILocalVariable. define void @store_alloca_phi_di_multiple() { -; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; CHECK-NEXT: Store inserted by -ftrivial-auto-var-init. +; CHECK-NEXT: Store size: 4 bytes. entry: %dst = alloca i32 %dst2 = alloca i32