; RUN: llc %s -pass-remarks-analysis=gisel-irtranslator-memsize -pass-remarks-output=%t.opt.yaml -pass-remarks-filter=gisel-irtranslator-memsize -global-isel -o /dev/null 2>&1 | FileCheck %s --check-prefix=GISEL --implicit-check-not=GISEL ; RUN: cat %t.opt.yaml | FileCheck -check-prefix=YAML %s source_filename = "memsize.c" target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" target triple = "arm64-apple-ios7.0.0" declare i8* @__memmove_chk(i8*, i8*, i64, i64) #1 declare i8* @__memcpy_chk(i8*, i8*, i64, i64) #1 declare i8* @__memset_chk(i8*, i32, i64, i64) #1 declare i64 @llvm.objectsize.i64.p0i8(i8*, i1 immarg, i1 immarg, i1 immarg) #2 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 @bzero(i8* nocapture, i64) nofree nounwind declare void @bcopy(i8* nocapture, i8* nocapture, i64) nofree nounwind declare i8* @memset(i8*, i32, i64) define void @memcpy_dynamic(i8* %d, i8* %s, i64 %l) #0 !dbg !14 { entry: %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %d, i1 false, i1 true, i1 false), !dbg !16 ; GISEL: remark: memsize.c:4:3: Call to memcpy.{{$}} %call = call i8* @__memcpy_chk(i8* %d, i8* %s, i64 %l, i64 %0) #4, !dbg !17 ret void, !dbg !18 } define void @memcpy_single(i8* %d, i8* %s, i64 %l) #0 !dbg !23 { entry: %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %d, i1 false, i1 true, i1 false), !dbg !24 ; GISEL: remark: memsize.c:10:3: Call to memcpy. Memory operation size: 1 bytes. %call = call i8* @__memcpy_chk(i8* %d, i8* %s, i64 1, i64 %0) #4, !dbg !25 ret void, !dbg !26 } define void @memcpy_intrinsic(i8* %d, i8* %s, i64 %l) #0 { entry: %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %d, i1 false, i1 true, i1 false) ; GISEL: remark: <unknown>:0:0: Call to memcpy. Memory operation size: 1 bytes. call void @llvm.memcpy.p0i8.p0i8.i64(i8* %d, i8* %s, i64 1, i1 false) ret void } define void @memcpy_static(i8* %d, i8* %s, i64 %l) #0 !dbg !27 { entry: %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %d, i1 false, i1 true, i1 false), !dbg !28 ; GISEL: remark: memsize.c:13:3: Call to memcpy. Memory operation size: 100 bytes. %call = call i8* @__memcpy_chk(i8* %d, i8* %s, i64 100, i64 %0) #4, !dbg !29 ret void, !dbg !30 } define void @memcpy_huge(i8* %d, i8* %s, i64 %l) #0 !dbg !31 { entry: %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %d, i1 false, i1 true, i1 false), !dbg !32 ; GISEL: remark: memsize.c:16:3: Call to memcpy. Memory operation size: 100000 bytes. %call = call i8* @__memcpy_chk(i8* %d, i8* %s, i64 100000, i64 %0) #4, !dbg !33 ret void, !dbg !34 } define void @memmove_dynamic(i8* %d, i8* %s, i64 %l) #0 { entry: %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %d, i1 false, i1 true, i1 false) ; GISEL: remark: <unknown>:0:0: Call to memmove.{{$}} %call = call i8* @__memmove_chk(i8* %d, i8* %s, i64 %l, i64 %0) #4 ret void } define void @memmove_single(i8* %d, i8* %s, i64 %l) #0 { entry: %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %d, i1 false, i1 true, i1 false) ; GISEL: remark: <unknown>:0:0: Call to memmove. Memory operation size: 1 bytes. %call = call i8* @__memmove_chk(i8* %d, i8* %s, i64 1, i64 %0) #4 ret void } define void @memmove_static(i8* %d, i8* %s, i64 %l) #0 { entry: %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %d, i1 false, i1 true, i1 false) ; GISEL: remark: <unknown>:0:0: Call to memmove. Memory operation size: 100 bytes. %call = call i8* @__memmove_chk(i8* %d, i8* %s, i64 100, i64 %0) #4 ret void } define void @memmove_huge(i8* %d, i8* %s, i64 %l) #0 { entry: %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %d, i1 false, i1 true, i1 false) ; GISEL: remark: <unknown>:0:0: Call to memmove. Memory operation size: 100000 bytes. %call = call i8* @__memmove_chk(i8* %d, i8* %s, i64 100000, i64 %0) #4 ret void } define void @memset_dynamic(i8* %d, i64 %l) #0 !dbg !38 { entry: %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %d, i1 false, i1 true, i1 false), !dbg !39 ; GISEL: remark: memsize.c:22:3: Call to memset.{{$}} %call = call i8* @__memset_chk(i8* %d, i32 0, i64 %l, i64 %0) #4, !dbg !40 ret void, !dbg !41 } define void @memset_single(i8* %d, i64 %l) #0 !dbg !46 { entry: %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %d, i1 false, i1 true, i1 false), !dbg !47 ; GISEL: remark: memsize.c:28:3: Call to memset. Memory operation size: 1 bytes. %call = call i8* @__memset_chk(i8* %d, i32 0, i64 1, i64 %0) #4, !dbg !48 ret void, !dbg !49 } define void @memset_static(i8* %d, i64 %l) #0 !dbg !50 { entry: %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %d, i1 false, i1 true, i1 false), !dbg !51 ; GISEL: remark: memsize.c:31:3: Call to memset. Memory operation size: 100 bytes. %call = call i8* @__memset_chk(i8* %d, i32 0, i64 100, i64 %0) #4, !dbg !52 ret void, !dbg !53 } define void @memset_huge(i8* %d, i64 %l) #0 !dbg !54 { entry: %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %d, i1 false, i1 true, i1 false), !dbg !55 ; GISEL: remark: memsize.c:34:3: Call to memset. Memory operation size: 100000 bytes. %call = call i8* @__memset_chk(i8* %d, i32 0, i64 100000, i64 %0) #4, !dbg !56 ret void, !dbg !57 } define void @memset_empty(i8* %d, i64 %l) #0 !dbg !42 { entry: %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %d, i1 false, i1 true, i1 false), !dbg !43 ; GISEL: remark: memsize.c:25:3: Call to memset. Memory operation size: 0 bytes. %call = call i8* @__memset_chk(i8* %d, i32 0, i64 0, i64 %0) #4, !dbg !44 ret void, !dbg !45 } ; YAML-LABEL: Function: memcpy_empty define void @memcpy_empty(i8* %d, i8* %s, i64 %l) #0 !dbg !19 { entry: %0 = call i64 @llvm.objectsize.i64.p0i8(i8* %d, i1 false, i1 true, i1 false), !dbg !20 ; GISEL: remark: memsize.c:7:3: Call to memcpy. Memory operation size: 0 bytes. %call = call i8* @__memcpy_chk(i8* %d, i8* %s, i64 0, i64 %0) #4, !dbg !21 ret void, !dbg !22 } ; Emit remarks for memcpy, memmove, memset, bzero, bcopy with known constant ; sizes to an object of known size. define void @known_call_with_dereferenceable_bytes(i8* dereferenceable(42) %dst, i8* dereferenceable(314) %src) { ; GISEL: Call to memset. Memory operation size: 1 bytes. ; GISEL-NOT: Read Variables: ; GISEL-NEXT: Written Variables: <unknown> (42 bytes). ; YAML: --- !Analysis ; YAML: gisel-irtranslator-memsize ; YAML: Name: MemoryOpIntrinsicCall ; YAML-LABEL: Function: known_call_with_dereferenceable_bytes ; YAML-NEXT: Args: ; YAML-NEXT: - String: 'Call to ' ; YAML-NEXT: - Callee: memset ; YAML-NEXT: - String: . ; YAML-NEXT: - String: ' Memory operation size: ' ; YAML-NEXT: - StoreSize: '1' ; YAML-NEXT: - String: ' bytes.' ; YAML-NEXT: - String: "\n Written Variables: " ; YAML-NEXT: - WVarName: '<unknown>' ; YAML-NEXT: - String: ' (' ; YAML-NEXT: - WVarSize: '42' ; YAML-NEXT: - String: ' bytes)' ; YAML-NEXT: - String: . ; YAML-NEXT: - String: ' Inlined: ' ; YAML-NEXT: - StoreInlined: 'false' ; YAML-NEXT: - String: . ; YAML-NEXT: - String: ' Volatile: ' ; YAML-NEXT: - StoreVolatile: 'false' ; YAML-NEXT: - String: . ; YAML-NEXT: - String: ' Atomic: ' ; YAML-NEXT: - StoreAtomic: 'false' ; YAML-NEXT: - String: . ; YAML-NEXT: ... call void @llvm.memset.p0i8.i64(i8* %dst, i8 0, i64 1, i1 false) ; GISEL: Call to memcpy. Memory operation size: 1 bytes. ; GISEL-NEXT: Read Variables: <unknown> (314 bytes). ; GISEL-NEXT: Written Variables: <unknown> (42 bytes). ; YAML: --- !Analysis ; YAML: gisel-irtranslator-memsize ; YAML: Name: MemoryOpIntrinsicCall ; YAML-LABEL: Function: known_call_with_dereferenceable_bytes ; YAML-NEXT: Args: ; YAML-NEXT: - String: 'Call to ' ; YAML-NEXT: - Callee: memcpy ; YAML-NEXT: - String: . ; YAML-NEXT: - String: ' Memory operation size: ' ; YAML-NEXT: - StoreSize: '1' ; YAML-NEXT: - String: ' bytes.' ; YAML-NEXT: - String: "\n Read Variables: " ; YAML-NEXT: - RVarName: '<unknown>' ; YAML-NEXT: - String: ' (' ; YAML-NEXT: - RVarSize: '314' ; YAML-NEXT: - String: ' bytes)' ; YAML-NEXT: - String: . ; YAML-NEXT: - String: "\n Written Variables: " ; YAML-NEXT: - WVarName: '<unknown>' ; YAML-NEXT: - String: ' (' ; YAML-NEXT: - WVarSize: '42' ; YAML-NEXT: - String: ' bytes)' ; YAML-NEXT: - String: . ; YAML-NEXT: - String: ' Inlined: ' ; YAML-NEXT: - StoreInlined: 'false' ; YAML-NEXT: - String: . ; YAML-NEXT: - String: ' Volatile: ' ; YAML-NEXT: - StoreVolatile: 'false' ; YAML-NEXT: - String: . ; YAML-NEXT: - String: ' Atomic: ' ; YAML-NEXT: - StoreAtomic: 'false' ; YAML-NEXT: - String: . ; YAML-NEXT: ... call void @llvm.memcpy.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 1, i1 false) ; GISEL: Call to memmove. Memory operation size: 1 bytes. ; GISEL-NEXT: Read Variables: <unknown> (314 bytes). ; GISEL-NEXT: Written Variables: <unknown> (42 bytes). ; YAML: --- !Analysis ; YAML: gisel-irtranslator-memsize ; YAML: Name: MemoryOpIntrinsicCall ; YAML-LABEL: Function: known_call_with_dereferenceable_bytes ; YAML-NEXT: Args: ; YAML-NEXT: - String: 'Call to ' ; YAML-NEXT: - Callee: memmove ; YAML-NEXT: - String: . ; YAML-NEXT: - String: ' Memory operation size: ' ; YAML-NEXT: - StoreSize: '1' ; YAML-NEXT: - String: ' bytes.' ; YAML-NEXT: - String: "\n Read Variables: " ; YAML-NEXT: - RVarName: '<unknown>' ; YAML-NEXT: - String: ' (' ; YAML-NEXT: - RVarSize: '314' ; YAML-NEXT: - String: ' bytes)' ; YAML-NEXT: - String: . ; YAML-NEXT: - String: "\n Written Variables: " ; YAML-NEXT: - WVarName: '<unknown>' ; YAML-NEXT: - String: ' (' ; YAML-NEXT: - WVarSize: '42' ; YAML-NEXT: - String: ' bytes)' ; YAML-NEXT: - String: . ; YAML-NEXT: - String: ' Inlined: ' ; YAML-NEXT: - StoreInlined: 'false' ; YAML-NEXT: - String: . ; YAML-NEXT: - String: ' Volatile: ' ; YAML-NEXT: - StoreVolatile: 'false' ; YAML-NEXT: - String: . ; YAML-NEXT: - String: ' Atomic: ' ; YAML-NEXT: - StoreAtomic: 'false' ; YAML-NEXT: - String: . ; YAML-NEXT: ... call void @llvm.memmove.p0i8.p0i8.i64(i8* %dst, i8* %src, i64 1, i1 false) ; GISEL: Call to bzero. Memory operation size: 1 bytes. ; GISEL-NOT: Read Variables: ; GISEL-NEXT: Written Variables: <unknown> (42 bytes). ; YAML: --- !Analysis ; YAML: gisel-irtranslator-memsize ; YAML: Name: MemoryOpCall ; YAML-LABEL: Function: known_call_with_dereferenceable_bytes ; YAML-NEXT: Args: ; YAML-NEXT: - String: 'Call to ' ; YAML-NEXT: - Callee: bzero ; YAML-NEXT: - String: . ; YAML-NEXT: - String: ' Memory operation size: ' ; YAML-NEXT: - StoreSize: '1' ; YAML-NEXT: - String: ' bytes.' ; YAML-NEXT: - String: "\n Written Variables: " ; YAML-NEXT: - WVarName: '<unknown>' ; YAML-NEXT: - String: ' (' ; YAML-NEXT: - WVarSize: '42' ; YAML-NEXT: - String: ' bytes)' ; YAML-NEXT: - String: . ; YAML-NEXT: ... call void @bzero(i8* %dst, i64 1) ; GISEL: Call to bcopy. Memory operation size: 1 bytes. ; GISEL-NEXT: Read Variables: <unknown> (314 bytes). ; GISEL-NEXT: Written Variables: <unknown> (42 bytes). ; YAML: --- !Analysis ; YAML: gisel-irtranslator-memsize ; YAML: Name: MemoryOpCall ; YAML-LABEL: Function: known_call_with_dereferenceable_bytes ; YAML-NEXT: Args: ; YAML-NEXT: - String: 'Call to ' ; YAML-NEXT: - Callee: bcopy ; YAML-NEXT: - String: . ; YAML-NEXT: - String: ' Memory operation size: ' ; YAML-NEXT: - StoreSize: '1' ; YAML-NEXT: - String: ' bytes.' ; YAML-NEXT: - String: "\n Read Variables: " ; YAML-NEXT: - RVarName: '<unknown>' ; YAML-NEXT: - String: ' (' ; YAML-NEXT: - RVarSize: '314' ; YAML-NEXT: - String: ' bytes)' ; YAML-NEXT: - String: . ; YAML-NEXT: - String: "\n Written Variables: " ; YAML-NEXT: - WVarName: '<unknown>' ; YAML-NEXT: - String: ' (' ; YAML-NEXT: - WVarSize: '42' ; YAML-NEXT: - String: ' bytes)' ; YAML-NEXT: - String: . ; YAML-NEXT: ... call void @bcopy(i8* %dst, i8* %src, i64 1) ret void } @dropbear = external unnamed_addr constant [3 x i8], align 1 @koala = external unnamed_addr constant [7 x i8], align 1 define void @slicePun() { bb: ; GISEL: remark: <unknown>:0:0: Call to memcpy. Memory operation size: 24 bytes.{{$}} ; GISEL-NEXT: Read Variables: koala (56 bytes). ; GISEL-NEXT: Written Variables: dropbear (24 bytes). tail call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 1 getelementptr inbounds ([3 x i8], [3 x i8]* @dropbear, i64 0, i64 0), i8* getelementptr inbounds ([7 x i8], [7 x i8]* @koala, i64 0, i64 0), i64 24, i1 false) ret void } attributes #0 = { noinline nounwind ssp uwtable "frame-pointer"="non-leaf" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-a7" "target-features"="+aes,+crypto,+fp-armv8,+neon,+sha2,+zcm,+zcz" } attributes #1 = { nounwind "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-a7" "target-features"="+aes,+crypto,+fp-armv8,+neon,+sha2,+zcm,+zcz" } attributes #2 = { nofree nosync nounwind readnone speculatable willreturn } attributes #3 = { argmemonly nofree nosync nounwind willreturn } attributes #4 = { nounwind } !llvm.module.flags = !{!0, !1, !2, !3, !4, !5, !6, !7, !8, !9} !llvm.dbg.cu = !{!10} !llvm.ident = !{!13} !0 = !{i32 2, !"SDK Version", [2 x i32] [i32 12, i32 0]} !1 = !{i32 2, !"Debug Info Version", i32 3} !2 = !{i32 1, !"wchar_size", i32 4} !3 = !{i32 8, !"branch-target-enforcement", i32 0} !4 = !{i32 8, !"sign-return-address", i32 0} !5 = !{i32 8, !"sign-return-address-all", i32 0} !6 = !{i32 8, !"sign-return-address-with-bkey", i32 0} !7 = !{i32 7, !"PIC Level", i32 2} !8 = !{i32 7, !"uwtable", i32 1} !9 = !{i32 7, !"frame-pointer", i32 1} !10 = distinct !DICompileUnit(language: DW_LANG_C99, file: !11, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: NoDebug, enums: !12, splitDebugInlining: false, nameTableKind: None, sysroot: "/") !11 = !DIFile(filename: "memsize.c", directory: "") !12 = !{} !13 = !{!"clang"} !14 = distinct !DISubprogram(name: "memcpy_dynamic", scope: !11, file: !11, line: 3, type: !15, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !10, retainedNodes: !12) !15 = !DISubroutineType(types: !12) !16 = !DILocation(line: 4, column: 36, scope: !14) !17 = !DILocation(line: 4, column: 3, scope: !14) !18 = !DILocation(line: 5, column: 1, scope: !14) !19 = distinct !DISubprogram(name: "memcpy_empty", scope: !11, file: !11, line: 6, type: !15, scopeLine: 6, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !10, retainedNodes: !12) !20 = !DILocation(line: 7, column: 36, scope: !19) !21 = !DILocation(line: 7, column: 3, scope: !19) !22 = !DILocation(line: 8, column: 1, scope: !19) !23 = distinct !DISubprogram(name: "memcpy_single", scope: !11, file: !11, line: 9, type: !15, scopeLine: 9, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !10, retainedNodes: !12) !24 = !DILocation(line: 10, column: 36, scope: !23) !25 = !DILocation(line: 10, column: 3, scope: !23) !26 = !DILocation(line: 11, column: 1, scope: !23) !27 = distinct !DISubprogram(name: "memcpy_static", scope: !11, file: !11, line: 12, type: !15, scopeLine: 12, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !10, retainedNodes: !12) !28 = !DILocation(line: 13, column: 38, scope: !27) !29 = !DILocation(line: 13, column: 3, scope: !27) !30 = !DILocation(line: 14, column: 1, scope: !27) !31 = distinct !DISubprogram(name: "memcpy_huge", scope: !11, file: !11, line: 15, type: !15, scopeLine: 15, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !10, retainedNodes: !12) !32 = !DILocation(line: 16, column: 41, scope: !31) !33 = !DILocation(line: 16, column: 3, scope: !31) !34 = !DILocation(line: 17, column: 1, scope: !31) !35 = distinct !DISubprogram(name: "memcpy_inline", scope: !11, file: !11, line: 18, type: !15, scopeLine: 18, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !10, retainedNodes: !12) !36 = !DILocation(line: 19, column: 3, scope: !35) !37 = !DILocation(line: 20, column: 1, scope: !35) !38 = distinct !DISubprogram(name: "memset_dynamic", scope: !11, file: !11, line: 21, type: !15, scopeLine: 21, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !10, retainedNodes: !12) !39 = !DILocation(line: 22, column: 36, scope: !38) !40 = !DILocation(line: 22, column: 3, scope: !38) !41 = !DILocation(line: 23, column: 1, scope: !38) !42 = distinct !DISubprogram(name: "memset_empty", scope: !11, file: !11, line: 24, type: !15, scopeLine: 24, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !10, retainedNodes: !12) !43 = !DILocation(line: 25, column: 36, scope: !42) !44 = !DILocation(line: 25, column: 3, scope: !42) !45 = !DILocation(line: 26, column: 1, scope: !42) !46 = distinct !DISubprogram(name: "memset_single", scope: !11, file: !11, line: 27, type: !15, scopeLine: 27, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !10, retainedNodes: !12) !47 = !DILocation(line: 28, column: 36, scope: !46) !48 = !DILocation(line: 28, column: 3, scope: !46) !49 = !DILocation(line: 29, column: 1, scope: !46) !50 = distinct !DISubprogram(name: "memset_static", scope: !11, file: !11, line: 30, type: !15, scopeLine: 30, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !10, retainedNodes: !12) !51 = !DILocation(line: 31, column: 38, scope: !50) !52 = !DILocation(line: 31, column: 3, scope: !50) !53 = !DILocation(line: 32, column: 1, scope: !50) !54 = distinct !DISubprogram(name: "memset_huge", scope: !11, file: !11, line: 33, type: !15, scopeLine: 33, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !10, retainedNodes: !12) !55 = !DILocation(line: 34, column: 41, scope: !54) !56 = !DILocation(line: 34, column: 3, scope: !54) !57 = !DILocation(line: 35, column: 1, scope: !54) !58 = distinct !DISubprogram(name: "auto_init", scope: !11, file: !11, line: 37, type: !15, scopeLine: 37, spFlags: DISPFlagDefinition, unit: !10, retainedNodes: !12)