-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Part 1 of well-defined copy-elision (second attempt) #1682
Conversation
```zig export fn entry() void { var x: i32 = undefined; } ``` ```llvm define void @entry() #2 !dbg !41 { Entry: %x = alloca i32, align 4 %0 = bitcast i32* %x to i8*, !dbg !48 call void @llvm.memset.p0i8.i64(i8* align 4 %0, i8 -86, i64 4, i1 false), !dbg !48 call void @llvm.dbg.declare(metadata i32* %x, metadata !45, metadata !DIExpression()), !dbg !48 ret void, !dbg !49 } ```
0ceab56
to
1dfca20
Compare
```zig export fn entry() void { var x = i32(1234); } ``` ```llvm define void @entry() #2 !dbg !41 { Entry: %x = alloca i32, align 4 store i32 1234, i32* %x, align 4, !dbg !48 %0 = bitcast i32* %x to i8*, !dbg !48 call void @llvm.memset.p0i8.i64(i8* align 4 %0, i8 -86, i64 4, i1 false), !dbg !48 call void @llvm.dbg.declare(metadata i32* %x, metadata !45, metadata !DIExpression()), !dbg !48 ret void, !dbg !49 } ```
```zig export fn entry() void { var x = Foo.{ .x = 1, .y = 2, }; } ``` ```llvm define void @entry() #2 !dbg !41 { Entry: %x = alloca %Foo, align 4 %0 = bitcast %Foo* %x to i8*, !dbg !52 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %0, i8* align 4 bitcast (%Foo* @0 to i8*), i64 8, i1 false), !dbg !52 call void @llvm.dbg.declare(metadata %Foo* %x, metadata !45, metadata !DIExpression()), !dbg !52 ret void, !dbg !53 } ```
```zig export fn entry() void { var y = foo(); } fn foo() Foo { return Foo.{ .x = 1, .y = 2, }; } ``` ```llvm define void @entry() #2 !dbg !41 { Entry: %y = alloca %Foo, align 4 call fastcc void @foo(%Foo* sret %y), !dbg !52 call void @llvm.dbg.declare(metadata %Foo* %y, metadata !45, metadata !DIExpression()), !dbg !53 ret void, !dbg !54 } define internal fastcc void @foo(%Foo* nonnull sret) unnamed_addr #2 !dbg !55 { Entry: %1 = bitcast %Foo* %0 to i8*, !dbg !60 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %1, i8* align 4 bitcast (%Foo* @0 to i8*), i64 8, i1 false), !dbg !60 ret void, !dbg !60 } ```
```zig export fn entry() void { var x = bar(); var y = x; } ``` ```llvm define void @entry() #2 !dbg !41 { Entry: %x = alloca %Foo, align 4 %y = alloca %Foo, align 4 call fastcc void @bar(%Foo* sret %x), !dbg !54 call void @llvm.dbg.declare(metadata %Foo* %x, metadata !45, metadata !DIExpression()), !dbg !55 %0 = bitcast %Foo* %x to i8*, !dbg !56 %1 = bitcast %Foo* %y to i8*, !dbg !56 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %1, i8* align 4 %0, i64 8, i1 false), !dbg !56 call void @llvm.dbg.declare(metadata %Foo* %y, metadata !52, metadata !DIExpression()), !dbg !57 ret void, !dbg !58 } ```
```zig export fn entry() void { var x: ?Foo = foo(); } ``` ```llvm define void @entry() #2 !dbg !41 { Entry: %x = alloca { %Foo, i1 }, align 4 %0 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %x, i32 0, i32 1, !dbg !57 store i1 true, i1* %0, align 1, !dbg !57 %1 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %x, i32 0, i32 0, !dbg !57 call fastcc void @foo(%Foo* sret %1), !dbg !58 call void @llvm.dbg.declare(metadata { %Foo, i1 }* %x, metadata !45, metadata !DIExpression()), !dbg !57 ret void, !dbg !59 } ```
```zig export fn entry() void { var a: i32 = 1234; var b: ?i32 = a; } ``` ```llvm define void @entry() #2 !dbg !41 { Entry: %a = alloca i32, align 4 %b = alloca { i32, i1 }, align 4 store i32 1234, i32* %a, align 4, !dbg !55 call void @llvm.dbg.declare(metadata i32* %a, metadata !45, metadata !DIExpression()), !dbg !55 %0 = load i32, i32* %a, align 4, !dbg !56 %1 = getelementptr inbounds { i32, i1 }, { i32, i1 }* %b, i32 0, i32 1, !dbg !57 store i1 true, i1* %1, align 1, !dbg !57 %2 = getelementptr inbounds { i32, i1 }, { i32, i1 }* %b, i32 0, i32 0, !dbg !57 store i32 %0, i32* %2, align 4, !dbg !57 call void @llvm.dbg.declare(metadata { i32, i1 }* %b, metadata !48, metadata !DIExpression()), !dbg !57 ret void, !dbg !58 } ```
```zig export fn entry() void { var y = true; var z = bar(); var x = if (y) foo() else z; } ``` ```llvm define void @entry() #2 !dbg !41 { Entry: %y = alloca i1, align 1 %z = alloca %Foo, align 4 %x = alloca %Foo, align 4 store i1 true, i1* %y, align 1, !dbg !57 call void @llvm.dbg.declare(metadata i1* %y, metadata !45, metadata !DIExpression()), !dbg !58 call fastcc void @bar(%Foo* sret %z), !dbg !59 call void @llvm.dbg.declare(metadata %Foo* %z, metadata !48, metadata !DIExpression()), !dbg !60 %0 = load i1, i1* %y, align 1, !dbg !61 br i1 %0, label %Then, label %Else, !dbg !61 Then: ; preds = %Entry call fastcc void @foo(%Foo* sret %x), !dbg !62 br label %EndIf, !dbg !63 Else: ; preds = %Entry %1 = bitcast %Foo* %z to i8*, !dbg !64 %2 = bitcast %Foo* %x to i8*, !dbg !64 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %2, i8* align 4 %1, i64 8, i1 false), !dbg !64 br label %EndIf, !dbg !63 EndIf: ; preds = %Else, %Then call void @llvm.dbg.declare(metadata %Foo* %x, metadata !55, metadata !DIExpression()), !dbg !65 ret void, !dbg !66 } ```
```zig export fn entry() void { var x: error!Foo = foo(); } ``` ```llvm define void @entry() #2 !dbg !41 { Entry: %x = alloca { i16, %Foo }, align 4 %0 = getelementptr inbounds { i16, %Foo }, { i16, %Foo }* %x, i32 0, i32 0, !dbg !56 store i16 0, i16* %0, align 2, !dbg !56 %1 = getelementptr inbounds { i16, %Foo }, { i16, %Foo }* %x, i32 0, i32 1, !dbg !56 call fastcc void @foo(%Foo* sret %1), !dbg !57 call void @llvm.dbg.declare(metadata { i16, %Foo }* %x, metadata !45, metadata !DIExpression()), !dbg !56 ret void, !dbg !58 } ```
```zig export fn entry() void { var x: error!Foo = fail(); } ``` ```llvm define void @entry() #2 !dbg !42 { Entry: %x = alloca { i16, %Foo }, align 4 %0 = getelementptr inbounds { i16, %Foo }, { i16, %Foo }* %x, i32 0, i32 0, !dbg !57 %1 = call fastcc i16 @fail(), !dbg !58 store i16 %1, i16* %0, align 2, !dbg !58 ret void, !dbg !59 } ```
```zig export fn entry() void { var x: error!?Foo = bar(); } ``` ```llvm define void @entry() #2 !dbg !41 { Entry: %x = alloca { i16, { %Foo, i1 } }, align 4 %0 = getelementptr inbounds { i16, { %Foo, i1 } }, { i16, { %Foo, i1 } }* %x, i32 0, i32 0, !dbg !61 store i16 0, i16* %0, align 2, !dbg !61 %1 = getelementptr inbounds { i16, { %Foo, i1 } }, { i16, { %Foo, i1 } }* %x, i32 0, i32 1, !dbg !61 %2 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %1, i32 0, i32 1, !dbg !61 store i1 true, i1* %2, align 1, !dbg !61 %3 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %1, i32 0, i32 0, !dbg !61 call fastcc void @bar(%Foo* sret %3), !dbg !62 ret void, !dbg !63 } ```
```zig export fn entry() void { var x = Foo.{ .x = 1, .y = bar(), }; } ``` ```llvm define void @entry() #2 !dbg !41 { Entry: %x = alloca %Foo, align 4 %0 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 0, !dbg !56 store i32 1, i32* %0, align 4, !dbg !57 %1 = getelementptr inbounds %Foo, %Foo* %x, i32 0, i32 1, !dbg !58 call fastcc void @bar(%Bar* sret %1), !dbg !59 ret void, !dbg !60 } ```
```zig export fn entry() void { var x: error!Bar = fail(); var z = x catch unreachable; } ``` ```llvm define void @entry() #2 !dbg !42 { Entry: %error_return_trace_addresses = alloca [30 x i64], align 8 %error_return_trace = alloca %StackTrace, align 8 %x = alloca { i16, %Bar }, align 4 %z = alloca %Bar, align 4 %0 = getelementptr inbounds %StackTrace, %StackTrace* %error_return_trace, i32 0, i32 0 store i64 0, i64* %0, align 8 %1 = getelementptr inbounds %StackTrace, %StackTrace* %error_return_trace, i32 0, i32 1 %2 = getelementptr inbounds %"[]usize", %"[]usize"* %1, i32 0, i32 0 %3 = getelementptr inbounds [30 x i64], [30 x i64]* %error_return_trace_addresses, i64 0, i64 0 store i64* %3, i64** %2, align 8 %4 = getelementptr inbounds %"[]usize", %"[]usize"* %1, i32 0, i32 1 store i64 30, i64* %4, align 8 %5 = getelementptr inbounds { i16, %Bar }, { i16, %Bar }* %x, i32 0, i32 0, !dbg !59 %6 = call fastcc i16 @fail(%StackTrace* %error_return_trace), !dbg !60 store i16 %6, i16* %5, align 2, !dbg !60 call void @llvm.dbg.declare(metadata { i16, %Bar }* %x, metadata !46, metadata !DIExpression()), !dbg !59 %7 = getelementptr inbounds { i16, %Bar }, { i16, %Bar }* %x, i32 0, i32 1, !dbg !61 %8 = bitcast %Bar* %7 to i8*, !dbg !61 %9 = bitcast %Bar* %z to i8*, !dbg !61 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %9, i8* align 4 %8, i64 8, i1 false), !dbg !61 %10 = getelementptr inbounds { i16, %Bar }, { i16, %Bar }* %x, i32 0, i32 0, !dbg !61 %11 = load i16, i16* %10, align 2, !dbg !61 %12 = icmp eq i16 %11, 0, !dbg !62 br i1 %12, label %UnwrapErrOk, label %UnwrapErrError, !dbg !62 UnwrapErrError: ; preds = %Entry tail call fastcc void @__zig_fail_unwrap(%StackTrace* %error_return_trace, i16 %11), !dbg !62 unreachable, !dbg !62 UnwrapErrOk: ; preds = %Entry call void @llvm.dbg.declare(metadata %Bar* %z, metadata !57, metadata !DIExpression()), !dbg !63 ret void, !dbg !64 } ```
This commit also makes `@sizeOf(?error) == @sizeof(error)`. Since 0 is not a valid error code, 0 can be used for the null value, in the same way that 0 is used for the null value of pointers. ```zig export fn entry() void { var x: error!Bar = fail(); var y = x catch bar2(); } ``` ```llvm define void @entry() #2 !dbg !42 { Entry: %error_return_trace_addresses = alloca [30 x i64], align 8 %error_return_trace = alloca %StackTrace, align 8 %x = alloca { i16, %Bar }, align 4 %y = alloca %Bar, align 4 %0 = getelementptr inbounds %StackTrace, %StackTrace* %error_return_trace, i32 0, i32 0 store i64 0, i64* %0, align 8 %1 = getelementptr inbounds %StackTrace, %StackTrace* %error_return_trace, i32 0, i32 1 %2 = getelementptr inbounds %"[]usize", %"[]usize"* %1, i32 0, i32 0 %3 = getelementptr inbounds [30 x i64], [30 x i64]* %error_return_trace_addresses, i64 0, i64 0 store i64* %3, i64** %2, align 8 %4 = getelementptr inbounds %"[]usize", %"[]usize"* %1, i32 0, i32 1 store i64 30, i64* %4, align 8 %5 = getelementptr inbounds { i16, %Bar }, { i16, %Bar }* %x, i32 0, i32 0, !dbg !59 %6 = call fastcc i16 @fail(%StackTrace* %error_return_trace), !dbg !60 store i16 %6, i16* %5, align 2, !dbg !60 call void @llvm.dbg.declare(metadata { i16, %Bar }* %x, metadata !46, metadata !DIExpression()), !dbg !59 %7 = getelementptr inbounds { i16, %Bar }, { i16, %Bar }* %x, i32 0, i32 1, !dbg !61 %8 = bitcast %Bar* %7 to i8*, !dbg !61 %9 = bitcast %Bar* %y to i8*, !dbg !61 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %9, i8* align 4 %8, i64 8, i1 false), !dbg !61 %10 = getelementptr inbounds { i16, %Bar }, { i16, %Bar }* %x, i32 0, i32 0, !dbg !61 %11 = load i16, i16* %10, align 2, !dbg !62 %12 = icmp ne i16 %11, 0, !dbg !62 br i1 %12, label %CatchError, label %CatchEnd, !dbg !62 CatchError: ; preds = %Entry call fastcc void @bar2(%Bar* sret %y), !dbg !63 br label %CatchEnd, !dbg !62 CatchEnd: ; preds = %CatchError, %Entry call void @llvm.dbg.declare(metadata %Bar* %y, metadata !57, metadata !DIExpression()), !dbg !64 ret void, !dbg !65 } ```
```zig export fn entry() void { var c = true; var y: i32 = if (c) 1234 else 5678; } ``` ```llvm define void @entry() #2 !dbg !41 { Entry: %c = alloca i1, align 1 %y = alloca i32, align 4 store i1 true, i1* %c, align 1, !dbg !51 call void @llvm.dbg.declare(metadata i1* %c, metadata !45, metadata !DIExpression()), !dbg !52 %0 = load i1, i1* %c, align 1, !dbg !53 br i1 %0, label %Then, label %Else, !dbg !53 Then: ; preds = %Entry store i32 1234, i32* %y, align 4, !dbg !54 br label %EndIf, !dbg !55 Else: ; preds = %Entry store i32 5678, i32* %y, align 4, !dbg !56 br label %EndIf, !dbg !55 EndIf: ; preds = %Else, %Then call void @llvm.dbg.declare(metadata i32* %y, metadata !48, metadata !DIExpression()), !dbg !57 ret void, !dbg !58 } ```
```zig export fn entry() void { var x: ?Foo = foo(); var y = if (x) |a| a.y else bar(); } ``` ```llvm define void @entry() #2 !dbg !41 { Entry: %x = alloca { %Foo, i1 }, align 4 %y = alloca %Bar, align 4 %0 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %x, i32 0, i32 1, !dbg !64 store i1 true, i1* %0, align 1, !dbg !64 %1 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %x, i32 0, i32 0, !dbg !64 call fastcc void @foo(%Foo* sret %1), !dbg !65 call void @llvm.dbg.declare(metadata { %Foo, i1 }* %x, metadata !45, metadata !DIExpression()), !dbg !64 %2 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %x, i32 0, i32 1, !dbg !66 %3 = load i1, i1* %2, align 1, !dbg !66 br i1 %3, label %OptionalThen, label %OptionalElse, !dbg !66 OptionalThen: ; preds = %Entry %4 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %x, i32 0, i32 0, !dbg !66 call void @llvm.dbg.declare(metadata %Foo* %4, metadata !61, metadata !DIExpression()), !dbg !66 %5 = getelementptr inbounds %Foo, %Foo* %4, i32 0, i32 1, !dbg !67 %6 = bitcast %Bar* %5 to i8*, !dbg !67 %7 = bitcast %Bar* %y to i8*, !dbg !67 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %7, i8* align 4 %6, i64 8, i1 false), !dbg !67 br label %OptionalEndIf, !dbg !66 OptionalElse: ; preds = %Entry call fastcc void @bar(%Bar* sret %y), !dbg !69 br label %OptionalEndIf, !dbg !66 OptionalEndIf: ; preds = %OptionalElse, %OptionalThen call void @llvm.dbg.declare(metadata %Bar* %y, metadata !63, metadata !DIExpression()), !dbg !70 ret void, !dbg !71 } ```
```zig export fn entry() void { var x: error!Foo = foo(); var y = if (x) |a| a.y else |e| bar(); } ``` ```llvm define void @entry() #2 !dbg !41 { Entry: %x = alloca { i16, %Foo }, align 4 %y = alloca %Bar, align 4 %0 = getelementptr inbounds { i16, %Foo }, { i16, %Foo }* %x, i32 0, i32 0, !dbg !64 store i16 0, i16* %0, align 2, !dbg !64 %1 = getelementptr inbounds { i16, %Foo }, { i16, %Foo }* %x, i32 0, i32 1, !dbg !64 call fastcc void @foo(%Foo* sret %1), !dbg !65 call void @llvm.dbg.declare(metadata { i16, %Foo }* %x, metadata !45, metadata !DIExpression()), !dbg !64 %2 = getelementptr inbounds { i16, %Foo }, { i16, %Foo }* %x, i32 0, i32 0, !dbg !66 %3 = load i16, i16* %2, align 2, !dbg !66 %4 = icmp ne i16 %3, 0, !dbg !66 br i1 %4, label %IfErrElse, label %IfErrThen, !dbg !66 IfErrThen: ; preds = %Entry %5 = getelementptr inbounds { i16, %Foo }, { i16, %Foo }* %x, i32 0, i32 1, !dbg !66 call void @llvm.dbg.declare(metadata %Foo* %5, metadata !60, metadata !DIExpression()), !dbg !66 %6 = getelementptr inbounds %Foo, %Foo* %5, i32 0, i32 1, !dbg !67 %7 = bitcast %Bar* %6 to i8*, !dbg !67 %8 = bitcast %Bar* %y to i8*, !dbg !67 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %8, i8* align 4 %7, i64 8, i1 false), !dbg !67 br label %IfErrEnd, !dbg !66 IfErrElse: ; preds = %Entry %9 = load i16, i16* %2, align 2, !dbg !66 call void @llvm.dbg.declare(metadata i16* %2, metadata !62, metadata !DIExpression()), !dbg !66 call fastcc void @bar(%Bar* sret %y), !dbg !69 br label %IfErrEnd, !dbg !66 IfErrEnd: ; preds = %IfErrElse, %IfErrThen call void @llvm.dbg.declare(metadata %Bar* %y, metadata !63, metadata !DIExpression()), !dbg !71 ret void, !dbg !72 } ```
```zig export fn entry() void { var x = error.Failure; var y: error!Foo = x; } ``` ```llvm define void @entry() #2 !dbg !42 { Entry: %x = alloca i16, align 2 %y = alloca { i16, %Foo }, align 4 store i16 1, i16* %x, align 2, !dbg !63 call void @llvm.dbg.declare(metadata i16* %x, metadata !46, metadata !DIExpression()), !dbg !64 %0 = load i16, i16* %x, align 2, !dbg !65 %1 = getelementptr inbounds { i16, %Foo }, { i16, %Foo }* %y, i32 0, i32 0, !dbg !66 store i16 %0, i16* %1, align 2, !dbg !65 call void @llvm.dbg.declare(metadata { i16, %Foo }* %y, metadata !48, metadata !DIExpression()), !dbg !66 ret void, !dbg !67 } ```
```zig export fn entry() void { var x: error!i32 = 1234; var y = if (x) |a| a else |e| 5678; } ``` ```llvm define void @entry() #2 !dbg !41 { Entry: %x = alloca { i16, i32 }, align 4 %y = alloca i32, align 4 %0 = bitcast { i16, i32 }* %x to i8*, !dbg !56 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %0, i8* align 4 bitcast ({ i16, i32 }* @0 to i8*), i64 8, i1 false), !dbg !56 call void @llvm.dbg.declare(metadata { i16, i32 }* %x, metadata !45, metadata !DIExpression()), !dbg !57 %1 = getelementptr inbounds { i16, i32 }, { i16, i32 }* %x, i32 0, i32 0, !dbg !58 %2 = load i16, i16* %1, align 2, !dbg !58 %3 = icmp ne i16 %2, 0, !dbg !58 br i1 %3, label %IfErrElse, label %IfErrThen, !dbg !58 IfErrThen: ; preds = %Entry %4 = getelementptr inbounds { i16, i32 }, { i16, i32 }* %x, i32 0, i32 1, !dbg !58 call void @llvm.dbg.declare(metadata i32* %4, metadata !52, metadata !DIExpression()), !dbg !58 %5 = load i32, i32* %4, align 4, !dbg !59 store i32 %5, i32* %y, align 4, !dbg !59 br label %IfErrEnd, !dbg !58 IfErrElse: ; preds = %Entry %6 = load i16, i16* %1, align 2, !dbg !58 call void @llvm.dbg.declare(metadata i16* %1, metadata !54, metadata !DIExpression()), !dbg !58 store i32 5678, i32* %y, align 4, !dbg !61 br label %IfErrEnd, !dbg !58 IfErrEnd: ; preds = %IfErrElse, %IfErrThen call void @llvm.dbg.declare(metadata i32* %y, metadata !55, metadata !DIExpression()), !dbg !63 ret void, !dbg !64 } ```
```zig export fn entry() void { var c = false; var x: ?Foo = foo(); var z = while (x) |a| { _ = if (c) break a.y; } else bar(); } ``` ```llvm define void @entry() #2 !dbg !41 { Entry: %c = alloca i1, align 1 %x = alloca { %Foo, i1 }, align 4 %z = alloca %Bar, align 4 store i1 false, i1* %c, align 1, !dbg !66 call void @llvm.dbg.declare(metadata i1* %c, metadata !45, metadata !DIExpression()), !dbg !67 %0 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %x, i32 0, i32 1, !dbg !68 store i1 true, i1* %0, align 1, !dbg !68 %1 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %x, i32 0, i32 0, !dbg !68 call fastcc void @foo(%Foo* sret %1), !dbg !69 call void @llvm.dbg.declare(metadata { %Foo, i1 }* %x, metadata !48, metadata !DIExpression()), !dbg !68 br label %WhileCond, !dbg !70 WhileCond: ; preds = %Else, %Entry %2 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %x, i32 0, i32 1, !dbg !71 %3 = load i1, i1* %2, align 1, !dbg !71 br i1 %3, label %WhileBody, label %WhileElse, !dbg !71 WhileBody: ; preds = %WhileCond %4 = getelementptr inbounds { %Foo, i1 }, { %Foo, i1 }* %x, i32 0, i32 0, !dbg !72 call void @llvm.dbg.declare(metadata %Foo* %4, metadata !63, metadata !DIExpression()), !dbg !70 %5 = load i1, i1* %c, align 1, !dbg !74 br i1 %5, label %Then, label %Else, !dbg !74 Then: ; preds = %WhileBody %6 = getelementptr inbounds %Foo, %Foo* %4, i32 0, i32 1, !dbg !76 %7 = bitcast %Bar* %6 to i8*, !dbg !76 %8 = bitcast %Bar* %z to i8*, !dbg !76 call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 4 %8, i8* align 4 %7, i64 8, i1 false), !dbg !76 br label %WhileEnd, !dbg !77 Else: ; preds = %WhileBody br label %WhileCond, !dbg !72 WhileElse: ; preds = %WhileCond call fastcc void @bar(%Bar* sret %z), !dbg !78 br label %WhileEnd, !dbg !70 WhileEnd: ; preds = %WhileElse, %Then call void @llvm.dbg.declare(metadata %Bar* %z, metadata !65, metadata !DIExpression()), !dbg !79 ret void, !dbg !80 } ```
All behavior tests are now passing in the copy elision branch.
...error union function call
also restore default panic handler code
...const slice cast in array literal
...pointer return value I had to put the panic handler stub back in since some code was being incorrectly comptime eliminated.
This branch also started going in a design direction and with a code quality that I was not comfortable with. I have backported all the extra stuff from this branch back into master in 581edd6 and when tackling copy elision I will try a third approach. The third approach involves breaking IR pass 2 (the analysis pass) into sub-phases:
With this framework in place, in IR pass 1, result location instructions will be generated to track result locations throughout expressions. However unlike in this pull request, they will be lazy. Pass 1 will only create the tree structure of result locations, correlated to the corresponding instructions. In the dual phased Pass 2, result locations will be resolved with full type information, which is a key difference. The separate is_comptime computation helps when there are "peer" expressions, for example an if expression or a switch expression. Each "prong" has the is_comptime value computed, and if all of them are comptime-known, then all of them are analyzed as comptime. Otherwise all of them are analyzed as runtime. This will also fix this particularly tricky test case, as mentioned in #1682 (comment) export fn entry(cond: bool, a: i8, b: i32) void {
const x = if (cond) a else b;
} So the plan is to close this branch, and then branch again from master. However, I think there are some important things to work on before embarking on a third copy elision attempt, such as merging the outstanding pull requests, and some other features to get into 0.4.0 besides copy elision. Master branch is open for business. |
Not satisfied with how the code was looking in #1652, I'm tossing out that work and starting over. This branch uses the IR system directly to implement copy elision, instead of awkwardly patching over it.
The goals of this branch are the same:
var foo = async bar()
.This does not solve the problem of how to access the result location of a function, (e.g. #287 (comment)). That is left for a future change.
Note that clang already generates code like this. This PR is actually Zig catching up with Clang in this particular area.
Checklist:
*[N]T
to[]T
@sliceToBytes
orelse
catch
with identifier expressioncatch
with fn call expressioncatch
with other expression which requires stack allocacatch
access of the error code.?
try
catch unreachable
with identifier expressioncatch unreachable
with fn call expressioncatch unreachable
with other expression which requires stack alloca@noInlineCall
/@inlineCall
parametersir_lval_wrap
@sizeOf(?error)
sret
? should the error value / null value be a pointer argument?See each commit message in this branch for example Zig/LLVM code.
Some interesting tidbits:
a catch b
is no longer syntactic sugar forif (a) |x| x else |_| b
. The former provides copy elision; the latter does not. Theif
expression creates a result location fora
, whereas thecatch
expression does not create a result location.try a
is no longer syntactic sugar forif (a) |x| x else |e| return e
. Same explanation.a orelse b
is no longer syntactic sugar forif (a) |x| x else b
. However,a.?
is still syntactic sugar fora orelse unreachable
.