diff --git a/llvm/lib/Transforms/Scalar/AnnotationRemarks.cpp b/llvm/lib/Transforms/Scalar/AnnotationRemarks.cpp --- a/llvm/lib/Transforms/Scalar/AnnotationRemarks.cpp +++ b/llvm/lib/Transforms/Scalar/AnnotationRemarks.cpp @@ -27,16 +27,40 @@ #define DEBUG_TYPE "annotation-remarks" #define REMARK_PASS DEBUG_TYPE +static void tryEmitAutoInitRemark(ArrayRef Instructions, + OptimizationRemarkEmitter &ORE) { + // For every auto-init annotation generate a separate remark. + for (Instruction *I : Instructions) { + if (!I->hasMetadata(LLVMContext::MD_annotation)) + continue; + for (const MDOperand &Op : + I->getMetadata(LLVMContext::MD_annotation)->operands()) { + if (cast(Op.get())->getString() != "auto-init") + continue; + + ORE.emit( + OptimizationRemarkMissed(REMARK_PASS, "AutoInitUnknownInstruction", I) + << "Initialization inserted by -ftrivial-auto-var-init."); + } + } +} + static void runImpl(Function &F) { if (!OptimizationRemarkEmitter::allowExtraAnalysis(F, REMARK_PASS)) return; + // Track all annotated instructions aggregated based on their debug location. + DenseMap> DebugLoc2Annotated; + OptimizationRemarkEmitter ORE(&F); - // For now, just generate a summary of the annotated instructions. + // First, generate a summary of the annotated instructions. MapVector Mapping; for (Instruction &I : instructions(F)) { if (!I.hasMetadata(LLVMContext::MD_annotation)) continue; + auto Iter = DebugLoc2Annotated.insert({I.getDebugLoc().getAsMDNode(), {}}); + Iter.first->second.push_back(&I); + for (const MDOperand &Op : I.getMetadata(LLVMContext::MD_annotation)->operands()) { auto Iter = Mapping.insert({cast(Op.get())->getString(), 0}); @@ -49,6 +73,16 @@ ORE.emit(OptimizationRemarkAnalysis(REMARK_PASS, "AnnotationSummary", IP) << "Annotated " << NV("count", KV.second) << " instructions with " << NV("type", KV.first)); + + // For each debug location, look for all the instructions with annotations and + // generate more detailed remarks to be displayed at that location. + for (auto &KV : DebugLoc2Annotated) { + // Don't generate remarks with no debug location. + if (!KV.first) + continue; + + tryEmitAutoInitRemark(KV.second, ORE); + } } namespace { diff --git a/llvm/test/Transforms/Util/trivial-auto-var-init-call.ll b/llvm/test/Transforms/Util/trivial-auto-var-init-call.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/Util/trivial-auto-var-init-call.ll @@ -0,0 +1,365 @@ +; RUN: opt -annotation-remarks -o /dev/null -S -pass-remarks-output=%t.opt.yaml %s -pass-remarks-missed=annotation-remarks 2>&1 | FileCheck %s +; RUN: cat %t.opt.yaml | FileCheck -check-prefix=YAML %s + +; Emit remarks for memcpy, memmove, memset, bzero. +define void @known_call(i8* %src, i8* %dst, i64 %size) { +; CHECK: Initialization inserted by -ftrivial-auto-var-init. +; YAML-LABEL: --- !Missed +; YAML-NEXT: Pass: annotation-remarks +; YAML-NEXT: Name: AutoInitUnknownInstruction +; YAML-NEXT: DebugLoc: +; YAML-NEXT: Function: known_call +; YAML-NEXT: Args: +; YAML-NEXT: - String: Initialization inserted by -ftrivial-auto-var-init. +; YAML-NEXT: ... + call void @llvm.memset.p0i8.i64(i8* %dst, i8 0, i64 %size, i1 false), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; YAML-LABEL: --- !Missed +; YAML-NEXT: Pass: annotation-remarks +; YAML-NEXT: Name: AutoInitUnknownInstruction +; YAML-NEXT: DebugLoc: +; YAML-NEXT: Function: known_call +; YAML-NEXT: Args: +; YAML-NEXT: - String: Initialization inserted by -ftrivial-auto-var-init. +; YAML-NEXT: ... + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 %size, i1 false), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; YAML-LABEL: --- !Missed +; YAML-NEXT: Pass: annotation-remarks +; YAML-NEXT: Name: AutoInitUnknownInstruction +; YAML-NEXT: DebugLoc: +; YAML-NEXT: Function: known_call +; YAML-NEXT: Args: +; YAML-NEXT: - String: Initialization inserted by -ftrivial-auto-var-init. +; YAML-NEXT: ... + call void @llvm.memmove.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 %size, i1 false), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. + +; YAML-LABEL: --- !Missed +; YAML-NEXT: Pass: annotation-remarks +; YAML-NEXT: Name: AutoInitUnknownInstruction +; YAML-NEXT: DebugLoc: +; YAML-NEXT: Function: known_call +; YAML-NEXT: Args: +; YAML-NEXT: - String: Initialization inserted by -ftrivial-auto-var-init. +; YAML-NEXT: ... + call void @bzero(i8* %dst, i64 %size), !annotation !0, !dbg !DILocation(scope: !4) + ret void +} + +; Emit remarks for memcpy, memmove, memset, bzero with known constant sizes. +define void @known_call_with_size(i8* %src, i8* %dst) { +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; YAML-LABEL: --- !Missed +; YAML-NEXT: Pass: annotation-remarks +; YAML-NEXT: Name: AutoInitUnknownInstruction +; YAML-NEXT: DebugLoc: +; YAML-NEXT: Function: known_call_with_size +; YAML-NEXT: Args: +; YAML-NEXT: - String: Initialization inserted by -ftrivial-auto-var-init. +; YAML-NEXT: ... + call void @llvm.memset.p0i8.i64(i8* %dst, i8 0, i64 32, i1 false), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; YAML-LABEL: --- !Missed +; YAML-NEXT: Pass: annotation-remarks +; YAML-NEXT: Name: AutoInitUnknownInstruction +; YAML-NEXT: DebugLoc: +; YAML-NEXT: Function: known_call_with_size +; YAML-NEXT: Args: +; YAML-NEXT: - String: Initialization inserted by -ftrivial-auto-var-init. +; YAML-NEXT: ... + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 32, i1 false), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; YAML-LABEL: --- !Missed +; YAML-NEXT: Pass: annotation-remarks +; YAML-NEXT: Name: AutoInitUnknownInstruction +; YAML-NEXT: DebugLoc: +; YAML-NEXT: Function: known_call_with_size +; YAML-NEXT: Args: +; YAML-NEXT: - String: Initialization inserted by -ftrivial-auto-var-init. +; YAML-NEXT: ... + call void @llvm.memmove.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 32, i1 false), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; YAML-LABEL: --- !Missed +; YAML-NEXT: Pass: annotation-remarks +; YAML-NEXT: Name: AutoInitUnknownInstruction +; YAML-NEXT: DebugLoc: +; YAML-NEXT: Function: known_call_with_size +; YAML-NEXT: Args: +; YAML-NEXT: - String: Initialization inserted by -ftrivial-auto-var-init. +; YAML-NEXT: ... + call void @bzero(i8* %dst, i64 32), !annotation !0, !dbg !DILocation(scope: !4) + + ret void +} + +; Emit remarks for memcpy, memmove, memset marked volatile. +define void @known_call_volatile(i8* %src, i8* %dst, i64 %size) { +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; YAML-LABEL: --- !Missed +; YAML-NEXT: Pass: annotation-remarks +; YAML-NEXT: Name: AutoInitUnknownInstruction +; YAML-NEXT: DebugLoc: +; YAML-NEXT: Function: known_call_volatile +; YAML-NEXT: Args: +; YAML-NEXT: - String: Initialization inserted by -ftrivial-auto-var-init. +; YAML-NEXT: ... + call void @llvm.memset.p0i8.i64(i8* %dst, i8 0, i64 %size, i1 true), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; YAML-LABEL: --- !Missed +; YAML-NEXT: Pass: annotation-remarks +; YAML-NEXT: Name: AutoInitUnknownInstruction +; YAML-NEXT: DebugLoc: +; YAML-NEXT: Function: known_call_volatile +; YAML-NEXT: Args: +; YAML-NEXT: - String: Initialization inserted by -ftrivial-auto-var-init. +; YAML-NEXT: ... + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 %size, i1 true), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; YAML-LABEL: --- !Missed +; YAML-NEXT: Pass: annotation-remarks +; YAML-NEXT: Name: AutoInitUnknownInstruction +; YAML-NEXT: DebugLoc: +; YAML-NEXT: Function: known_call_volatile +; YAML-NEXT: Args: +; YAML-NEXT: - String: Initialization inserted by -ftrivial-auto-var-init. +; YAML-NEXT: ... + call void @llvm.memmove.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 %size, i1 true), !annotation !0, !dbg !DILocation(scope: !4) + ret void +} + +; Emit remarks for memcpy, memmove, memset marked atomic. +define void @known_call_atomic(i8* %src, i8* %dst, i64 %size) { +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; YAML-LABEL: --- !Missed +; YAML-NEXT: Pass: annotation-remarks +; YAML-NEXT: Name: AutoInitUnknownInstruction +; YAML-NEXT: DebugLoc: +; YAML-NEXT: Function: known_call_atomic +; YAML-NEXT: Args: +; YAML-NEXT: - String: Initialization inserted by -ftrivial-auto-var-init. +; YAML-NEXT: ... + call void @llvm.memset.element.unordered.atomic.p0i8.i64(i8* align 1 %dst, i8 0, i64 %size, i32 1), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; YAML-LABEL: --- !Missed +; YAML-NEXT: Pass: annotation-remarks +; YAML-NEXT: Name: AutoInitUnknownInstruction +; YAML-NEXT: DebugLoc: +; YAML-NEXT: Function: known_call_atomic +; YAML-NEXT: Args: +; YAML-NEXT: - String: Initialization inserted by -ftrivial-auto-var-init. +; YAML-NEXT: ... + call void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 %dst, i8* align 1 %src, i64 %size, i32 1), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; YAML-LABEL: --- !Missed +; YAML-NEXT: Pass: annotation-remarks +; YAML-NEXT: Name: AutoInitUnknownInstruction +; YAML-NEXT: DebugLoc: +; YAML-NEXT: Function: known_call_atomic +; YAML-NEXT: Args: +; YAML-NEXT: - String: Initialization inserted by -ftrivial-auto-var-init. +; YAML-NEXT: ... + call void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i64(i8* align 1 %dst, i8* align 1 %src, i64 %size, i32 1), !annotation !0, !dbg !DILocation(scope: !4) + ret void +} + +; Emit remarks for memcpy, memmove, memset, bzero with known constant sizes to +; an alloca. +define void @known_call_with_size_alloca(i8* %src) { +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; YAML-LABEL: --- !Missed +; YAML-NEXT: Pass: annotation-remarks +; YAML-NEXT: Name: AutoInitUnknownInstruction +; YAML-NEXT: DebugLoc: +; YAML-NEXT: Function: known_call_with_size_alloca +; YAML-NEXT: Args: +; YAML-NEXT: - String: Initialization inserted by -ftrivial-auto-var-init. +; YAML-NEXT: ... + %dst = alloca i8 + call void @llvm.memset.p0i8.i64(i8* %dst, i8 0, i64 1, i1 false), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; YAML-LABEL: --- !Missed +; YAML-NEXT: Pass: annotation-remarks +; YAML-NEXT: Name: AutoInitUnknownInstruction +; YAML-NEXT: DebugLoc: +; YAML-NEXT: Function: known_call_with_size_alloca +; YAML-NEXT: Args: +; YAML-NEXT: - String: Initialization inserted by -ftrivial-auto-var-init. +; YAML-NEXT: ... + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 1, i1 false), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; YAML-LABEL: --- !Missed +; YAML-NEXT: Pass: annotation-remarks +; YAML-NEXT: Name: AutoInitUnknownInstruction +; YAML-NEXT: DebugLoc: +; YAML-NEXT: Function: known_call_with_size_alloca +; YAML-NEXT: Args: +; YAML-NEXT: - String: Initialization inserted by -ftrivial-auto-var-init. +; YAML-NEXT: ... + call void @llvm.memmove.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 1, i1 false), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; YAML-LABEL: --- !Missed +; YAML-NEXT: Pass: annotation-remarks +; YAML-NEXT: Name: AutoInitUnknownInstruction +; YAML-NEXT: DebugLoc: +; YAML-NEXT: Function: known_call_with_size_alloca +; YAML-NEXT: Args: +; YAML-NEXT: - String: Initialization inserted by -ftrivial-auto-var-init. +; YAML-NEXT: ... + call void @bzero(i8* %dst, i64 1), !annotation !0, !dbg !DILocation(scope: !4) + + ret void +} + +; Emit remarks for memcpy, memmove, memset, bzero with known constant sizes to +; an alloca through a GEP. +define void @known_call_with_size_alloca_gep(i8* %src) { +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. + %dst = alloca i8 + %gep = getelementptr i8, i8* %dst, i32 0 + call void @llvm.memset.p0i8.i64(i8* %gep, i8 0, i64 1, i1 false), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %gep, i8* %src, i64 1, i1 false), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. + call void @llvm.memmove.p0i8.p0i8.i64(i8* %gep, i8* %src, i64 1, i1 false), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. + call void @bzero(i8* %gep, i64 1), !annotation !0, !dbg !DILocation(scope: !4) + ret void +} + +; Emit remarks for memcpy, memmove, memset, bzero with known constant sizes to +; an alloca through a GEP in an array. +define void @known_call_with_size_alloca_gep_array(i8* %src) { +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. + %dst = alloca [2 x i8] + %gep = getelementptr [2 x i8], [2 x i8]* %dst, i64 0, i64 0 + call void @llvm.memset.p0i8.i64(i8* %gep, i8 0, i64 1, i1 false), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %gep, i8* %src, i64 1, i1 false), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. + call void @llvm.memmove.p0i8.p0i8.i64(i8* %gep, i8* %src, i64 1, i1 false), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. + call void @bzero(i8* %gep, i64 1), !annotation !0, !dbg !DILocation(scope: !4) + ret void +} + +; Emit remarks for memcpy, memmove, memset, bzero with known constant sizes to +; an alloca through a bitcast. +define void @known_call_with_size_alloca_bitcast(i8* %src) { +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. + %dst = alloca [2 x i8] + %bc = bitcast [2 x i8]* %dst to i8* + call void @llvm.memset.p0i8.i64(i8* %bc, i8 0, i64 1, i1 false), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %bc, i8* %src, i64 1, i1 false), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. + call void @llvm.memmove.p0i8.p0i8.i64(i8* %bc, i8* %src, i64 1, i1 false), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. + call void @bzero(i8* %bc, i64 1), !annotation !0, !dbg !DILocation(scope: !4) + ret void +} + +; Emit remarks for memcpy, memmove, memset, bzero with known constant sizes to an alloca that has a DILocalVariable attached. +define void @known_call_with_size_alloca_di(i8* %src) { +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. + %dst = alloca i8 + call void @llvm.dbg.declare(metadata i8* %dst, metadata !6, metadata !DIExpression()), !dbg !DILocation(scope: !4) + call void @llvm.memset.p0i8.i64(i8* %dst, i8 0, i64 1, i1 false), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 1, i1 false), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. + call void @llvm.memmove.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 1, i1 false), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. + call void @bzero(i8* %dst, i64 1), !annotation !0, !dbg !DILocation(scope: !4) + ret void +} + +; Emit remarks for memcpy, memmove, memset, bzero with known constant sizes to +; an alloca that has more than one DILocalVariable attached. +define void @known_call_with_size_alloca_di_multiple(i8* %src) { +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. + %dst = alloca i8 + call void @llvm.dbg.declare(metadata i8* %dst, metadata !6, metadata !DIExpression()), !dbg !DILocation(scope: !4) + call void @llvm.memset.p0i8.i64(i8* %dst, i8 0, i64 1, i1 false), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 1, i1 false), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. + call void @llvm.memmove.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 1, i1 false), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. + call void @bzero(i8* %dst, i64 1), !annotation !0, !dbg !DILocation(scope: !4) + ret void +} + +; Emit remarks for memcpy, memmove, memset, bzero with known constant sizes to +; a PHI node that can be two different allocas. +define void @known_call_with_size_alloca_phi(i8* %src) { +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +entry: + %dst = alloca i8 + %dst2 = alloca i8 + %cmp = icmp eq i32 undef, undef + br i1 %cmp, label %l0, label %l1 +l0: + br label %l2 +l1: + br label %l2 +l2: + %phidst = phi i8* [ %dst, %l0 ], [ %dst2, %l1 ] + call void @llvm.memset.p0i8.i64(i8* %phidst, i8 0, i64 1, i1 false), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %phidst, i8* %src, i64 1, i1 false), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. + call void @llvm.memmove.p0i8.p0i8.i64(i8* %phidst, i8* %src, i64 1, i1 false), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. + call void @bzero(i8* %phidst, i64 1), !annotation !0, !dbg !DILocation(scope: !4) + ret void +} + +; Emit remarks for memcpy, memmove, memset, bzero with known constant sizes to +; a PHI node that can be two different allocas, where one of it has multiple +; DILocalVariable. +define void @known_call_with_size_alloca_phi_di_multiple(i8* %src) { +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +entry: + %dst = alloca i8 + %dst2 = alloca i8 + call void @llvm.dbg.declare(metadata i8* %dst, metadata !6, metadata !DIExpression()), !dbg !DILocation(scope: !4) + call void @llvm.dbg.declare(metadata i8* %dst, metadata !7, metadata !DIExpression()), !dbg !DILocation(scope: !4) + %cmp = icmp eq i32 undef, undef + br i1 %cmp, label %l0, label %l1 +l0: + br label %l2 +l1: + br label %l2 +l2: + %phidst = phi i8* [ %dst, %l0 ], [ %dst2, %l1 ] + call void @llvm.memset.p0i8.i64(i8* %phidst, i8 0, i64 1, i1 false), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. + call void @llvm.memcpy.p0i8.p0i8.i64(i8* %phidst, i8* %src, i64 1, i1 false), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. + call void @llvm.memmove.p0i8.p0i8.i64(i8* %phidst, i8* %src, i64 1, i1 false), !annotation !0, !dbg !DILocation(scope: !4) +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. + call void @bzero(i8* %phidst, i64 1), !annotation !0, !dbg !DILocation(scope: !4) + ret void +} + +declare void @llvm.dbg.declare(metadata, metadata, metadata) nounwind readnone speculatable willreturn +declare void @llvm.memset.p0i8.i64(i8* nocapture writeonly, i8, i64, i1 immarg) argmemonly nounwind willreturn writeonly +declare void @llvm.memmove.p0i8.p0i8.i64(i8* nocapture, i8* nocapture readonly, i64, i1 immarg) argmemonly nounwind willreturn +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) argmemonly nounwind willreturn + +declare void @llvm.memset.element.unordered.atomic.p0i8.i64(i8* nocapture writeonly, i8, i64, i32 immarg) argmemonly nounwind willreturn writeonly +declare void @llvm.memcpy.element.unordered.atomic.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i32 immarg) argmemonly nounwind willreturn +declare void @llvm.memmove.element.unordered.atomic.p0i8.p0i8.i64(i8* nocapture writeonly, i8* nocapture readonly, i64, i32 immarg) argmemonly nounwind willreturn + +declare void @bzero(i8* nocapture, i64) nofree nounwind + +!llvm.module.flags = !{!1} +!0 = !{ !"auto-init" } +!1 = !{i32 2, !"Debug Info Version", i32 3} +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3) +!3 = !DIFile(filename: "file", directory: "") +!4 = distinct !DISubprogram(name: "function", scope: !3, file: !3, unit: !2) +!5 = !DIBasicType(name: "byte", size: 8) +!6 = !DILocalVariable(name: "destination", scope: !4, file: !3, type: !5) +!7 = !DILocalVariable(name: "destination2", scope: !4, file: !3, type: !5) diff --git a/llvm/test/Transforms/Util/trivial-auto-var-init-store.ll b/llvm/test/Transforms/Util/trivial-auto-var-init-store.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/Util/trivial-auto-var-init-store.ll @@ -0,0 +1,164 @@ +; RUN: opt -annotation-remarks -o /dev/null -S -pass-remarks-output=%t.opt.yaml %s -pass-remarks-missed=annotation-remarks 2>&1 | FileCheck %s +; RUN: cat %t.opt.yaml | FileCheck -check-prefix=YAML %s + +; Emit a remark that reports a store. +define void @store(i32* %dst) { +; CHECK: Initialization inserted by -ftrivial-auto-var-init. +; YAML-LABEL: --- !Missed +; YAML-NEXT: Pass: annotation-remarks +; YAML-NEXT: Name: AutoInitUnknownInstruction +; YAML-NEXT: DebugLoc: +; YAML-NEXT: Function: store +; YAML-NEXT: Args: +; YAML-NEXT: - String: Initialization inserted by -ftrivial-auto-var-init. +; YAML-NEXT: ... + store i32 0, i32* %dst, !annotation !0, !dbg !DILocation(scope: !4) + ret void +} + +; Emit a remark that reports a volatile store. +define void @volatile_store(i32* %dst) { +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; YAML-LABEL: --- !Missed +; YAML-NEXT: Pass: annotation-remarks +; YAML-NEXT: Name: AutoInitUnknownInstruction +; YAML-NEXT: DebugLoc: +; YAML-NEXT: Function: volatile_store +; YAML-NEXT: Args: +; YAML-NEXT: - String: Initialization inserted by -ftrivial-auto-var-init. +; YAML-NEXT: ... + store volatile i32 0, i32* %dst, !annotation !0, !dbg !DILocation(scope: !4) + ret void +} + +; Emit a remark that reports an atomic store. +define void @atomic_store(i32* %dst) { +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; YAML-LABEL: --- !Missed +; YAML-NEXT: Pass: annotation-remarks +; YAML-NEXT: Name: AutoInitUnknownInstruction +; YAML-NEXT: DebugLoc: +; YAML-NEXT: Function: atomic_store +; YAML-NEXT: Args: +; YAML-NEXT: - String: Initialization inserted by -ftrivial-auto-var-init. +; YAML-NEXT: ... + store atomic i32 0, i32* %dst unordered, align 4, !annotation !0, !dbg !DILocation(scope: !4) + ret void +} + +; Emit a remark that reports a store to an alloca. +define void @store_alloca() { +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; YAML-LABEL: --- !Missed +; YAML-NEXT: Pass: annotation-remarks +; YAML-NEXT: Name: AutoInitUnknownInstruction +; YAML-NEXT: DebugLoc: +; YAML-NEXT: Function: store_alloca +; YAML-NEXT: Args: +; YAML-NEXT: - String: Initialization inserted by -ftrivial-auto-var-init. +; YAML-NEXT: ... + %dst = alloca i32 + store i32 0, i32* %dst, !annotation !0, !dbg !DILocation(scope: !4) + ret void +} + +; 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. + %dst = alloca i32 + %gep = getelementptr i32, i32* %dst, i32 0 + store i32 0, i32* %gep, !annotation !0, !dbg !DILocation(scope: !4) + ret void +} + +; 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. + %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) + ret void +} + +; 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. + %dst = alloca [2 x i16] + %bc = bitcast [2 x i16]* %dst to i32* + store i32 0, i32* %bc, !annotation !0, !dbg !DILocation(scope: !4) + ret void +} + +; 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. + %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) + ret void +} + +; 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. + %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) + call void @llvm.dbg.declare(metadata i32* %dst, metadata !7, metadata !DIExpression()), !dbg !DILocation(scope: !4) + ret void +} + +; 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. +entry: + %dst = alloca i32 + %dst2 = alloca i32 + %cmp = icmp eq i32 undef, undef + br i1 %cmp, label %l0, label %l1 +l0: + br label %l2 +l1: + br label %l2 +l2: + %phidst = phi i32* [ %dst, %l0 ], [ %dst2, %l1 ] + store i32 0, i32* %phidst, !annotation !0, !dbg !DILocation(scope: !4) + ret void +} + +; 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. +entry: + %dst = alloca i32 + %dst2 = alloca i32 + call void @llvm.dbg.declare(metadata i32* %dst, metadata !6, metadata !DIExpression()), !dbg !DILocation(scope: !4) + call void @llvm.dbg.declare(metadata i32* %dst, metadata !7, metadata !DIExpression()), !dbg !DILocation(scope: !4) + %cmp = icmp eq i32 undef, undef + br i1 %cmp, label %l0, label %l1 +l0: + br label %l2 +l1: + br label %l2 +l2: + %phidst = phi i32* [ %dst, %l0 ], [ %dst2, %l1 ] + store i32 0, i32* %phidst, !annotation !0, !dbg !DILocation(scope: !4) + ret void +} + +; Function Attrs: nounwind readnone speculatable willreturn +declare void @llvm.dbg.declare(metadata, metadata, metadata) nounwind readnone speculatable willreturn + +!llvm.module.flags = !{!1} +!0 = !{ !"auto-init" } +!1 = !{i32 2, !"Debug Info Version", i32 3} +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3) +!3 = !DIFile(filename: "file", directory: "") +!4 = distinct !DISubprogram(name: "function", scope: !3, file: !3, unit: !2) +!5 = !DIBasicType(name: "int", size: 32) +!6 = !DILocalVariable(name: "destination", scope: !4, file: !3, type: !5) +!7 = !DILocalVariable(name: "destination2", scope: !4, file: !3, type: !5) diff --git a/llvm/test/Transforms/Util/trivial-auto-var-init-unknown.ll b/llvm/test/Transforms/Util/trivial-auto-var-init-unknown.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/Util/trivial-auto-var-init-unknown.ll @@ -0,0 +1,62 @@ +; RUN: opt -annotation-remarks -o /dev/null -S -pass-remarks-output=%t.opt.yaml %s -pass-remarks-missed=annotation-remarks 2>&1 | FileCheck %s +; RUN: cat %t.opt.yaml | FileCheck -check-prefix=YAML %s + +; No remarks for this function, no instructions with metadata. +define void @none() { +; YAML-NOT: Function: none + ret void +} + +; Emit a remark that reports an instruction we can't analyze. +define void @unknown() { +; CHECK: Initialization inserted by -ftrivial-auto-var-init. +; YAML-LABEL: --- !Missed +; YAML-NEXT: Pass: annotation-remarks +; YAML-NEXT: Name: AutoInitUnknownInstruction +; YAML-NEXT: DebugLoc: +; YAML-NEXT: Function: unknown +; YAML-NEXT: Args: +; YAML-NEXT: - String: Initialization inserted by -ftrivial-auto-var-init. +; YAML-NEXT: ... + ret void, !annotation !0, !dbg !DILocation(scope: !4) +} + +; Emit a remark that reports an intrinsic call to an unknown intrinsic. +define void @unknown_intrinsic(i32* %dst) { +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; YAML-LABEL: --- !Missed +; YAML-NEXT: Pass: annotation-remarks +; YAML-NEXT: Name: AutoInitUnknownInstruction +; YAML-NEXT: DebugLoc: +; YAML-NEXT: Function: unknown_intrinsic + call i8* @llvm.returnaddress(i32 0), !annotation !0, !dbg !DILocation(scope: !4) + ret void +} + +; Emit a remark that reports a function call to a known libcall. +define void @known_call(i8* %dst) { +; CHECK-NEXT: Initialization inserted by -ftrivial-auto-var-init. +; YAML-LABEL: --- !Missed +; YAML-NEXT: Pass: annotation-remarks +; YAML-NEXT: Name: AutoInitUnknownInstruction +; YAML-NEXT: DebugLoc: +; YAML-NEXT: Function: known_call +; YAML-NEXT: Args: +; YAML-NEXT: - String: Initialization inserted by -ftrivial-auto-var-init. +; YAML-NEXT: ... + call i8* @memset(i8* %dst, i32 0, i64 32), !annotation !0, !dbg !DILocation(scope: !4) + ret void +} + +declare i8* @llvm.returnaddress(i32) nounwind readnone +declare i8* @memset(i8*, i32, i64) + +!llvm.module.flags = !{!1} +!0 = !{ !"auto-init" } +!1 = !{i32 2, !"Debug Info Version", i32 3} +!2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3) +!3 = !DIFile(filename: "file", directory: "") +!4 = distinct !DISubprogram(name: "function", scope: !3, file: !3, unit: !2) +!5 = !DIBasicType(name: "byte", size: 8) +!6 = !DILocalVariable(name: "destination", scope: !4, file: !3, type: !5) +!7 = !DILocalVariable(name: "destination2", scope: !4, file: !3, type: !5)