Peng Yu via llvm-dev
2019-Jan-19 17:09 UTC
[llvm-dev] Is read and write variables always translated to load and store IR instructions?
Hi, It seems that read and write access to variables are translated to load and store IR instructions. Are they only translated to load and store IR instructions in .ll code? Could read and write accesses be translated to other IR instructions (for .0.0.preopt.bc only)? Thanks. $ clang -std=gnu99 -g3 -flto -Wall -pedantic -c -o main.o main.c $ clang main.o -flto -fuse-ld=gold '-Wl,-plugin-opt=save-temps' -o main.exe $ cat main.c /* vim: set noexpandtab tabstop=2: */ #include <stdio.h> int i; struct { int x; int y; } a[10]; void print() { puts("Hello World!"); } int main(int argc, char *argv[]) { ++i; if(i) { ++a[0].x; print(); printf("%d\n", i); printf("%d\n", a[0].x); } return 0; } $ cat main.exe.0.0.preopt.ll source_filename = "ld-temp.o" target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" target triple = "x86_64-pc-linux-gnu" %struct.anon = type { i32, i32 } @.str = private unnamed_addr constant [13 x i8] c"Hello World!\00", align 1 @i = common dso_local global i32 0, align 4, !dbg !0 @a = common dso_local global [10 x %struct.anon] zeroinitializer, align 16, !dbg !6 @.str.1 = private unnamed_addr constant [4 x i8] c"%d\0A\00", align 1 ; Function Attrs: noinline nounwind optnone uwtable define dso_local void @print() #0 !dbg !20 { %1 = call i32 @puts(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str, i32 0, i32 0)), !dbg !23 ret void, !dbg !24 } declare i32 @puts(i8*) #1 ; Function Attrs: noinline nounwind optnone uwtable define dso_local i32 @main(i32, i8**) #0 !dbg !25 { %3 = alloca i32, align 4 %4 = alloca i32, align 4 %5 = alloca i8**, align 8 store i32 0, i32* %3, align 4 store i32 %0, i32* %4, align 4 call void @llvm.dbg.declare(metadata i32* %4, metadata !31, metadata !DIExpression()), !dbg !32 store i8** %1, i8*** %5, align 8 call void @llvm.dbg.declare(metadata i8*** %5, metadata !33, metadata !DIExpression()), !dbg !34 %6 = load i32, i32* @i, align 4, !dbg !35 %7 = add nsw i32 %6, 1, !dbg !35 store i32 %7, i32* @i, align 4, !dbg !35 %8 = load i32, i32* @i, align 4, !dbg !36 %9 = icmp ne i32 %8, 0, !dbg !36 br i1 %9, label %10, label %17, !dbg !38 ; <label>:10: ; preds = %2 %11 = load i32, i32* getelementptr inbounds ([10 x %struct.anon], [10 x %struct.anon]* @a, i64 0, i64 0, i32 0), align 16, !dbg !39 %12 = add nsw i32 %11, 1, !dbg !39 store i32 %12, i32* getelementptr inbounds ([10 x %struct.anon], [10 x %struct.anon]* @a, i64 0, i64 0, i32 0), align 16, !dbg !39 call void @print(), !dbg !41 %13 = load i32, i32* @i, align 4, !dbg !42 %14 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.1, i32 0, i32 0), i32 %13), !dbg !43 %15 = load i32, i32* getelementptr inbounds ([10 x %struct.anon], [10 x %struct.anon]* @a, i64 0, i64 0, i32 0), align 16, !dbg !44 %16 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([4 x i8], [4 x i8]* @.str.1, i32 0, i32 0), i32 %15), !dbg !45 br label %17, !dbg !46 ; <label>:17: ; preds = %10, %2 ret i32 0, !dbg !47 } ; Function Attrs: nounwind readnone speculatable declare void @llvm.dbg.declare(metadata, metadata, metadata) #2 declare i32 @printf(i8*, ...) #1 attributes #0 = { noinline nounwind optnone uwtable "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-jump-tables"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #1 = { "correctly-rounded-divide-sqrt-fp-math"="false" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "no-signed-zeros-fp-math"="false" "no-trapping-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+fxsr,+mmx,+sse,+sse2,+x87" "unsafe-fp-math"="false" "use-soft-float"="false" } attributes #2 = { nounwind readnone speculatable } !llvm.dbg.cu = !{!2} !llvm.ident = !{!16} !llvm.module.flags = !{!17, !18, !19} !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) !1 = distinct !DIGlobalVariable(name: "i", scope: !2, file: !3, line: 4, type: !12, isLocal: false, isDefinition: true) !2 = distinct !DICompileUnit(language: DW_LANG_C99, file: !3, producer: "clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !4, globals: !5) !4 = !{} !5 = !{!0, !6} !6 = !DIGlobalVariableExpression(var: !7, expr: !DIExpression()) !7 = distinct !DIGlobalVariable(name: "a", scope: !2, file: !3, line: 9, type: !8, isLocal: false, isDefinition: true) !8 = !DICompositeType(tag: DW_TAG_array_type, baseType: !9, size: 640, elements: !14) !9 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !3, line: 6, size: 64, elements: !10) !10 = !{!11, !13} !11 = !DIDerivedType(tag: DW_TAG_member, name: "x", scope: !9, file: !3, line: 7, baseType: !12, size: 32) !12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) !13 = !DIDerivedType(tag: DW_TAG_member, name: "y", scope: !9, file: !3, line: 8, baseType: !12, size: 32, offset: 32) !14 = !{!15} !15 = !DISubrange(count: 10) !16 = !{!"clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)"} !17 = !{i32 2, !"Dwarf Version", i32 4} !18 = !{i32 2, !"Debug Info Version", i32 3} !19 = !{i32 1, !"wchar_size", i32 4} !20 = distinct !DISubprogram(name: "print", scope: !3, file: !3, line: 11, type: !21, isLocal: false, isDefinition: true, scopeLine: 11, isOptimized: false, unit: !2, retainedNodes: !4) !21 = !DISubroutineType(types: !22) !22 = !{null} !23 = !DILocation(line: 12, column: 3, scope: !20) !24 = !DILocation(line: 13, column: 1, scope: !20) !25 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 15, type: !26, isLocal: false, isDefinition: true, scopeLine: 15, flags: DIFlagPrototyped, isOptimized: false, unit: !2, retainedNodes: !4) !26 = !DISubroutineType(types: !27) !27 = !{!12, !12, !28} !28 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !29, size: 64) !29 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !30, size: 64) !30 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) !31 = !DILocalVariable(name: "argc", arg: 1, scope: !25, file: !3, line: 15, type: !12) !32 = !DILocation(line: 15, column: 14, scope: !25) !33 = !DILocalVariable(name: "argv", arg: 2, scope: !25, file: !3, line: 15, type: !28) !34 = !DILocation(line: 15, column: 26, scope: !25) !35 = !DILocation(line: 16, column: 3, scope: !25) !36 = !DILocation(line: 17, column: 6, scope: !37) !37 = distinct !DILexicalBlock(scope: !25, file: !3, line: 17, column: 6) !38 = !DILocation(line: 17, column: 6, scope: !25) !39 = !DILocation(line: 18, column: 5, scope: !40) !40 = distinct !DILexicalBlock(scope: !37, file: !3, line: 17, column: 9) !41 = !DILocation(line: 19, column: 5, scope: !40) !42 = !DILocation(line: 20, column: 20, scope: !40) !43 = !DILocation(line: 20, column: 5, scope: !40) !44 = !DILocation(line: 21, column: 25, scope: !40) !45 = !DILocation(line: 21, column: 5, scope: !40) !46 = !DILocation(line: 22, column: 3, scope: !40) !47 = !DILocation(line: 23, column: 3, scope: !25) -- Regards, Peng
Tim Northover via llvm-dev
2019-Jan-19 21:36 UTC
[llvm-dev] Is read and write variables always translated to load and store IR instructions?
Hi, On Sat, 19 Jan 2019 at 17:09, Peng Yu via llvm-dev <llvm-dev at lists.llvm.org> wrote:> It seems that read and write access to variables are translated to > load and store IR instructions. > > Are they only translated to load and store IR instructions in .ll > code? Could read and write accesses be translated to other IR > instructions (for .0.0.preopt.bc only)? Thanks.I think this is more a question for cfe-dev since llvm-dev only really gets involved once the IR has been generated. That said, a proper answer probably involves some quite involved discussions about just what counts as an access. At the very least Clang will also generate calls to @llvm.memcpy.* for struct copies. For example: typedef struct { int a; } Foo; void func(Foo f) { Foo g = f; } will cause Clang to initialize 'g' with a memcpy. memset can be generated similarly if you set a struct to 0. Cheers. Tim.