| author | |
| committer | |
| log | 525b1e8fb4abc38143a6ae47272fd5d016ba7eeb |
| tree | ee16b05de3828936971df6d977e75d5825b10547 |
| parent | d28aa38db71a861fd2036efbb22e57c1d34a5615 |
| parent | 656cc33f8d49cb5e79cd3f9f8f56963747d43ed6 |
| signature |
introduce `@call` and remove other builtin calls35 files changed, 995 insertions(+), 445 deletions(-)
doc/langref.html.in+93-86| ... | ... | @@ -6839,6 +6839,99 @@ async fn func(y: *i32) void { |
| 6839 | 6839 | </p> |
| 6840 | 6840 | {#header_close#} |
| 6841 | 6841 | |
| 6842 | {#header_open|@call#} | |
| 6843 | <pre>{#syntax#}@call(options: std.builtin.CallOptions, function: var, args: var) var{#endsyntax#}</pre> | |
| 6844 | <p> | |
| 6845 | Calls a function, in the same way that invoking an expression with parentheses does: | |
| 6846 | </p> | |
| 6847 | {#code_begin|test|call#} | |
| 6848 | const assert = @import("std").debug.assert; | |
| 6849 | ||
| 6850 | test "noinline function call" { | |
| 6851 | assert(@call(.{}, add, .{3, 9}) == 12); | |
| 6852 | } | |
| 6853 | ||
| 6854 | fn add(a: i32, b: i32) i32 { | |
| 6855 | return a + b; | |
| 6856 | } | |
| 6857 | {#code_end#} | |
| 6858 | <p> | |
| 6859 | {#syntax#}@call{#endsyntax#} allows more flexibility than normal function call syntax does. The | |
| 6860 | {#syntax#}CallOptions{#endsyntax#} struct is reproduced here: | |
| 6861 | </p> | |
| 6862 | {#code_begin|syntax#} | |
| 6863 | pub const CallOptions = struct { | |
| 6864 | modifier: Modifier = .auto, | |
| 6865 | stack: ?[]align(std.Target.stack_align) u8 = null, | |
| 6866 | ||
| 6867 | pub const Modifier = enum { | |
| 6868 | /// Equivalent to function call syntax. | |
| 6869 | auto, | |
| 6870 | ||
| 6871 | /// Prevents tail call optimization. This guarantees that the return | |
| 6872 | /// address will point to the callsite, as opposed to the callsite's | |
| 6873 | /// callsite. If the call is otherwise required to be tail-called | |
| 6874 | /// or inlined, a compile error is emitted instead. | |
| 6875 | never_tail, | |
| 6876 | ||
| 6877 | /// Guarantees that the call will not be inlined. If the call is | |
| 6878 | /// otherwise required to be inlined, a compile error is emitted instead. | |
| 6879 | never_inline, | |
| 6880 | ||
| 6881 | /// Asserts that the function call will not suspend. This allows a | |
| 6882 | /// non-async function to call an async function. | |
| 6883 | no_async, | |
| 6884 | ||
| 6885 | /// Guarantees that the call will be generated with tail call optimization. | |
| 6886 | /// If this is not possible, a compile error is emitted instead. | |
| 6887 | always_tail, | |
| 6888 | ||
| 6889 | /// Guarantees that the call will inlined at the callsite. | |
| 6890 | /// If this is not possible, a compile error is emitted instead. | |
| 6891 | always_inline, | |
| 6892 | ||
| 6893 | /// Evaluates the call at compile-time. If the call cannot be completed at | |
| 6894 | /// compile-time, a compile error is emitted instead. | |
| 6895 | compile_time, | |
| 6896 | }; | |
| 6897 | }; | |
| 6898 | {#code_end#} | |
| 6899 | ||
| 6900 | {#header_open|Calling with a New Stack#} | |
| 6901 | <p> | |
| 6902 | When the {#syntax#}stack{#endsyntax#} option is provided, instead of using the same stack as the caller, the function uses the provided stack. | |
| 6903 | </p> | |
| 6904 | {#code_begin|test|new_stack_call#} | |
| 6905 | const std = @import("std"); | |
| 6906 | const assert = std.debug.assert; | |
| 6907 | ||
| 6908 | var new_stack_bytes: [1024]u8 align(16) = undefined; | |
| 6909 | ||
| 6910 | test "calling a function with a new stack" { | |
| 6911 | const arg = 1234; | |
| 6912 | ||
| 6913 | const a = @call(.{.stack = new_stack_bytes[0..512]}, targetFunction, .{arg}); | |
| 6914 | const b = @call(.{.stack = new_stack_bytes[512..]}, targetFunction, .{arg}); | |
| 6915 | _ = targetFunction(arg); | |
| 6916 | ||
| 6917 | assert(arg == 1234); | |
| 6918 | assert(a < b); | |
| 6919 | } | |
| 6920 | ||
| 6921 | fn targetFunction(x: i32) usize { | |
| 6922 | assert(x == 1234); | |
| 6923 | ||
| 6924 | var local_variable: i32 = 42; | |
| 6925 | const ptr = &local_variable; | |
| 6926 | ptr.* += 1; | |
| 6927 | ||
| 6928 | assert(local_variable == 43); | |
| 6929 | return @ptrToInt(ptr); | |
| 6930 | } | |
| 6931 | {#code_end#} | |
| 6932 | {#header_close#} | |
| 6933 | {#header_close#} | |
| 6934 | ||
| 6842 | 6935 | {#header_open|@cDefine#} |
| 6843 | 6936 | <pre>{#syntax#}@cDefine(comptime name: []u8, value){#endsyntax#}</pre> |
| 6844 | 6937 | <p> |
| ... | ... | @@ -7424,27 +7517,6 @@ test "@hasDecl" { |
| 7424 | 7517 | {#see_also|Compile Variables|@embedFile#} |
| 7425 | 7518 | {#header_close#} |
| 7426 | 7519 | |
| 7427 | {#header_open|@inlineCall#} | |
| 7428 | <pre>{#syntax#}@inlineCall(function: X, args: ...) Y{#endsyntax#}</pre> | |
| 7429 | <p> | |
| 7430 | This calls a function, in the same way that invoking an expression with parentheses does: | |
| 7431 | </p> | |
| 7432 | {#code_begin|test#} | |
| 7433 | const assert = @import("std").debug.assert; | |
| 7434 | ||
| 7435 | test "inline function call" { | |
| 7436 | assert(@inlineCall(add, 3, 9) == 12); | |
| 7437 | } | |
| 7438 | ||
| 7439 | fn add(a: i32, b: i32) i32 { return a + b; } | |
| 7440 | {#code_end#} | |
| 7441 | <p> | |
| 7442 | Unlike a normal function call, however, {#syntax#}@inlineCall{#endsyntax#} guarantees that the call | |
| 7443 | will be inlined. If the call cannot be inlined, a compile error is emitted. | |
| 7444 | </p> | |
| 7445 | {#see_also|@noInlineCall#} | |
| 7446 | {#header_close#} | |
| 7447 | ||
| 7448 | 7520 | {#header_open|@intCast#} |
| 7449 | 7521 | <pre>{#syntax#}@intCast(comptime DestType: type, int: var) DestType{#endsyntax#}</pre> |
| 7450 | 7522 | <p> |
| ... | ... | @@ -7602,71 +7674,6 @@ mem.set(u8, dest, c);{#endsyntax#}</pre> |
| 7602 | 7674 | </p> |
| 7603 | 7675 | {#header_close#} |
| 7604 | 7676 | |
| 7605 | {#header_open|@newStackCall#} | |
| 7606 | <pre>{#syntax#}@newStackCall(new_stack: []align(target_stack_align) u8, function: var, args: ...) var{#endsyntax#}</pre> | |
| 7607 | <p> | |
| 7608 | This calls a function, in the same way that invoking an expression with parentheses does. However, | |
| 7609 | instead of using the same stack as the caller, the function uses the stack provided in the {#syntax#}new_stack{#endsyntax#} | |
| 7610 | parameter. | |
| 7611 | </p> | |
| 7612 | <p> | |
| 7613 | The new stack must be aligned to {#syntax#}target_stack_align{#endsyntax#} bytes. This is a target-specific | |
| 7614 | number. A safe value that will work on all targets is {#syntax#}16{#endsyntax#}. This value can | |
| 7615 | also be obtained by using {#link|@sizeOf#} on the {#link|@Frame#} type of {#link|Async Functions#}. | |
| 7616 | </p> | |
| 7617 | {#code_begin|test#} | |
| 7618 | const std = @import("std"); | |
| 7619 | const assert = std.debug.assert; | |
| 7620 | ||
| 7621 | var new_stack_bytes: [1024]u8 align(16) = undefined; | |
| 7622 | ||
| 7623 | test "calling a function with a new stack" { | |
| 7624 | const arg = 1234; | |
| 7625 | ||
| 7626 | const a = @newStackCall(new_stack_bytes[0..512], targetFunction, arg); | |
| 7627 | const b = @newStackCall(new_stack_bytes[512..], targetFunction, arg); | |
| 7628 | _ = targetFunction(arg); | |
| 7629 | ||
| 7630 | assert(arg == 1234); | |
| 7631 | assert(a < b); | |
| 7632 | } | |
| 7633 | ||
| 7634 | fn targetFunction(x: i32) usize { | |
| 7635 | assert(x == 1234); | |
| 7636 | ||
| 7637 | var local_variable: i32 = 42; | |
| 7638 | const ptr = &local_variable; | |
| 7639 | ptr.* += 1; | |
| 7640 | ||
| 7641 | assert(local_variable == 43); | |
| 7642 | return @ptrToInt(ptr); | |
| 7643 | } | |
| 7644 | {#code_end#} | |
| 7645 | {#header_close#} | |
| 7646 | ||
| 7647 | {#header_open|@noInlineCall#} | |
| 7648 | <pre>{#syntax#}@noInlineCall(function: var, args: ...) var{#endsyntax#}</pre> | |
| 7649 | <p> | |
| 7650 | This calls a function, in the same way that invoking an expression with parentheses does: | |
| 7651 | </p> | |
| 7652 | {#code_begin|test#} | |
| 7653 | const assert = @import("std").debug.assert; | |
| 7654 | ||
| 7655 | test "noinline function call" { | |
| 7656 | assert(@noInlineCall(add, 3, 9) == 12); | |
| 7657 | } | |
| 7658 | ||
| 7659 | fn add(a: i32, b: i32) i32 { | |
| 7660 | return a + b; | |
| 7661 | } | |
| 7662 | {#code_end#} | |
| 7663 | <p> | |
| 7664 | Unlike a normal function call, however, {#syntax#}@noInlineCall{#endsyntax#} guarantees that the call | |
| 7665 | will not be inlined. If the call must be inlined, a compile error is emitted. | |
| 7666 | </p> | |
| 7667 | {#see_also|@inlineCall#} | |
| 7668 | {#header_close#} | |
| 7669 | ||
| 7670 | 7677 | {#header_open|@OpaqueType#} |
| 7671 | 7678 | <pre>{#syntax#}@OpaqueType() type{#endsyntax#}</pre> |
| 7672 | 7679 | <p> |
lib/std/builtin.zig+38| ... | ... | @@ -372,6 +372,44 @@ pub const Version = struct { |
| 372 | 372 | patch: u32, |
| 373 | 373 | }; |
| 374 | 374 | |
| 375 | /// This data structure is used by the Zig language code generation and | |
| 376 | /// therefore must be kept in sync with the compiler implementation. | |
| 377 | pub const CallOptions = struct { | |
| 378 | modifier: Modifier = .auto, | |
| 379 | stack: ?[]align(std.Target.stack_align) u8 = null, | |
| 380 | ||
| 381 | pub const Modifier = enum { | |
| 382 | /// Equivalent to function call syntax. | |
| 383 | auto, | |
| 384 | ||
| 385 | /// Prevents tail call optimization. This guarantees that the return | |
| 386 | /// address will point to the callsite, as opposed to the callsite's | |
| 387 | /// callsite. If the call is otherwise required to be tail-called | |
| 388 | /// or inlined, a compile error is emitted instead. | |
| 389 | never_tail, | |
| 390 | ||
| 391 | /// Guarantees that the call will not be inlined. If the call is | |
| 392 | /// otherwise required to be inlined, a compile error is emitted instead. | |
| 393 | never_inline, | |
| 394 | ||
| 395 | /// Asserts that the function call will not suspend. This allows a | |
| 396 | /// non-async function to call an async function. | |
| 397 | no_async, | |
| 398 | ||
| 399 | /// Guarantees that the call will be generated with tail call optimization. | |
| 400 | /// If this is not possible, a compile error is emitted instead. | |
| 401 | always_tail, | |
| 402 | ||
| 403 | /// Guarantees that the call will inlined at the callsite. | |
| 404 | /// If this is not possible, a compile error is emitted instead. | |
| 405 | always_inline, | |
| 406 | ||
| 407 | /// Evaluates the call at compile-time. If the call cannot be completed at | |
| 408 | /// compile-time, a compile error is emitted instead. | |
| 409 | compile_time, | |
| 410 | }; | |
| 411 | }; | |
| 412 | ||
| 375 | 413 | /// This function type is used by the Zig language code generation and |
| 376 | 414 | /// therefore must be kept in sync with the compiler implementation. |
| 377 | 415 | pub const PanicFn = fn ([]const u8, ?*StackTrace) noreturn; |
lib/std/hash/auto_hash.zig+2-2| ... | ... | @@ -92,7 +92,7 @@ pub fn hash(hasher: var, key: var, comptime strat: HashStrategy) void { |
| 92 | 92 | |
| 93 | 93 | // Help the optimizer see that hashing an int is easy by inlining! |
| 94 | 94 | // TODO Check if the situation is better after #561 is resolved. |
| 95 | .Int => @inlineCall(hasher.update, std.mem.asBytes(&key)), | |
| 95 | .Int => @call(.{ .modifier = .always_inline }, hasher.update, .{std.mem.asBytes(&key)}), | |
| 96 | 96 | |
| 97 | 97 | .Float => |info| hash(hasher, @bitCast(@IntType(false, info.bits), key), strat), |
| 98 | 98 | |
| ... | ... | @@ -101,7 +101,7 @@ pub fn hash(hasher: var, key: var, comptime strat: HashStrategy) void { |
| 101 | 101 | .ErrorSet => hash(hasher, @errorToInt(key), strat), |
| 102 | 102 | .AnyFrame, .Fn => hash(hasher, @ptrToInt(key), strat), |
| 103 | 103 | |
| 104 | .Pointer => @inlineCall(hashPointer, hasher, key, strat), | |
| 104 | .Pointer => @call(.{ .modifier = .always_inline }, hashPointer, .{ hasher, key, strat }), | |
| 105 | 105 | |
| 106 | 106 | .Optional => if (key) |k| hash(hasher, k, strat), |
| 107 | 107 |
lib/std/hash/cityhash.zig+11-4| ... | ... | @@ -197,7 +197,7 @@ pub const CityHash64 = struct { |
| 197 | 197 | } |
| 198 | 198 | |
| 199 | 199 | fn hashLen16(u: u64, v: u64) u64 { |
| 200 | return @inlineCall(hash128To64, u, v); | |
| 200 | return @call(.{ .modifier = .always_inline }, hash128To64, .{ u, v }); | |
| 201 | 201 | } |
| 202 | 202 | |
| 203 | 203 | fn hashLen16Mul(low: u64, high: u64, mul: u64) u64 { |
| ... | ... | @@ -210,7 +210,7 @@ pub const CityHash64 = struct { |
| 210 | 210 | } |
| 211 | 211 | |
| 212 | 212 | fn hash128To64(low: u64, high: u64) u64 { |
| 213 | return @inlineCall(hashLen16Mul, low, high, 0x9ddfea08eb382d69); | |
| 213 | return @call(.{ .modifier = .always_inline }, hashLen16Mul, .{ low, high, 0x9ddfea08eb382d69 }); | |
| 214 | 214 | } |
| 215 | 215 | |
| 216 | 216 | fn hashLen0To16(str: []const u8) u64 { |
| ... | ... | @@ -291,7 +291,14 @@ pub const CityHash64 = struct { |
| 291 | 291 | } |
| 292 | 292 | |
| 293 | 293 | fn weakHashLen32WithSeeds(ptr: [*]const u8, a: u64, b: u64) WeakPair { |
| 294 | return @inlineCall(weakHashLen32WithSeedsHelper, fetch64(ptr), fetch64(ptr + 8), fetch64(ptr + 16), fetch64(ptr + 24), a, b); | |
| 294 | return @call(.{ .modifier = .always_inline }, weakHashLen32WithSeedsHelper, .{ | |
| 295 | fetch64(ptr), | |
| 296 | fetch64(ptr + 8), | |
| 297 | fetch64(ptr + 16), | |
| 298 | fetch64(ptr + 24), | |
| 299 | a, | |
| 300 | b, | |
| 301 | }); | |
| 295 | 302 | } |
| 296 | 303 | |
| 297 | 304 | pub fn hash(str: []const u8) u64 { |
| ... | ... | @@ -339,7 +346,7 @@ pub const CityHash64 = struct { |
| 339 | 346 | } |
| 340 | 347 | |
| 341 | 348 | pub fn hashWithSeed(str: []const u8, seed: u64) u64 { |
| 342 | return @inlineCall(Self.hashWithSeeds, str, k2, seed); | |
| 349 | return @call(.{ .modifier = .always_inline }, Self.hashWithSeeds, .{ str, k2, seed }); | |
| 343 | 350 | } |
| 344 | 351 | |
| 345 | 352 | pub fn hashWithSeeds(str: []const u8, seed0: u64, seed1: u64) u64 { |
lib/std/hash/murmur.zig+9-9| ... | ... | @@ -8,7 +8,7 @@ pub const Murmur2_32 = struct { |
| 8 | 8 | const Self = @This(); |
| 9 | 9 | |
| 10 | 10 | pub fn hash(str: []const u8) u32 { |
| 11 | return @inlineCall(Self.hashWithSeed, str, default_seed); | |
| 11 | return @call(.{ .modifier = .always_inline }, Self.hashWithSeed, .{ str, default_seed }); | |
| 12 | 12 | } |
| 13 | 13 | |
| 14 | 14 | pub fn hashWithSeed(str: []const u8, seed: u32) u32 { |
| ... | ... | @@ -44,7 +44,7 @@ pub const Murmur2_32 = struct { |
| 44 | 44 | } |
| 45 | 45 | |
| 46 | 46 | pub fn hashUint32(v: u32) u32 { |
| 47 | return @inlineCall(Self.hashUint32WithSeed, v, default_seed); | |
| 47 | return @call(.{ .modifier = .always_inline }, Self.hashUint32WithSeed, .{ v, default_seed }); | |
| 48 | 48 | } |
| 49 | 49 | |
| 50 | 50 | pub fn hashUint32WithSeed(v: u32, seed: u32) u32 { |
| ... | ... | @@ -64,7 +64,7 @@ pub const Murmur2_32 = struct { |
| 64 | 64 | } |
| 65 | 65 | |
| 66 | 66 | pub fn hashUint64(v: u64) u32 { |
| 67 | return @inlineCall(Self.hashUint64WithSeed, v, default_seed); | |
| 67 | return @call(.{ .modifier = .always_inline }, Self.hashUint64WithSeed, .{ v, default_seed }); | |
| 68 | 68 | } |
| 69 | 69 | |
| 70 | 70 | pub fn hashUint64WithSeed(v: u64, seed: u32) u32 { |
| ... | ... | @@ -93,7 +93,7 @@ pub const Murmur2_64 = struct { |
| 93 | 93 | const Self = @This(); |
| 94 | 94 | |
| 95 | 95 | pub fn hash(str: []const u8) u64 { |
| 96 | return @inlineCall(Self.hashWithSeed, str, default_seed); | |
| 96 | return @call(.{ .modifier = .always_inline }, Self.hashWithSeed, .{ str, default_seed }); | |
| 97 | 97 | } |
| 98 | 98 | |
| 99 | 99 | pub fn hashWithSeed(str: []const u8, seed: u64) u64 { |
| ... | ... | @@ -127,7 +127,7 @@ pub const Murmur2_64 = struct { |
| 127 | 127 | } |
| 128 | 128 | |
| 129 | 129 | pub fn hashUint32(v: u32) u64 { |
| 130 | return @inlineCall(Self.hashUint32WithSeed, v, default_seed); | |
| 130 | return @call(.{ .modifier = .always_inline }, Self.hashUint32WithSeed, .{ v, default_seed }); | |
| 131 | 131 | } |
| 132 | 132 | |
| 133 | 133 | pub fn hashUint32WithSeed(v: u32, seed: u32) u64 { |
| ... | ... | @@ -144,7 +144,7 @@ pub const Murmur2_64 = struct { |
| 144 | 144 | } |
| 145 | 145 | |
| 146 | 146 | pub fn hashUint64(v: u64) u64 { |
| 147 | return @inlineCall(Self.hashUint64WithSeed, v, default_seed); | |
| 147 | return @call(.{ .modifier = .always_inline }, Self.hashUint64WithSeed, .{ v, default_seed }); | |
| 148 | 148 | } |
| 149 | 149 | |
| 150 | 150 | pub fn hashUint64WithSeed(v: u64, seed: u32) u64 { |
| ... | ... | @@ -172,7 +172,7 @@ pub const Murmur3_32 = struct { |
| 172 | 172 | } |
| 173 | 173 | |
| 174 | 174 | pub fn hash(str: []const u8) u32 { |
| 175 | return @inlineCall(Self.hashWithSeed, str, default_seed); | |
| 175 | return @call(.{ .modifier = .always_inline }, Self.hashWithSeed, .{ str, default_seed }); | |
| 176 | 176 | } |
| 177 | 177 | |
| 178 | 178 | pub fn hashWithSeed(str: []const u8, seed: u32) u32 { |
| ... | ... | @@ -220,7 +220,7 @@ pub const Murmur3_32 = struct { |
| 220 | 220 | } |
| 221 | 221 | |
| 222 | 222 | pub fn hashUint32(v: u32) u32 { |
| 223 | return @inlineCall(Self.hashUint32WithSeed, v, default_seed); | |
| 223 | return @call(.{ .modifier = .always_inline }, Self.hashUint32WithSeed, .{ v, default_seed }); | |
| 224 | 224 | } |
| 225 | 225 | |
| 226 | 226 | pub fn hashUint32WithSeed(v: u32, seed: u32) u32 { |
| ... | ... | @@ -246,7 +246,7 @@ pub const Murmur3_32 = struct { |
| 246 | 246 | } |
| 247 | 247 | |
| 248 | 248 | pub fn hashUint64(v: u64) u32 { |
| 249 | return @inlineCall(Self.hashUint64WithSeed, v, default_seed); | |
| 249 | return @call(.{ .modifier = .always_inline }, Self.hashUint64WithSeed, .{ v, default_seed }); | |
| 250 | 250 | } |
| 251 | 251 | |
| 252 | 252 | pub fn hashUint64WithSeed(v: u64, seed: u32) u32 { |
lib/std/hash/siphash.zig+12-7| ... | ... | @@ -11,7 +11,7 @@ const testing = std.testing; |
| 11 | 11 | const math = std.math; |
| 12 | 12 | const mem = std.mem; |
| 13 | 13 | |
| 14 | const Endian = @import("builtin").Endian; | |
| 14 | const Endian = std.builtin.Endian; | |
| 15 | 15 | |
| 16 | 16 | pub fn SipHash64(comptime c_rounds: usize, comptime d_rounds: usize) type { |
| 17 | 17 | return SipHash(u64, c_rounds, d_rounds); |
| ... | ... | @@ -62,7 +62,7 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round |
| 62 | 62 | |
| 63 | 63 | var off: usize = 0; |
| 64 | 64 | while (off < b.len) : (off += 8) { |
| 65 | @inlineCall(self.round, b[off .. off + 8]); | |
| 65 | @call(.{ .modifier = .always_inline }, self.round, .{b[off .. off + 8]}); | |
| 66 | 66 | } |
| 67 | 67 | |
| 68 | 68 | self.msg_len +%= @truncate(u8, b.len); |
| ... | ... | @@ -84,9 +84,12 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round |
| 84 | 84 | self.v2 ^= 0xff; |
| 85 | 85 | } |
| 86 | 86 | |
| 87 | // TODO this is a workaround, should be able to supply the value without a separate variable | |
| 88 | const inl = std.builtin.CallOptions{ .modifier = .always_inline }; | |
| 89 | ||
| 87 | 90 | comptime var i: usize = 0; |
| 88 | 91 | inline while (i < d_rounds) : (i += 1) { |
| 89 | @inlineCall(sipRound, self); | |
| 92 | @call(inl, sipRound, .{self}); | |
| 90 | 93 | } |
| 91 | 94 | |
| 92 | 95 | const b1 = self.v0 ^ self.v1 ^ self.v2 ^ self.v3; |
| ... | ... | @@ -98,7 +101,7 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round |
| 98 | 101 | |
| 99 | 102 | comptime var j: usize = 0; |
| 100 | 103 | inline while (j < d_rounds) : (j += 1) { |
| 101 | @inlineCall(sipRound, self); | |
| 104 | @call(inl, sipRound, .{self}); | |
| 102 | 105 | } |
| 103 | 106 | |
| 104 | 107 | const b2 = self.v0 ^ self.v1 ^ self.v2 ^ self.v3; |
| ... | ... | @@ -111,9 +114,11 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round |
| 111 | 114 | const m = mem.readIntSliceLittle(u64, b[0..]); |
| 112 | 115 | self.v3 ^= m; |
| 113 | 116 | |
| 117 | // TODO this is a workaround, should be able to supply the value without a separate variable | |
| 118 | const inl = std.builtin.CallOptions{ .modifier = .always_inline }; | |
| 114 | 119 | comptime var i: usize = 0; |
| 115 | 120 | inline while (i < c_rounds) : (i += 1) { |
| 116 | @inlineCall(sipRound, self); | |
| 121 | @call(inl, sipRound, .{self}); | |
| 117 | 122 | } |
| 118 | 123 | |
| 119 | 124 | self.v0 ^= m; |
| ... | ... | @@ -140,8 +145,8 @@ fn SipHashStateless(comptime T: type, comptime c_rounds: usize, comptime d_round |
| 140 | 145 | const aligned_len = input.len - (input.len % 8); |
| 141 | 146 | |
| 142 | 147 | var c = Self.init(key); |
| 143 | @inlineCall(c.update, input[0..aligned_len]); | |
| 144 | return @inlineCall(c.final, input[aligned_len..]); | |
| 148 | @call(.{ .modifier = .always_inline }, c.update, .{input[0..aligned_len]}); | |
| 149 | return @call(.{ .modifier = .always_inline }, c.final, .{input[aligned_len..]}); | |
| 145 | 150 | } |
| 146 | 151 | }; |
| 147 | 152 | } |
lib/std/hash/wyhash.zig+3-3| ... | ... | @@ -65,7 +65,7 @@ const WyhashStateless = struct { |
| 65 | 65 | |
| 66 | 66 | var off: usize = 0; |
| 67 | 67 | while (off < b.len) : (off += 32) { |
| 68 | @inlineCall(self.round, b[off .. off + 32]); | |
| 68 | @call(.{ .modifier = .always_inline }, self.round, .{b[off .. off + 32]}); | |
| 69 | 69 | } |
| 70 | 70 | |
| 71 | 71 | self.msg_len += b.len; |
| ... | ... | @@ -121,8 +121,8 @@ const WyhashStateless = struct { |
| 121 | 121 | const aligned_len = input.len - (input.len % 32); |
| 122 | 122 | |
| 123 | 123 | var c = WyhashStateless.init(seed); |
| 124 | @inlineCall(c.update, input[0..aligned_len]); | |
| 125 | return @inlineCall(c.final, input[aligned_len..]); | |
| 124 | @call(.{ .modifier = .always_inline }, c.update, .{input[0..aligned_len]}); | |
| 125 | return @call(.{ .modifier = .always_inline }, c.final, .{input[aligned_len..]}); | |
| 126 | 126 | } |
| 127 | 127 | }; |
| 128 | 128 |
lib/std/math/big/int.zig+11-3| ... | ... | @@ -811,7 +811,7 @@ pub const Int = struct { |
| 811 | 811 | |
| 812 | 812 | var j: usize = 0; |
| 813 | 813 | while (j < a_lo.len) : (j += 1) { |
| 814 | a_lo[j] = @inlineCall(addMulLimbWithCarry, a_lo[j], y[j], xi, &carry); | |
| 814 | a_lo[j] = @call(.{ .modifier = .always_inline }, addMulLimbWithCarry, .{ a_lo[j], y[j], xi, &carry }); | |
| 815 | 815 | } |
| 816 | 816 | |
| 817 | 817 | j = 0; |
| ... | ... | @@ -1214,7 +1214,11 @@ pub const Int = struct { |
| 1214 | 1214 | const dst_i = src_i + limb_shift; |
| 1215 | 1215 | |
| 1216 | 1216 | const src_digit = a[src_i]; |
| 1217 | r[dst_i] = carry | @inlineCall(math.shr, Limb, src_digit, Limb.bit_count - @intCast(Limb, interior_limb_shift)); | |
| 1217 | r[dst_i] = carry | @call(.{ .modifier = .always_inline }, math.shr, .{ | |
| 1218 | Limb, | |
| 1219 | src_digit, | |
| 1220 | Limb.bit_count - @intCast(Limb, interior_limb_shift), | |
| 1221 | }); | |
| 1218 | 1222 | carry = (src_digit << interior_limb_shift); |
| 1219 | 1223 | } |
| 1220 | 1224 | |
| ... | ... | @@ -1254,7 +1258,11 @@ pub const Int = struct { |
| 1254 | 1258 | |
| 1255 | 1259 | const src_digit = a[src_i]; |
| 1256 | 1260 | r[dst_i] = carry | (src_digit >> interior_limb_shift); |
| 1257 | carry = @inlineCall(math.shl, Limb, src_digit, Limb.bit_count - @intCast(Limb, interior_limb_shift)); | |
| 1261 | carry = @call(.{ .modifier = .always_inline }, math.shl, .{ | |
| 1262 | Limb, | |
| 1263 | src_digit, | |
| 1264 | Limb.bit_count - @intCast(Limb, interior_limb_shift), | |
| 1265 | }); | |
| 1258 | 1266 | } |
| 1259 | 1267 | } |
| 1260 | 1268 |
lib/std/os/linux.zig+1-1| ... | ... | @@ -94,7 +94,7 @@ pub fn fork() usize { |
| 94 | 94 | /// the compiler is not aware of how vfork affects control flow and you may |
| 95 | 95 | /// see different results in optimized builds. |
| 96 | 96 | pub inline fn vfork() usize { |
| 97 | return @inlineCall(syscall0, SYS_vfork); | |
| 97 | return @call(.{ .modifier = .always_inline }, syscall0, .{SYS_vfork}); | |
| 98 | 98 | } |
| 99 | 99 | |
| 100 | 100 | pub fn futimens(fd: i32, times: *const [2]timespec) usize { |
lib/std/special/compiler_rt/arm/aeabi_dcmp.zig+5-5| ... | ... | @@ -14,31 +14,31 @@ const ConditionalOperator = enum { |
| 14 | 14 | |
| 15 | 15 | pub nakedcc fn __aeabi_dcmpeq() noreturn { |
| 16 | 16 | @setRuntimeSafety(false); |
| 17 | @inlineCall(aeabi_dcmp, .Eq); | |
| 17 | @call(.{ .modifier = .always_inline }, aeabi_dcmp, .{.Eq}); | |
| 18 | 18 | unreachable; |
| 19 | 19 | } |
| 20 | 20 | |
| 21 | 21 | pub nakedcc fn __aeabi_dcmplt() noreturn { |
| 22 | 22 | @setRuntimeSafety(false); |
| 23 | @inlineCall(aeabi_dcmp, .Lt); | |
| 23 | @call(.{ .modifier = .always_inline }, aeabi_dcmp, .{.Lt}); | |
| 24 | 24 | unreachable; |
| 25 | 25 | } |
| 26 | 26 | |
| 27 | 27 | pub nakedcc fn __aeabi_dcmple() noreturn { |
| 28 | 28 | @setRuntimeSafety(false); |
| 29 | @inlineCall(aeabi_dcmp, .Le); | |
| 29 | @call(.{ .modifier = .always_inline }, aeabi_dcmp, .{.Le}); | |
| 30 | 30 | unreachable; |
| 31 | 31 | } |
| 32 | 32 | |
| 33 | 33 | pub nakedcc fn __aeabi_dcmpge() noreturn { |
| 34 | 34 | @setRuntimeSafety(false); |
| 35 | @inlineCall(aeabi_dcmp, .Ge); | |
| 35 | @call(.{ .modifier = .always_inline }, aeabi_dcmp, .{.Ge}); | |
| 36 | 36 | unreachable; |
| 37 | 37 | } |
| 38 | 38 | |
| 39 | 39 | pub nakedcc fn __aeabi_dcmpgt() noreturn { |
| 40 | 40 | @setRuntimeSafety(false); |
| 41 | @inlineCall(aeabi_dcmp, .Gt); | |
| 41 | @call(.{ .modifier = .always_inline }, aeabi_dcmp, .{.Gt}); | |
| 42 | 42 | unreachable; |
| 43 | 43 | } |
| 44 | 44 |
lib/std/special/compiler_rt/arm/aeabi_fcmp.zig+5-5| ... | ... | @@ -14,31 +14,31 @@ const ConditionalOperator = enum { |
| 14 | 14 | |
| 15 | 15 | pub nakedcc fn __aeabi_fcmpeq() noreturn { |
| 16 | 16 | @setRuntimeSafety(false); |
| 17 | @inlineCall(aeabi_fcmp, .Eq); | |
| 17 | @call(.{ .modifier = .always_inline }, aeabi_fcmp, .{.Eq}); | |
| 18 | 18 | unreachable; |
| 19 | 19 | } |
| 20 | 20 | |
| 21 | 21 | pub nakedcc fn __aeabi_fcmplt() noreturn { |
| 22 | 22 | @setRuntimeSafety(false); |
| 23 | @inlineCall(aeabi_fcmp, .Lt); | |
| 23 | @call(.{ .modifier = .always_inline }, aeabi_fcmp, .{.Lt}); | |
| 24 | 24 | unreachable; |
| 25 | 25 | } |
| 26 | 26 | |
| 27 | 27 | pub nakedcc fn __aeabi_fcmple() noreturn { |
| 28 | 28 | @setRuntimeSafety(false); |
| 29 | @inlineCall(aeabi_fcmp, .Le); | |
| 29 | @call(.{ .modifier = .always_inline }, aeabi_fcmp, .{.Le}); | |
| 30 | 30 | unreachable; |
| 31 | 31 | } |
| 32 | 32 | |
| 33 | 33 | pub nakedcc fn __aeabi_fcmpge() noreturn { |
| 34 | 34 | @setRuntimeSafety(false); |
| 35 | @inlineCall(aeabi_fcmp, .Ge); | |
| 35 | @call(.{ .modifier = .always_inline }, aeabi_fcmp, .{.Ge}); | |
| 36 | 36 | unreachable; |
| 37 | 37 | } |
| 38 | 38 | |
| 39 | 39 | pub nakedcc fn __aeabi_fcmpgt() noreturn { |
| 40 | 40 | @setRuntimeSafety(false); |
| 41 | @inlineCall(aeabi_fcmp, .Gt); | |
| 41 | @call(.{ .modifier = .always_inline }, aeabi_fcmp, .{.Gt}); | |
| 42 | 42 | unreachable; |
| 43 | 43 | } |
| 44 | 44 |
lib/std/special/compiler_rt/divti3.zig+4-1| ... | ... | @@ -17,7 +17,10 @@ pub extern fn __divti3(a: i128, b: i128) i128 { |
| 17 | 17 | |
| 18 | 18 | const v128 = @Vector(2, u64); |
| 19 | 19 | pub extern fn __divti3_windows_x86_64(a: v128, b: v128) v128 { |
| 20 | return @bitCast(v128, @inlineCall(__divti3, @bitCast(i128, a), @bitCast(i128, b))); | |
| 20 | return @bitCast(v128, @call(.{ .modifier = .always_inline }, __divti3, .{ | |
| 21 | @bitCast(i128, a), | |
| 22 | @bitCast(i128, b), | |
| 23 | })); | |
| 21 | 24 | } |
| 22 | 25 | |
| 23 | 26 | test "import divti3" { |
lib/std/special/compiler_rt/extendXfYf2.zig+4-4| ... | ... | @@ -3,19 +3,19 @@ const builtin = @import("builtin"); |
| 3 | 3 | const is_test = builtin.is_test; |
| 4 | 4 | |
| 5 | 5 | pub extern fn __extendsfdf2(a: f32) f64 { |
| 6 | return @inlineCall(extendXfYf2, f64, f32, @bitCast(u32, a)); | |
| 6 | return @call(.{ .modifier = .always_inline }, extendXfYf2, .{ f64, f32, @bitCast(u32, a) }); | |
| 7 | 7 | } |
| 8 | 8 | |
| 9 | 9 | pub extern fn __extenddftf2(a: f64) f128 { |
| 10 | return @inlineCall(extendXfYf2, f128, f64, @bitCast(u64, a)); | |
| 10 | return @call(.{ .modifier = .always_inline }, extendXfYf2, .{ f128, f64, @bitCast(u64, a) }); | |
| 11 | 11 | } |
| 12 | 12 | |
| 13 | 13 | pub extern fn __extendsftf2(a: f32) f128 { |
| 14 | return @inlineCall(extendXfYf2, f128, f32, @bitCast(u32, a)); | |
| 14 | return @call(.{ .modifier = .always_inline }, extendXfYf2, .{ f128, f32, @bitCast(u32, a) }); | |
| 15 | 15 | } |
| 16 | 16 | |
| 17 | 17 | pub extern fn __extendhfsf2(a: u16) f32 { |
| 18 | return @inlineCall(extendXfYf2, f32, f16, a); | |
| 18 | return @call(.{ .modifier = .always_inline }, extendXfYf2, .{ f32, f16, a }); | |
| 19 | 19 | } |
| 20 | 20 | |
| 21 | 21 | const CHAR_BIT = 8; |
lib/std/special/compiler_rt/floatsiXf.zig+3-3| ... | ... | @@ -55,17 +55,17 @@ fn floatsiXf(comptime T: type, a: i32) T { |
| 55 | 55 | |
| 56 | 56 | pub extern fn __floatsisf(arg: i32) f32 { |
| 57 | 57 | @setRuntimeSafety(builtin.is_test); |
| 58 | return @inlineCall(floatsiXf, f32, arg); | |
| 58 | return @call(.{ .modifier = .always_inline }, floatsiXf, .{ f32, arg }); | |
| 59 | 59 | } |
| 60 | 60 | |
| 61 | 61 | pub extern fn __floatsidf(arg: i32) f64 { |
| 62 | 62 | @setRuntimeSafety(builtin.is_test); |
| 63 | return @inlineCall(floatsiXf, f64, arg); | |
| 63 | return @call(.{ .modifier = .always_inline }, floatsiXf, .{ f64, arg }); | |
| 64 | 64 | } |
| 65 | 65 | |
| 66 | 66 | pub extern fn __floatsitf(arg: i32) f128 { |
| 67 | 67 | @setRuntimeSafety(builtin.is_test); |
| 68 | return @inlineCall(floatsiXf, f128, arg); | |
| 68 | return @call(.{ .modifier = .always_inline }, floatsiXf, .{ f128, arg }); | |
| 69 | 69 | } |
| 70 | 70 | |
| 71 | 71 | fn test_one_floatsitf(a: i32, expected: u128) void { |
lib/std/special/compiler_rt/modti3.zig+4-1| ... | ... | @@ -22,7 +22,10 @@ pub extern fn __modti3(a: i128, b: i128) i128 { |
| 22 | 22 | |
| 23 | 23 | const v128 = @Vector(2, u64); |
| 24 | 24 | pub extern fn __modti3_windows_x86_64(a: v128, b: v128) v128 { |
| 25 | return @bitCast(v128, @inlineCall(__modti3, @bitCast(i128, a), @bitCast(i128, b))); | |
| 25 | return @bitCast(v128, @call(.{ .modifier = .always_inline }, __modti3, .{ | |
| 26 | @bitCast(i128, a), | |
| 27 | @bitCast(i128, b), | |
| 28 | })); | |
| 26 | 29 | } |
| 27 | 30 | |
| 28 | 31 | test "import modti3" { |
lib/std/special/compiler_rt/multi3.zig+4-1| ... | ... | @@ -16,7 +16,10 @@ pub extern fn __multi3(a: i128, b: i128) i128 { |
| 16 | 16 | |
| 17 | 17 | const v128 = @Vector(2, u64); |
| 18 | 18 | pub extern fn __multi3_windows_x86_64(a: v128, b: v128) v128 { |
| 19 | return @bitCast(v128, @inlineCall(__multi3, @bitCast(i128, a), @bitCast(i128, b))); | |
| 19 | return @bitCast(v128, @call(.{ .modifier = .always_inline }, __multi3, .{ | |
| 20 | @bitCast(i128, a), | |
| 21 | @bitCast(i128, b), | |
| 22 | })); | |
| 20 | 23 | } |
| 21 | 24 | |
| 22 | 25 | fn __mulddi3(a: u64, b: u64) i128 { |
lib/std/special/compiler_rt/stack_probe.zig+6-6| ... | ... | @@ -182,25 +182,25 @@ fn win_probe_stack_adjust_sp() void { |
| 182 | 182 | |
| 183 | 183 | pub nakedcc fn _chkstk() void { |
| 184 | 184 | @setRuntimeSafety(false); |
| 185 | @inlineCall(win_probe_stack_adjust_sp); | |
| 185 | @call(.{ .modifier = .always_inline }, win_probe_stack_adjust_sp, .{}); | |
| 186 | 186 | } |
| 187 | 187 | pub nakedcc fn __chkstk() void { |
| 188 | 188 | @setRuntimeSafety(false); |
| 189 | 189 | switch (builtin.arch) { |
| 190 | .i386 => @inlineCall(win_probe_stack_adjust_sp), | |
| 191 | .x86_64 => @inlineCall(win_probe_stack_only), | |
| 190 | .i386 => @call(.{ .modifier = .always_inline }, win_probe_stack_adjust_sp, .{}), | |
| 191 | .x86_64 => @call(.{ .modifier = .always_inline }, win_probe_stack_only, .{}), | |
| 192 | 192 | else => unreachable, |
| 193 | 193 | } |
| 194 | 194 | } |
| 195 | 195 | pub nakedcc fn ___chkstk() void { |
| 196 | 196 | @setRuntimeSafety(false); |
| 197 | @inlineCall(win_probe_stack_adjust_sp); | |
| 197 | @call(.{ .modifier = .always_inline }, win_probe_stack_adjust_sp, .{}); | |
| 198 | 198 | } |
| 199 | 199 | pub nakedcc fn __chkstk_ms() void { |
| 200 | 200 | @setRuntimeSafety(false); |
| 201 | @inlineCall(win_probe_stack_only); | |
| 201 | @call(.{ .modifier = .always_inline }, win_probe_stack_only, .{}); | |
| 202 | 202 | } |
| 203 | 203 | pub nakedcc fn ___chkstk_ms() void { |
| 204 | 204 | @setRuntimeSafety(false); |
| 205 | @inlineCall(win_probe_stack_only); | |
| 205 | @call(.{ .modifier = .always_inline }, win_probe_stack_only, .{}); | |
| 206 | 206 | } |
lib/std/special/compiler_rt/umodti3.zig+4-1| ... | ... | @@ -11,5 +11,8 @@ pub extern fn __umodti3(a: u128, b: u128) u128 { |
| 11 | 11 | |
| 12 | 12 | const v128 = @Vector(2, u64); |
| 13 | 13 | pub extern fn __umodti3_windows_x86_64(a: v128, b: v128) v128 { |
| 14 | return @bitCast(v128, @inlineCall(__umodti3, @bitCast(u128, a), @bitCast(u128, b))); | |
| 14 | return @bitCast(v128, @call(.{ .modifier = .always_inline }, __umodti3, .{ | |
| 15 | @bitCast(u128, a), | |
| 16 | @bitCast(u128, b), | |
| 17 | })); | |
| 15 | 18 | } |
lib/std/special/start.zig+7-7| ... | ... | @@ -61,7 +61,7 @@ stdcallcc fn _DllMainCRTStartup( |
| 61 | 61 | extern fn wasm_freestanding_start() void { |
| 62 | 62 | // This is marked inline because for some reason LLVM in release mode fails to inline it, |
| 63 | 63 | // and we want fewer call frames in stack traces. |
| 64 | _ = @inlineCall(callMain); | |
| 64 | _ = @call(.{ .modifier = .always_inline }, callMain, .{}); | |
| 65 | 65 | } |
| 66 | 66 | |
| 67 | 67 | extern fn EfiMain(handle: uefi.Handle, system_table: *uefi.tables.SystemTable) usize { |
| ... | ... | @@ -91,7 +91,7 @@ nakedcc fn _start() noreturn { |
| 91 | 91 | if (builtin.os == builtin.Os.wasi) { |
| 92 | 92 | // This is marked inline because for some reason LLVM in release mode fails to inline it, |
| 93 | 93 | // and we want fewer call frames in stack traces. |
| 94 | std.os.wasi.proc_exit(@inlineCall(callMain)); | |
| 94 | std.os.wasi.proc_exit(@call(.{ .modifier = .always_inline }, callMain, .{})); | |
| 95 | 95 | } |
| 96 | 96 | |
| 97 | 97 | switch (builtin.arch) { |
| ... | ... | @@ -127,7 +127,7 @@ nakedcc fn _start() noreturn { |
| 127 | 127 | } |
| 128 | 128 | // If LLVM inlines stack variables into _start, they will overwrite |
| 129 | 129 | // the command line argument data. |
| 130 | @noInlineCall(posixCallMainAndExit); | |
| 130 | @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{}); | |
| 131 | 131 | } |
| 132 | 132 | |
| 133 | 133 | stdcallcc fn WinMainCRTStartup() noreturn { |
| ... | ... | @@ -186,10 +186,10 @@ fn posixCallMainAndExit() noreturn { |
| 186 | 186 | // 0, |
| 187 | 187 | //) catch @panic("out of memory"); |
| 188 | 188 | //std.os.mprotect(new_stack[0..std.mem.page_size], std.os.PROT_NONE) catch {}; |
| 189 | //std.os.exit(@newStackCall(new_stack, callMainWithArgs, argc, argv, envp)); | |
| 189 | //std.os.exit(@call(.{.stack = new_stack}, callMainWithArgs, .{argc, argv, envp})); | |
| 190 | 190 | } |
| 191 | 191 | |
| 192 | std.os.exit(@inlineCall(callMainWithArgs, argc, argv, envp)); | |
| 192 | std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp })); | |
| 193 | 193 | } |
| 194 | 194 | |
| 195 | 195 | fn callMainWithArgs(argc: usize, argv: [*][*:0]u8, envp: [][*:0]u8) u8 { |
| ... | ... | @@ -205,7 +205,7 @@ extern fn main(c_argc: i32, c_argv: [*][*:0]u8, c_envp: [*:null]?[*:0]u8) i32 { |
| 205 | 205 | var env_count: usize = 0; |
| 206 | 206 | while (c_envp[env_count] != null) : (env_count += 1) {} |
| 207 | 207 | const envp = @ptrCast([*][*:0]u8, c_envp)[0..env_count]; |
| 208 | return @inlineCall(callMainWithArgs, @intCast(usize, c_argc), c_argv, envp); | |
| 208 | return @call(.{ .modifier = .always_inline }, callMainWithArgs, .{ @intCast(usize, c_argc), c_argv, envp }); | |
| 209 | 209 | } |
| 210 | 210 | |
| 211 | 211 | // General error message for a malformed return type |
| ... | ... | @@ -235,7 +235,7 @@ inline fn initEventLoopAndCallMain() u8 { |
| 235 | 235 | |
| 236 | 236 | // This is marked inline because for some reason LLVM in release mode fails to inline it, |
| 237 | 237 | // and we want fewer call frames in stack traces. |
| 238 | return @inlineCall(callMain); | |
| 238 | return @call(.{ .modifier = .always_inline }, callMain, .{}); | |
| 239 | 239 | } |
| 240 | 240 | |
| 241 | 241 | async fn callMainAsync(loop: *std.event.Loop) u8 { |
src-self-hosted/ir.zig+2-2| ... | ... | @@ -321,7 +321,7 @@ pub const Inst = struct { |
| 321 | 321 | } |
| 322 | 322 | |
| 323 | 323 | const llvm_cc = llvm.CCallConv; |
| 324 | const fn_inline = llvm.FnInline.Auto; | |
| 324 | const call_attr = llvm.CallAttr.Auto; | |
| 325 | 325 | |
| 326 | 326 | return llvm.BuildCall( |
| 327 | 327 | ofile.builder, |
| ... | ... | @@ -329,7 +329,7 @@ pub const Inst = struct { |
| 329 | 329 | args.ptr, |
| 330 | 330 | @intCast(c_uint, args.len), |
| 331 | 331 | llvm_cc, |
| 332 | fn_inline, | |
| 332 | call_attr, | |
| 333 | 333 | "", |
| 334 | 334 | ) orelse error.OutOfMemory; |
| 335 | 335 | } |
src-self-hosted/llvm.zig+6-4| ... | ... | @@ -260,10 +260,12 @@ pub const X86StdcallCallConv = c.LLVMX86StdcallCallConv; |
| 260 | 260 | pub const X86FastcallCallConv = c.LLVMX86FastcallCallConv; |
| 261 | 261 | pub const CallConv = c.LLVMCallConv; |
| 262 | 262 | |
| 263 | pub const FnInline = extern enum { | |
| 263 | pub const CallAttr = extern enum { | |
| 264 | 264 | Auto, |
| 265 | Always, | |
| 266 | Never, | |
| 265 | NeverTail, | |
| 266 | NeverInline, | |
| 267 | AlwaysTail, | |
| 268 | AlwaysInline, | |
| 267 | 269 | }; |
| 268 | 270 | |
| 269 | 271 | fn removeNullability(comptime T: type) type { |
| ... | ... | @@ -286,6 +288,6 @@ extern fn ZigLLVMTargetMachineEmitToFile( |
| 286 | 288 | ) bool; |
| 287 | 289 | |
| 288 | 290 | pub const BuildCall = ZigLLVMBuildCall; |
| 289 | extern fn ZigLLVMBuildCall(B: *Builder, Fn: *Value, Args: [*]*Value, NumArgs: c_uint, CC: c_uint, fn_inline: FnInline, Name: [*:0]const u8) ?*Value; | |
| 291 | extern fn ZigLLVMBuildCall(B: *Builder, Fn: *Value, Args: [*]*Value, NumArgs: c_uint, CC: c_uint, fn_inline: CallAttr, Name: [*:0]const u8) ?*Value; | |
| 290 | 292 | |
| 291 | 293 | pub const PrivateLinkage = c.LLVMLinkage.LLVMPrivateLinkage; |
src/all_types.hpp+40-8| ... | ... | @@ -409,6 +409,9 @@ struct ZigValue { |
| 409 | 409 | LLVMValueRef llvm_global; |
| 410 | 410 | |
| 411 | 411 | union { |
| 412 | // populated if special == ConstValSpecialLazy | |
| 413 | LazyValue *x_lazy; | |
| 414 | ||
| 412 | 415 | // populated if special == ConstValSpecialStatic |
| 413 | 416 | BigInt x_bigint; |
| 414 | 417 | BigFloat x_bigfloat; |
| ... | ... | @@ -429,7 +432,6 @@ struct ZigValue { |
| 429 | 432 | ConstPtrValue x_ptr; |
| 430 | 433 | ConstArgTuple x_arg_tuple; |
| 431 | 434 | Buf *x_enum_literal; |
| 432 | LazyValue *x_lazy; | |
| 433 | 435 | |
| 434 | 436 | // populated if special == ConstValSpecialRuntime |
| 435 | 437 | RuntimeHintErrorUnion rh_error_union; |
| ... | ... | @@ -767,11 +769,19 @@ struct AstNodeUnwrapOptional { |
| 767 | 769 | AstNode *expr; |
| 768 | 770 | }; |
| 769 | 771 | |
| 772 | // Must be synchronized with std.builtin.CallOptions.Modifier | |
| 770 | 773 | enum CallModifier { |
| 771 | 774 | CallModifierNone, |
| 772 | CallModifierAsync, | |
| 775 | CallModifierNeverTail, | |
| 776 | CallModifierNeverInline, | |
| 773 | 777 | CallModifierNoAsync, |
| 778 | CallModifierAlwaysTail, | |
| 779 | CallModifierAlwaysInline, | |
| 780 | CallModifierCompileTime, | |
| 781 | ||
| 782 | // These are additional tags in the compiler, but not exposed in the std lib. | |
| 774 | 783 | CallModifierBuiltin, |
| 784 | CallModifierAsync, | |
| 775 | 785 | }; |
| 776 | 786 | |
| 777 | 787 | struct AstNodeFnCallExpr { |
| ... | ... | @@ -1692,8 +1702,6 @@ enum BuiltinFnId { |
| 1692 | 1702 | BuiltinFnIdFieldParentPtr, |
| 1693 | 1703 | BuiltinFnIdByteOffsetOf, |
| 1694 | 1704 | BuiltinFnIdBitOffsetOf, |
| 1695 | BuiltinFnIdInlineCall, | |
| 1696 | BuiltinFnIdNoInlineCall, | |
| 1697 | 1705 | BuiltinFnIdNewStackCall, |
| 1698 | 1706 | BuiltinFnIdAsyncCall, |
| 1699 | 1707 | BuiltinFnIdTypeId, |
| ... | ... | @@ -1717,6 +1725,7 @@ enum BuiltinFnId { |
| 1717 | 1725 | BuiltinFnIdFrameHandle, |
| 1718 | 1726 | BuiltinFnIdFrameSize, |
| 1719 | 1727 | BuiltinFnIdAs, |
| 1728 | BuiltinFnIdCall, | |
| 1720 | 1729 | }; |
| 1721 | 1730 | |
| 1722 | 1731 | struct BuiltinFnEntry { |
| ... | ... | @@ -2479,6 +2488,8 @@ enum IrInstructionId { |
| 2479 | 2488 | IrInstructionIdVarPtr, |
| 2480 | 2489 | IrInstructionIdReturnPtr, |
| 2481 | 2490 | IrInstructionIdCallSrc, |
| 2491 | IrInstructionIdCallSrcArgs, | |
| 2492 | IrInstructionIdCallExtra, | |
| 2482 | 2493 | IrInstructionIdCallGen, |
| 2483 | 2494 | IrInstructionIdConst, |
| 2484 | 2495 | IrInstructionIdReturn, |
| ... | ... | @@ -2886,15 +2897,37 @@ struct IrInstructionCallSrc { |
| 2886 | 2897 | ZigFn *fn_entry; |
| 2887 | 2898 | size_t arg_count; |
| 2888 | 2899 | IrInstruction **args; |
| 2900 | IrInstruction *ret_ptr; | |
| 2889 | 2901 | ResultLoc *result_loc; |
| 2890 | 2902 | |
| 2891 | 2903 | IrInstruction *new_stack; |
| 2892 | 2904 | |
| 2893 | FnInline fn_inline; | |
| 2894 | 2905 | CallModifier modifier; |
| 2895 | ||
| 2896 | 2906 | bool is_async_call_builtin; |
| 2897 | bool is_comptime; | |
| 2907 | }; | |
| 2908 | ||
| 2909 | // This is a pass1 instruction, used by @call when the args node is | |
| 2910 | // a tuple or struct literal. | |
| 2911 | struct IrInstructionCallSrcArgs { | |
| 2912 | IrInstruction base; | |
| 2913 | ||
| 2914 | IrInstruction *options; | |
| 2915 | IrInstruction *fn_ref; | |
| 2916 | IrInstruction **args_ptr; | |
| 2917 | size_t args_len; | |
| 2918 | ResultLoc *result_loc; | |
| 2919 | }; | |
| 2920 | ||
| 2921 | // This is a pass1 instruction, used by @call, when the args node | |
| 2922 | // is not a literal. | |
| 2923 | // `args` is expected to be either a struct or a tuple. | |
| 2924 | struct IrInstructionCallExtra { | |
| 2925 | IrInstruction base; | |
| 2926 | ||
| 2927 | IrInstruction *options; | |
| 2928 | IrInstruction *fn_ref; | |
| 2929 | IrInstruction *args; | |
| 2930 | ResultLoc *result_loc; | |
| 2898 | 2931 | }; |
| 2899 | 2932 | |
| 2900 | 2933 | struct IrInstructionCallGen { |
| ... | ... | @@ -2908,7 +2941,6 @@ struct IrInstructionCallGen { |
| 2908 | 2941 | IrInstruction *frame_result_loc; |
| 2909 | 2942 | IrInstruction *new_stack; |
| 2910 | 2943 | |
| 2911 | FnInline fn_inline; | |
| 2912 | 2944 | CallModifier modifier; |
| 2913 | 2945 | |
| 2914 | 2946 | bool is_async_call_builtin; |
src/analyze.cpp+15-9| ... | ... | @@ -594,8 +594,11 @@ ZigType *get_pointer_to_type_extra2(CodeGen *g, ZigType *child_type, bool is_con |
| 594 | 594 | break; |
| 595 | 595 | } |
| 596 | 596 | |
| 597 | ||
| 598 | if (type_is_resolved(child_type, ResolveStatusZeroBitsKnown)) { | |
| 597 | if (inferred_struct_field != nullptr) { | |
| 598 | entry->abi_size = g->builtin_types.entry_usize->abi_size; | |
| 599 | entry->size_in_bits = g->builtin_types.entry_usize->size_in_bits; | |
| 600 | entry->abi_align = g->builtin_types.entry_usize->abi_align; | |
| 601 | } else if (type_is_resolved(child_type, ResolveStatusZeroBitsKnown)) { | |
| 599 | 602 | if (type_has_bits(child_type)) { |
| 600 | 603 | entry->abi_size = g->builtin_types.entry_usize->abi_size; |
| 601 | 604 | entry->size_in_bits = g->builtin_types.entry_usize->size_in_bits; |
| ... | ... | @@ -956,10 +959,7 @@ bool calling_convention_allows_zig_types(CallingConvention cc) { |
| 956 | 959 | |
| 957 | 960 | ZigType *get_stack_trace_type(CodeGen *g) { |
| 958 | 961 | if (g->stack_trace_type == nullptr) { |
| 959 | ZigValue *stack_trace_type_val = get_builtin_value(g, "StackTrace"); | |
| 960 | assert(stack_trace_type_val->type->id == ZigTypeIdMetaType); | |
| 961 | ||
| 962 | g->stack_trace_type = stack_trace_type_val->data.x_type; | |
| 962 | g->stack_trace_type = get_builtin_type(g, "StackTrace"); | |
| 963 | 963 | assertNoError(type_resolve(g, g->stack_trace_type, ResolveStatusZeroBitsKnown)); |
| 964 | 964 | } |
| 965 | 965 | return g->stack_trace_type; |
| ... | ... | @@ -2717,10 +2717,10 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) { |
| 2717 | 2717 | src_assert(struct_type->data.structure.fields == nullptr, decl_node); |
| 2718 | 2718 | struct_type->data.structure.fields = alloc_type_struct_fields(field_count); |
| 2719 | 2719 | } else if (decl_node->type == NodeTypeContainerInitExpr) { |
| 2720 | src_assert(struct_type->data.structure.is_inferred, decl_node); | |
| 2721 | src_assert(struct_type->data.structure.fields != nullptr, decl_node); | |
| 2722 | ||
| 2723 | 2720 | field_count = struct_type->data.structure.src_field_count; |
| 2721 | ||
| 2722 | src_assert(struct_type->data.structure.is_inferred, decl_node); | |
| 2723 | src_assert(field_count == 0 || struct_type->data.structure.fields != nullptr, decl_node); | |
| 2724 | 2724 | } else zig_unreachable(); |
| 2725 | 2725 | |
| 2726 | 2726 | struct_type->data.structure.fields_by_name.init(field_count); |
| ... | ... | @@ -7531,6 +7531,12 @@ ZigValue *get_builtin_value(CodeGen *codegen, const char *name) { |
| 7531 | 7531 | return var_value; |
| 7532 | 7532 | } |
| 7533 | 7533 | |
| 7534 | ZigType *get_builtin_type(CodeGen *codegen, const char *name) { | |
| 7535 | ZigValue *type_val = get_builtin_value(codegen, name); | |
| 7536 | assert(type_val->type->id == ZigTypeIdMetaType); | |
| 7537 | return type_val->data.x_type; | |
| 7538 | } | |
| 7539 | ||
| 7534 | 7540 | bool type_is_global_error_set(ZigType *err_set_type) { |
| 7535 | 7541 | assert(err_set_type->id == ZigTypeIdErrorSet); |
| 7536 | 7542 | assert(!err_set_type->data.error_set.incomplete); |
src/analyze.hpp+1| ... | ... | @@ -207,6 +207,7 @@ void add_var_export(CodeGen *g, ZigVar *fn_table_entry, const char *symbol_name, |
| 207 | 207 | |
| 208 | 208 | |
| 209 | 209 | ZigValue *get_builtin_value(CodeGen *codegen, const char *name); |
| 210 | ZigType *get_builtin_type(CodeGen *codegen, const char *name); | |
| 210 | 211 | ZigType *get_stack_trace_type(CodeGen *g); |
| 211 | 212 | bool resolve_inferred_error_set(CodeGen *g, ZigType *err_set_type, AstNode *source_node); |
| 212 | 213 |
src/ast_render.cpp+19-4| ... | ... | @@ -702,14 +702,29 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) { |
| 702 | 702 | switch (node->data.fn_call_expr.modifier) { |
| 703 | 703 | case CallModifierNone: |
| 704 | 704 | break; |
| 705 | case CallModifierBuiltin: | |
| 706 | fprintf(ar->f, "@"); | |
| 705 | case CallModifierNoAsync: | |
| 706 | fprintf(ar->f, "noasync "); | |
| 707 | 707 | break; |
| 708 | 708 | case CallModifierAsync: |
| 709 | 709 | fprintf(ar->f, "async "); |
| 710 | 710 | break; |
| 711 | case CallModifierNoAsync: | |
| 712 | fprintf(ar->f, "noasync "); | |
| 711 | case CallModifierNeverTail: | |
| 712 | fprintf(ar->f, "notail "); | |
| 713 | break; | |
| 714 | case CallModifierNeverInline: | |
| 715 | fprintf(ar->f, "noinline "); | |
| 716 | break; | |
| 717 | case CallModifierAlwaysTail: | |
| 718 | fprintf(ar->f, "tail "); | |
| 719 | break; | |
| 720 | case CallModifierAlwaysInline: | |
| 721 | fprintf(ar->f, "inline "); | |
| 722 | break; | |
| 723 | case CallModifierCompileTime: | |
| 724 | fprintf(ar->f, "comptime "); | |
| 725 | break; | |
| 726 | case CallModifierBuiltin: | |
| 727 | fprintf(ar->f, "@"); | |
| 713 | 728 | break; |
| 714 | 729 | } |
| 715 | 730 | AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr; |
src/codegen.cpp+48-25| ... | ... | @@ -981,7 +981,7 @@ static void gen_panic(CodeGen *g, LLVMValueRef msg_arg, LLVMValueRef stack_trace |
| 981 | 981 | msg_arg, |
| 982 | 982 | stack_trace_arg, |
| 983 | 983 | }; |
| 984 | ZigLLVMBuildCall(g->builder, fn_val, args, 2, llvm_cc, ZigLLVM_FnInlineAuto, ""); | |
| 984 | ZigLLVMBuildCall(g->builder, fn_val, args, 2, llvm_cc, ZigLLVM_CallAttrAuto, ""); | |
| 985 | 985 | if (!stack_trace_is_llvm_alloca) { |
| 986 | 986 | // The stack trace argument is not in the stack of the caller, so |
| 987 | 987 | // we'd like to set tail call here, but because slices (the type of msg_arg) are |
| ... | ... | @@ -1201,7 +1201,8 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) { |
| 1201 | 1201 | |
| 1202 | 1202 | LLVMPositionBuilderAtEnd(g->builder, dest_non_null_block); |
| 1203 | 1203 | LLVMValueRef args[] = { err_ret_trace_ptr, return_address }; |
| 1204 | ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, ""); | |
| 1204 | ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, | |
| 1205 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAlwaysInline, ""); | |
| 1205 | 1206 | LLVMBuildRetVoid(g->builder); |
| 1206 | 1207 | |
| 1207 | 1208 | LLVMPositionBuilderAtEnd(g->builder, prev_block); |
| ... | ... | @@ -1370,13 +1371,13 @@ static void gen_safety_crash_for_err(CodeGen *g, LLVMValueRef err_val, Scope *sc |
| 1370 | 1371 | err_val, |
| 1371 | 1372 | }; |
| 1372 | 1373 | call_instruction = ZigLLVMBuildCall(g->builder, safety_crash_err_fn, args, 2, |
| 1373 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); | |
| 1374 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAuto, ""); | |
| 1374 | 1375 | } else { |
| 1375 | 1376 | LLVMValueRef args[] = { |
| 1376 | 1377 | err_val, |
| 1377 | 1378 | }; |
| 1378 | 1379 | call_instruction = ZigLLVMBuildCall(g->builder, safety_crash_err_fn, args, 1, |
| 1379 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); | |
| 1380 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAuto, ""); | |
| 1380 | 1381 | } |
| 1381 | 1382 | if (!is_llvm_alloca) { |
| 1382 | 1383 | LLVMSetTailCall(call_instruction, true); |
| ... | ... | @@ -2216,7 +2217,7 @@ static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) { |
| 2216 | 2217 | LLVMValueRef addr_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr_val, &ptr_index, 1, ""); |
| 2217 | 2218 | LLVMValueRef this_addr_val = LLVMBuildLoad(g->builder, addr_ptr, ""); |
| 2218 | 2219 | LLVMValueRef args[] = {dest_stack_trace_ptr, this_addr_val}; |
| 2219 | ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, ""); | |
| 2220 | ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAlwaysInline, ""); | |
| 2220 | 2221 | LLVMValueRef prev_frames_left = LLVMBuildLoad(g->builder, frames_left_ptr, ""); |
| 2221 | 2222 | LLVMValueRef new_frames_left = LLVMBuildNUWSub(g->builder, prev_frames_left, usize_one, ""); |
| 2222 | 2223 | LLVMValueRef done_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, new_frames_left, usize_zero, ""); |
| ... | ... | @@ -2253,7 +2254,7 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut |
| 2253 | 2254 | LLVMValueRef my_err_trace_val = get_cur_err_ret_trace_val(g, save_err_ret_addr_instruction->base.scope, |
| 2254 | 2255 | &is_llvm_alloca); |
| 2255 | 2256 | ZigLLVMBuildCall(g->builder, return_err_fn, &my_err_trace_val, 1, |
| 2256 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); | |
| 2257 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAuto, ""); | |
| 2257 | 2258 | |
| 2258 | 2259 | ZigType *ret_type = g->cur_fn->type_entry->data.fn.fn_type_id.return_type; |
| 2259 | 2260 | if (fn_is_async(g->cur_fn) && codegen_fn_has_err_ret_tracing_arg(g, ret_type)) { |
| ... | ... | @@ -2297,7 +2298,7 @@ static LLVMValueRef gen_resume(CodeGen *g, LLVMValueRef fn_val, LLVMValueRef tar |
| 2297 | 2298 | LLVMValueRef arg_val = LLVMConstSub(LLVMConstAllOnes(usize_type_ref), |
| 2298 | 2299 | LLVMConstInt(usize_type_ref, resume_id, false)); |
| 2299 | 2300 | LLVMValueRef args[] = {target_frame_ptr, arg_val}; |
| 2300 | return ZigLLVMBuildCall(g->builder, fn_val, args, 2, LLVMFastCallConv, ZigLLVM_FnInlineAuto, ""); | |
| 2301 | return ZigLLVMBuildCall(g->builder, fn_val, args, 2, LLVMFastCallConv, ZigLLVM_CallAttrAuto, ""); | |
| 2301 | 2302 | } |
| 2302 | 2303 | |
| 2303 | 2304 | static LLVMBasicBlockRef gen_suspend_begin(CodeGen *g, const char *name_hint) { |
| ... | ... | @@ -2424,7 +2425,7 @@ static void gen_async_return(CodeGen *g, IrInstructionReturn *instruction) { |
| 2424 | 2425 | LLVMValueRef my_err_trace_val = get_cur_err_ret_trace_val(g, instruction->base.scope, &is_llvm_alloca); |
| 2425 | 2426 | LLVMValueRef args[] = { dest_trace_ptr, my_err_trace_val }; |
| 2426 | 2427 | ZigLLVMBuildCall(g->builder, get_merge_err_ret_traces_fn_val(g), args, 2, |
| 2427 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); | |
| 2428 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAuto, ""); | |
| 2428 | 2429 | } |
| 2429 | 2430 | } |
| 2430 | 2431 | |
| ... | ... | @@ -3061,7 +3062,7 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable, |
| 3061 | 3062 | ZigType *actual_type = cast_instruction->value->value->type; |
| 3062 | 3063 | ZigType *wanted_type = cast_instruction->base.value->type; |
| 3063 | 3064 | LLVMValueRef expr_val = ir_llvm_value(g, cast_instruction->value); |
| 3064 | assert(expr_val); | |
| 3065 | ir_assert(expr_val, &cast_instruction->base); | |
| 3065 | 3066 | |
| 3066 | 3067 | switch (cast_instruction->cast_op) { |
| 3067 | 3068 | case CastOpNoCast: |
| ... | ... | @@ -4142,16 +4143,28 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 4142 | 4143 | fn_walk.data.call.gen_param_types = &gen_param_types; |
| 4143 | 4144 | walk_function_params(g, fn_type, &fn_walk); |
| 4144 | 4145 | |
| 4145 | ZigLLVM_FnInline fn_inline; | |
| 4146 | switch (instruction->fn_inline) { | |
| 4147 | case FnInlineAuto: | |
| 4148 | fn_inline = ZigLLVM_FnInlineAuto; | |
| 4146 | ZigLLVM_CallAttr call_attr; | |
| 4147 | switch (instruction->modifier) { | |
| 4148 | case CallModifierBuiltin: | |
| 4149 | case CallModifierCompileTime: | |
| 4150 | zig_unreachable(); | |
| 4151 | case CallModifierNone: | |
| 4152 | case CallModifierNoAsync: | |
| 4153 | case CallModifierAsync: | |
| 4154 | call_attr = ZigLLVM_CallAttrAuto; | |
| 4149 | 4155 | break; |
| 4150 | case FnInlineAlways: | |
| 4151 | fn_inline = (instruction->fn_entry == nullptr) ? ZigLLVM_FnInlineAuto : ZigLLVM_FnInlineAlways; | |
| 4156 | case CallModifierNeverTail: | |
| 4157 | call_attr = ZigLLVM_CallAttrNeverTail; | |
| 4152 | 4158 | break; |
| 4153 | case FnInlineNever: | |
| 4154 | fn_inline = ZigLLVM_FnInlineNever; | |
| 4159 | case CallModifierNeverInline: | |
| 4160 | call_attr = ZigLLVM_CallAttrNeverInline; | |
| 4161 | break; | |
| 4162 | case CallModifierAlwaysTail: | |
| 4163 | call_attr = ZigLLVM_CallAttrAlwaysTail; | |
| 4164 | break; | |
| 4165 | case CallModifierAlwaysInline: | |
| 4166 | ir_assert(instruction->fn_entry != nullptr, &instruction->base); | |
| 4167 | call_attr = ZigLLVM_CallAttrAlwaysInline; | |
| 4155 | 4168 | break; |
| 4156 | 4169 | } |
| 4157 | 4170 | |
| ... | ... | @@ -4257,7 +4270,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 4257 | 4270 | |
| 4258 | 4271 | if (instruction->new_stack == nullptr || instruction->is_async_call_builtin) { |
| 4259 | 4272 | result = ZigLLVMBuildCall(g->builder, fn_val, |
| 4260 | gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, fn_inline, ""); | |
| 4273 | gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, call_attr, ""); | |
| 4261 | 4274 | } else if (instruction->modifier == CallModifierAsync) { |
| 4262 | 4275 | zig_panic("TODO @asyncCall of non-async function"); |
| 4263 | 4276 | } else { |
| ... | ... | @@ -4269,7 +4282,7 @@ static LLVMValueRef ir_render_call(CodeGen *g, IrExecutable *executable, IrInstr |
| 4269 | 4282 | } |
| 4270 | 4283 | gen_set_stack_pointer(g, new_stack_addr); |
| 4271 | 4284 | result = ZigLLVMBuildCall(g->builder, fn_val, |
| 4272 | gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, fn_inline, ""); | |
| 4285 | gen_param_values.items, (unsigned)gen_param_values.length, llvm_cc, call_attr, ""); | |
| 4273 | 4286 | if (src_return_type->id != ZigTypeIdUnreachable) { |
| 4274 | 4287 | LLVMValueRef stackrestore_fn_val = get_stackrestore_fn_val(g); |
| 4275 | 4288 | LLVMBuildCall(g->builder, stackrestore_fn_val, &old_stack_ref, 1, ""); |
| ... | ... | @@ -4317,8 +4330,17 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa |
| 4317 | 4330 | return struct_ptr; |
| 4318 | 4331 | } |
| 4319 | 4332 | |
| 4320 | ZigType *struct_type = (struct_ptr_type->id == ZigTypeIdPointer) ? | |
| 4321 | struct_ptr_type->data.pointer.child_type : struct_ptr_type; | |
| 4333 | ZigType *struct_type; | |
| 4334 | if (struct_ptr_type->id == ZigTypeIdPointer) { | |
| 4335 | if (struct_ptr_type->data.pointer.inferred_struct_field != nullptr) { | |
| 4336 | struct_type = struct_ptr_type->data.pointer.inferred_struct_field->inferred_struct_type; | |
| 4337 | } else { | |
| 4338 | struct_type = struct_ptr_type->data.pointer.child_type; | |
| 4339 | } | |
| 4340 | } else { | |
| 4341 | struct_type = struct_ptr_type; | |
| 4342 | } | |
| 4343 | ||
| 4322 | 4344 | if ((err = type_resolve(g, struct_type, ResolveStatusLLVMFull))) |
| 4323 | 4345 | codegen_report_errors_and_exit(g); |
| 4324 | 4346 | |
| ... | ... | @@ -4947,7 +4969,7 @@ static LLVMValueRef ir_render_enum_tag_name(CodeGen *g, IrExecutable *executable |
| 4947 | 4969 | |
| 4948 | 4970 | LLVMValueRef enum_tag_value = ir_llvm_value(g, instruction->target); |
| 4949 | 4971 | return ZigLLVMBuildCall(g->builder, enum_name_function, &enum_tag_value, 1, |
| 4950 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); | |
| 4972 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAuto, ""); | |
| 4951 | 4973 | } |
| 4952 | 4974 | |
| 4953 | 4975 | static LLVMValueRef ir_render_field_parent_ptr(CodeGen *g, IrExecutable *executable, |
| ... | ... | @@ -5903,7 +5925,7 @@ static LLVMValueRef gen_await_early_return(CodeGen *g, IrInstruction *source_ins |
| 5903 | 5925 | LLVMValueRef dest_trace_ptr = get_cur_err_ret_trace_val(g, source_instr->scope, &is_llvm_alloca); |
| 5904 | 5926 | LLVMValueRef args[] = { dest_trace_ptr, src_trace_ptr }; |
| 5905 | 5927 | ZigLLVMBuildCall(g->builder, get_merge_err_ret_traces_fn_val(g), args, 2, |
| 5906 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, ""); | |
| 5928 | get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_CallAttrAuto, ""); | |
| 5907 | 5929 | } |
| 5908 | 5930 | if (non_async && type_has_bits(result_type)) { |
| 5909 | 5931 | LLVMValueRef result_ptr = (result_loc == nullptr) ? their_result_ptr : result_loc; |
| ... | ... | @@ -6137,7 +6159,9 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, |
| 6137 | 6159 | case IrInstructionIdLoadPtr: |
| 6138 | 6160 | case IrInstructionIdHasDecl: |
| 6139 | 6161 | case IrInstructionIdUndeclaredIdent: |
| 6162 | case IrInstructionIdCallExtra: | |
| 6140 | 6163 | case IrInstructionIdCallSrc: |
| 6164 | case IrInstructionIdCallSrcArgs: | |
| 6141 | 6165 | case IrInstructionIdAllocaSrc: |
| 6142 | 6166 | case IrInstructionIdEndExpr: |
| 6143 | 6167 | case IrInstructionIdImplicitCast: |
| ... | ... | @@ -8118,8 +8142,6 @@ static void define_builtin_fns(CodeGen *g) { |
| 8118 | 8142 | create_builtin_fn(g, BuiltinFnIdNearbyInt, "nearbyInt", 2); |
| 8119 | 8143 | create_builtin_fn(g, BuiltinFnIdRound, "round", 2); |
| 8120 | 8144 | create_builtin_fn(g, BuiltinFnIdMulAdd, "mulAdd", 4); |
| 8121 | create_builtin_fn(g, BuiltinFnIdInlineCall, "inlineCall", SIZE_MAX); | |
| 8122 | create_builtin_fn(g, BuiltinFnIdNoInlineCall, "noInlineCall", SIZE_MAX); | |
| 8123 | 8145 | create_builtin_fn(g, BuiltinFnIdNewStackCall, "newStackCall", SIZE_MAX); |
| 8124 | 8146 | create_builtin_fn(g, BuiltinFnIdAsyncCall, "asyncCall", SIZE_MAX); |
| 8125 | 8147 | create_builtin_fn(g, BuiltinFnIdTypeId, "typeId", 1); |
| ... | ... | @@ -8146,6 +8168,7 @@ static void define_builtin_fns(CodeGen *g) { |
| 8146 | 8168 | create_builtin_fn(g, BuiltinFnIdFrameAddress, "frameAddress", 0); |
| 8147 | 8169 | create_builtin_fn(g, BuiltinFnIdFrameSize, "frameSize", 1); |
| 8148 | 8170 | create_builtin_fn(g, BuiltinFnIdAs, "as", 2); |
| 8171 | create_builtin_fn(g, BuiltinFnIdCall, "call", 3); | |
| 8149 | 8172 | } |
| 8150 | 8173 | |
| 8151 | 8174 | static const char *bool_to_str(bool b) { |
src/ir.cpp+462-203| ... | ... | @@ -265,6 +265,7 @@ static IrInstruction *ir_analyze_struct_field_ptr(IrAnalyze *ira, IrInstruction |
| 265 | 265 | static IrInstruction *ir_analyze_inferred_field_ptr(IrAnalyze *ira, Buf *field_name, |
| 266 | 266 | IrInstruction *source_instr, IrInstruction *container_ptr, ZigType *container_type); |
| 267 | 267 | static ResultLoc *no_result_loc(void); |
| 268 | static IrInstruction *ir_analyze_test_non_null(IrAnalyze *ira, IrInstruction *source_inst, IrInstruction *value); | |
| 268 | 269 | |
| 269 | 270 | static void destroy_instruction(IrInstruction *inst) { |
| 270 | 271 | #ifdef ZIG_ENABLE_MEM_PROFILE |
| ... | ... | @@ -289,6 +290,10 @@ static void destroy_instruction(IrInstruction *inst) { |
| 289 | 290 | return destroy(reinterpret_cast<IrInstructionCast *>(inst), name); |
| 290 | 291 | case IrInstructionIdCallSrc: |
| 291 | 292 | return destroy(reinterpret_cast<IrInstructionCallSrc *>(inst), name); |
| 293 | case IrInstructionIdCallSrcArgs: | |
| 294 | return destroy(reinterpret_cast<IrInstructionCallSrcArgs *>(inst), name); | |
| 295 | case IrInstructionIdCallExtra: | |
| 296 | return destroy(reinterpret_cast<IrInstructionCallExtra *>(inst), name); | |
| 292 | 297 | case IrInstructionIdCallGen: |
| 293 | 298 | return destroy(reinterpret_cast<IrInstructionCallGen *>(inst), name); |
| 294 | 299 | case IrInstructionIdUnOp: |
| ... | ... | @@ -646,6 +651,15 @@ static ZigValue *const_ptr_pointee_unchecked(CodeGen *g, ZigValue *const_val) { |
| 646 | 651 | assert(const_val->special == ConstValSpecialStatic); |
| 647 | 652 | ZigValue *result; |
| 648 | 653 | |
| 654 | InferredStructField *isf = const_val->type->data.pointer.inferred_struct_field; | |
| 655 | if (isf != nullptr) { | |
| 656 | TypeStructField *field = find_struct_type_field(isf->inferred_struct_type, isf->field_name); | |
| 657 | assert(field != nullptr); | |
| 658 | assert(const_val->data.x_ptr.special == ConstPtrSpecialRef); | |
| 659 | ZigValue *struct_val = const_val->data.x_ptr.data.ref.pointee; | |
| 660 | return struct_val->data.x_struct.fields[field->src_index]; | |
| 661 | } | |
| 662 | ||
| 649 | 663 | switch (type_has_one_possible_value(g, const_val->type->data.pointer.child_type)) { |
| 650 | 664 | case OnePossibleValueInvalid: |
| 651 | 665 | zig_unreachable(); |
| ... | ... | @@ -705,6 +719,13 @@ static bool is_opt_err_set(ZigType *ty) { |
| 705 | 719 | (ty->id == ZigTypeIdOptional && ty->data.maybe.child_type->id == ZigTypeIdErrorSet); |
| 706 | 720 | } |
| 707 | 721 | |
| 722 | static bool is_tuple(ZigType *type) { | |
| 723 | return type->id == ZigTypeIdStruct && type->data.structure.decl_node != nullptr && | |
| 724 | type->data.structure.decl_node->type == NodeTypeContainerInitExpr && | |
| 725 | (type->data.structure.decl_node->data.container_init_expr.kind == ContainerInitKindArray || | |
| 726 | type->data.structure.decl_node->data.container_init_expr.entries.length == 0); | |
| 727 | } | |
| 728 | ||
| 708 | 729 | static bool is_slice(ZigType *type) { |
| 709 | 730 | return type->id == ZigTypeIdStruct && type->data.structure.is_slice; |
| 710 | 731 | } |
| ... | ... | @@ -968,6 +989,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionCallSrc *) { |
| 968 | 989 | return IrInstructionIdCallSrc; |
| 969 | 990 | } |
| 970 | 991 | |
| 992 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCallSrcArgs *) { | |
| 993 | return IrInstructionIdCallSrcArgs; | |
| 994 | } | |
| 995 | ||
| 996 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCallExtra *) { | |
| 997 | return IrInstructionIdCallExtra; | |
| 998 | } | |
| 999 | ||
| 971 | 1000 | static constexpr IrInstructionId ir_instruction_id(IrInstructionCallGen *) { |
| 972 | 1001 | return IrInstructionIdCallGen; |
| 973 | 1002 | } |
| ... | ... | @@ -1891,30 +1920,61 @@ static IrInstruction *ir_build_union_field_ptr(IrBuilder *irb, Scope *scope, Ast |
| 1891 | 1920 | return &instruction->base; |
| 1892 | 1921 | } |
| 1893 | 1922 | |
| 1923 | static IrInstruction *ir_build_call_extra(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 1924 | IrInstruction *options, IrInstruction *fn_ref, IrInstruction *args, ResultLoc *result_loc) | |
| 1925 | { | |
| 1926 | IrInstructionCallExtra *call_instruction = ir_build_instruction<IrInstructionCallExtra>(irb, scope, source_node); | |
| 1927 | call_instruction->options = options; | |
| 1928 | call_instruction->fn_ref = fn_ref; | |
| 1929 | call_instruction->args = args; | |
| 1930 | call_instruction->result_loc = result_loc; | |
| 1931 | ||
| 1932 | ir_ref_instruction(options, irb->current_basic_block); | |
| 1933 | ir_ref_instruction(fn_ref, irb->current_basic_block); | |
| 1934 | ir_ref_instruction(args, irb->current_basic_block); | |
| 1935 | ||
| 1936 | return &call_instruction->base; | |
| 1937 | } | |
| 1938 | ||
| 1939 | static IrInstruction *ir_build_call_src_args(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 1940 | IrInstruction *options, IrInstruction *fn_ref, IrInstruction **args_ptr, size_t args_len, | |
| 1941 | ResultLoc *result_loc) | |
| 1942 | { | |
| 1943 | IrInstructionCallSrcArgs *call_instruction = ir_build_instruction<IrInstructionCallSrcArgs>(irb, scope, source_node); | |
| 1944 | call_instruction->options = options; | |
| 1945 | call_instruction->fn_ref = fn_ref; | |
| 1946 | call_instruction->args_ptr = args_ptr; | |
| 1947 | call_instruction->args_len = args_len; | |
| 1948 | call_instruction->result_loc = result_loc; | |
| 1949 | ||
| 1950 | ir_ref_instruction(options, irb->current_basic_block); | |
| 1951 | ir_ref_instruction(fn_ref, irb->current_basic_block); | |
| 1952 | for (size_t i = 0; i < args_len; i += 1) | |
| 1953 | ir_ref_instruction(args_ptr[i], irb->current_basic_block); | |
| 1954 | ||
| 1955 | return &call_instruction->base; | |
| 1956 | } | |
| 1957 | ||
| 1894 | 1958 | static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *source_node, |
| 1895 | 1959 | ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, |
| 1896 | bool is_comptime, FnInline fn_inline, CallModifier modifier, bool is_async_call_builtin, | |
| 1960 | IrInstruction *ret_ptr, CallModifier modifier, bool is_async_call_builtin, | |
| 1897 | 1961 | IrInstruction *new_stack, ResultLoc *result_loc) |
| 1898 | 1962 | { |
| 1899 | 1963 | IrInstructionCallSrc *call_instruction = ir_build_instruction<IrInstructionCallSrc>(irb, scope, source_node); |
| 1900 | 1964 | call_instruction->fn_entry = fn_entry; |
| 1901 | 1965 | call_instruction->fn_ref = fn_ref; |
| 1902 | call_instruction->is_comptime = is_comptime; | |
| 1903 | call_instruction->fn_inline = fn_inline; | |
| 1904 | 1966 | call_instruction->args = args; |
| 1905 | 1967 | call_instruction->arg_count = arg_count; |
| 1906 | 1968 | call_instruction->modifier = modifier; |
| 1907 | 1969 | call_instruction->is_async_call_builtin = is_async_call_builtin; |
| 1908 | 1970 | call_instruction->new_stack = new_stack; |
| 1909 | 1971 | call_instruction->result_loc = result_loc; |
| 1972 | call_instruction->ret_ptr = ret_ptr; | |
| 1910 | 1973 | |
| 1911 | 1974 | if (fn_ref != nullptr) ir_ref_instruction(fn_ref, irb->current_basic_block); |
| 1912 | 1975 | for (size_t i = 0; i < arg_count; i += 1) |
| 1913 | 1976 | ir_ref_instruction(args[i], irb->current_basic_block); |
| 1914 | if (modifier == CallModifierAsync && new_stack != nullptr) { | |
| 1915 | // in this case the arg at the end is the return pointer | |
| 1916 | ir_ref_instruction(args[arg_count], irb->current_basic_block); | |
| 1917 | } | |
| 1977 | if (ret_ptr != nullptr) ir_ref_instruction(ret_ptr, irb->current_basic_block); | |
| 1918 | 1978 | if (new_stack != nullptr) ir_ref_instruction(new_stack, irb->current_basic_block); |
| 1919 | 1979 | |
| 1920 | 1980 | return &call_instruction->base; |
| ... | ... | @@ -1922,7 +1982,7 @@ static IrInstruction *ir_build_call_src(IrBuilder *irb, Scope *scope, AstNode *s |
| 1922 | 1982 | |
| 1923 | 1983 | static IrInstructionCallGen *ir_build_call_gen(IrAnalyze *ira, IrInstruction *source_instruction, |
| 1924 | 1984 | ZigFn *fn_entry, IrInstruction *fn_ref, size_t arg_count, IrInstruction **args, |
| 1925 | FnInline fn_inline, CallModifier modifier, IrInstruction *new_stack, bool is_async_call_builtin, | |
| 1985 | CallModifier modifier, IrInstruction *new_stack, bool is_async_call_builtin, | |
| 1926 | 1986 | IrInstruction *result_loc, ZigType *return_type) |
| 1927 | 1987 | { |
| 1928 | 1988 | IrInstructionCallGen *call_instruction = ir_build_instruction<IrInstructionCallGen>(&ira->new_irb, |
| ... | ... | @@ -1930,7 +1990,6 @@ static IrInstructionCallGen *ir_build_call_gen(IrAnalyze *ira, IrInstruction *so |
| 1930 | 1990 | call_instruction->base.value->type = return_type; |
| 1931 | 1991 | call_instruction->fn_entry = fn_entry; |
| 1932 | 1992 | call_instruction->fn_ref = fn_ref; |
| 1933 | call_instruction->fn_inline = fn_inline; | |
| 1934 | 1993 | call_instruction->args = args; |
| 1935 | 1994 | call_instruction->arg_count = arg_count; |
| 1936 | 1995 | call_instruction->modifier = modifier; |
| ... | ... | @@ -5054,10 +5113,7 @@ static IrInstruction *ir_gen_async_call(IrBuilder *irb, Scope *scope, AstNode *a |
| 5054 | 5113 | return fn_ref; |
| 5055 | 5114 | |
| 5056 | 5115 | size_t arg_count = call_node->data.fn_call_expr.params.length - arg_offset; |
| 5057 | ||
| 5058 | // last "arg" is return pointer | |
| 5059 | IrInstruction **args = allocate<IrInstruction*>(arg_count + 1); | |
| 5060 | ||
| 5116 | IrInstruction **args = allocate<IrInstruction*>(arg_count); | |
| 5061 | 5117 | for (size_t i = 0; i < arg_count; i += 1) { |
| 5062 | 5118 | AstNode *arg_node = call_node->data.fn_call_expr.params.at(i + arg_offset); |
| 5063 | 5119 | IrInstruction *arg = ir_gen_node(irb, arg_node, scope); |
| ... | ... | @@ -5066,15 +5122,50 @@ static IrInstruction *ir_gen_async_call(IrBuilder *irb, Scope *scope, AstNode *a |
| 5066 | 5122 | args[i] = arg; |
| 5067 | 5123 | } |
| 5068 | 5124 | |
| 5069 | args[arg_count] = ret_ptr; | |
| 5070 | ||
| 5071 | 5125 | CallModifier modifier = (await_node == nullptr) ? CallModifierAsync : CallModifierNone; |
| 5072 | 5126 | bool is_async_call_builtin = true; |
| 5073 | IrInstruction *call = ir_build_call_src(irb, scope, call_node, nullptr, fn_ref, arg_count, args, false, | |
| 5074 | FnInlineAuto, modifier, is_async_call_builtin, bytes, result_loc); | |
| 5127 | IrInstruction *call = ir_build_call_src(irb, scope, call_node, nullptr, fn_ref, arg_count, args, | |
| 5128 | ret_ptr, modifier, is_async_call_builtin, bytes, result_loc); | |
| 5075 | 5129 | return ir_lval_wrap(irb, scope, call, lval, result_loc); |
| 5076 | 5130 | } |
| 5077 | 5131 | |
| 5132 | static IrInstruction *ir_gen_fn_call_with_args(IrBuilder *irb, Scope *scope, AstNode *source_node, | |
| 5133 | AstNode *fn_ref_node, CallModifier modifier, IrInstruction *options, | |
| 5134 | AstNode **args_ptr, size_t args_len, LVal lval, ResultLoc *result_loc) | |
| 5135 | { | |
| 5136 | IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope); | |
| 5137 | if (fn_ref == irb->codegen->invalid_instruction) | |
| 5138 | return fn_ref; | |
| 5139 | ||
| 5140 | IrInstruction *fn_type = ir_build_typeof(irb, scope, source_node, fn_ref); | |
| 5141 | ||
| 5142 | IrInstruction **args = allocate<IrInstruction*>(args_len); | |
| 5143 | for (size_t i = 0; i < args_len; i += 1) { | |
| 5144 | AstNode *arg_node = args_ptr[i]; | |
| 5145 | ||
| 5146 | IrInstruction *arg_index = ir_build_const_usize(irb, scope, arg_node, i); | |
| 5147 | IrInstruction *arg_type = ir_build_arg_type(irb, scope, source_node, fn_type, arg_index, true); | |
| 5148 | ResultLoc *no_result = no_result_loc(); | |
| 5149 | ir_build_reset_result(irb, scope, source_node, no_result); | |
| 5150 | ResultLocCast *result_loc_cast = ir_build_cast_result_loc(irb, arg_type, no_result); | |
| 5151 | ||
| 5152 | IrInstruction *arg = ir_gen_node_extra(irb, arg_node, scope, LValNone, &result_loc_cast->base); | |
| 5153 | if (arg == irb->codegen->invalid_instruction) | |
| 5154 | return arg; | |
| 5155 | ||
| 5156 | args[i] = ir_build_implicit_cast(irb, scope, arg_node, arg, result_loc_cast); | |
| 5157 | } | |
| 5158 | ||
| 5159 | IrInstruction *fn_call; | |
| 5160 | if (options != nullptr) { | |
| 5161 | fn_call = ir_build_call_src_args(irb, scope, source_node, options, fn_ref, args, args_len, result_loc); | |
| 5162 | } else { | |
| 5163 | fn_call = ir_build_call_src(irb, scope, source_node, nullptr, fn_ref, args_len, args, nullptr, | |
| 5164 | modifier, false, nullptr, result_loc); | |
| 5165 | } | |
| 5166 | return ir_lval_wrap(irb, scope, fn_call, lval, result_loc); | |
| 5167 | } | |
| 5168 | ||
| 5078 | 5169 | static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, |
| 5079 | 5170 | ResultLoc *result_loc) |
| 5080 | 5171 | { |
| ... | ... | @@ -5993,34 +6084,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 5993 | 6084 | IrInstruction *offset_of = ir_build_bit_offset_of(irb, scope, node, arg0_value, arg1_value); |
| 5994 | 6085 | return ir_lval_wrap(irb, scope, offset_of, lval, result_loc); |
| 5995 | 6086 | } |
| 5996 | case BuiltinFnIdInlineCall: | |
| 5997 | case BuiltinFnIdNoInlineCall: | |
| 5998 | { | |
| 5999 | if (node->data.fn_call_expr.params.length == 0) { | |
| 6000 | add_node_error(irb->codegen, node, buf_sprintf("expected at least 1 argument, found 0")); | |
| 6001 | return irb->codegen->invalid_instruction; | |
| 6002 | } | |
| 6003 | ||
| 6004 | AstNode *fn_ref_node = node->data.fn_call_expr.params.at(0); | |
| 6005 | IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope); | |
| 6006 | if (fn_ref == irb->codegen->invalid_instruction) | |
| 6007 | return fn_ref; | |
| 6008 | ||
| 6009 | size_t arg_count = node->data.fn_call_expr.params.length - 1; | |
| 6010 | ||
| 6011 | IrInstruction **args = allocate<IrInstruction*>(arg_count); | |
| 6012 | for (size_t i = 0; i < arg_count; i += 1) { | |
| 6013 | AstNode *arg_node = node->data.fn_call_expr.params.at(i + 1); | |
| 6014 | args[i] = ir_gen_node(irb, arg_node, scope); | |
| 6015 | if (args[i] == irb->codegen->invalid_instruction) | |
| 6016 | return args[i]; | |
| 6017 | } | |
| 6018 | FnInline fn_inline = (builtin_fn->id == BuiltinFnIdInlineCall) ? FnInlineAlways : FnInlineNever; | |
| 6019 | ||
| 6020 | IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false, | |
| 6021 | fn_inline, CallModifierNone, false, nullptr, result_loc); | |
| 6022 | return ir_lval_wrap(irb, scope, call, lval, result_loc); | |
| 6023 | } | |
| 6024 | 6087 | case BuiltinFnIdNewStackCall: |
| 6025 | 6088 | { |
| 6026 | 6089 | if (node->data.fn_call_expr.params.length < 2) { |
| ... | ... | @@ -6050,10 +6113,52 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo |
| 6050 | 6113 | return args[i]; |
| 6051 | 6114 | } |
| 6052 | 6115 | |
| 6053 | IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false, | |
| 6054 | FnInlineAuto, CallModifierNone, false, new_stack, result_loc); | |
| 6116 | IrInstruction *call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, | |
| 6117 | nullptr, CallModifierNone, false, new_stack, result_loc); | |
| 6118 | return ir_lval_wrap(irb, scope, call, lval, result_loc); | |
| 6119 | } | |
| 6120 | case BuiltinFnIdCall: { | |
| 6121 | // Cast the options parameter to the options type | |
| 6122 | ZigType *options_type = get_builtin_type(irb->codegen, "CallOptions"); | |
| 6123 | IrInstruction *options_type_inst = ir_build_const_type(irb, scope, node, options_type); | |
| 6124 | ResultLocCast *result_loc_cast = ir_build_cast_result_loc(irb, options_type_inst, no_result_loc()); | |
| 6125 | ||
| 6126 | AstNode *options_node = node->data.fn_call_expr.params.at(0); | |
| 6127 | IrInstruction *options_inner = ir_gen_node_extra(irb, options_node, scope, | |
| 6128 | LValNone, &result_loc_cast->base); | |
| 6129 | if (options_inner == irb->codegen->invalid_instruction) | |
| 6130 | return options_inner; | |
| 6131 | IrInstruction *options = ir_build_implicit_cast(irb, scope, options_node, options_inner, result_loc_cast); | |
| 6132 | ||
| 6133 | AstNode *fn_ref_node = node->data.fn_call_expr.params.at(1); | |
| 6134 | AstNode *args_node = node->data.fn_call_expr.params.at(2); | |
| 6135 | if (args_node->type == NodeTypeContainerInitExpr) { | |
| 6136 | if (args_node->data.container_init_expr.kind == ContainerInitKindArray || | |
| 6137 | args_node->data.container_init_expr.entries.length == 0) | |
| 6138 | { | |
| 6139 | return ir_gen_fn_call_with_args(irb, scope, node, | |
| 6140 | fn_ref_node, CallModifierNone, options, | |
| 6141 | args_node->data.container_init_expr.entries.items, | |
| 6142 | args_node->data.container_init_expr.entries.length, | |
| 6143 | lval, result_loc); | |
| 6144 | } else { | |
| 6145 | exec_add_error_node(irb->codegen, irb->exec, args_node, | |
| 6146 | buf_sprintf("TODO: @call with anon struct literal")); | |
| 6147 | return irb->codegen->invalid_instruction; | |
| 6148 | } | |
| 6149 | } else { | |
| 6150 | IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope); | |
| 6151 | if (fn_ref == irb->codegen->invalid_instruction) | |
| 6152 | return fn_ref; | |
| 6153 | ||
| 6154 | IrInstruction *args = ir_gen_node(irb, args_node, scope); | |
| 6155 | if (args == irb->codegen->invalid_instruction) | |
| 6156 | return args; | |
| 6157 | ||
| 6158 | IrInstruction *call = ir_build_call_extra(irb, scope, node, options, fn_ref, args, result_loc); | |
| 6055 | 6159 | return ir_lval_wrap(irb, scope, call, lval, result_loc); |
| 6056 | 6160 | } |
| 6161 | } | |
| 6057 | 6162 | case BuiltinFnIdAsyncCall: |
| 6058 | 6163 | return ir_gen_async_call(irb, scope, nullptr, node, lval, result_loc); |
| 6059 | 6164 | case BuiltinFnIdTypeId: |
| ... | ... | @@ -6371,33 +6476,8 @@ static IrInstruction *ir_gen_fn_call(IrBuilder *irb, Scope *scope, AstNode *node |
| 6371 | 6476 | return ir_gen_builtin_fn_call(irb, scope, node, lval, result_loc); |
| 6372 | 6477 | |
| 6373 | 6478 | AstNode *fn_ref_node = node->data.fn_call_expr.fn_ref_expr; |
| 6374 | IrInstruction *fn_ref = ir_gen_node(irb, fn_ref_node, scope); | |
| 6375 | if (fn_ref == irb->codegen->invalid_instruction) | |
| 6376 | return fn_ref; | |
| 6377 | ||
| 6378 | IrInstruction *fn_type = ir_build_typeof(irb, scope, node, fn_ref); | |
| 6379 | ||
| 6380 | size_t arg_count = node->data.fn_call_expr.params.length; | |
| 6381 | IrInstruction **args = allocate<IrInstruction*>(arg_count); | |
| 6382 | for (size_t i = 0; i < arg_count; i += 1) { | |
| 6383 | AstNode *arg_node = node->data.fn_call_expr.params.at(i); | |
| 6384 | ||
| 6385 | IrInstruction *arg_index = ir_build_const_usize(irb, scope, arg_node, i); | |
| 6386 | IrInstruction *arg_type = ir_build_arg_type(irb, scope, node, fn_type, arg_index, true); | |
| 6387 | ResultLoc *no_result = no_result_loc(); | |
| 6388 | ir_build_reset_result(irb, scope, node, no_result); | |
| 6389 | ResultLocCast *result_loc_cast = ir_build_cast_result_loc(irb, arg_type, no_result); | |
| 6390 | ||
| 6391 | IrInstruction *arg = ir_gen_node_extra(irb, arg_node, scope, LValNone, &result_loc_cast->base); | |
| 6392 | if (arg == irb->codegen->invalid_instruction) | |
| 6393 | return arg; | |
| 6394 | ||
| 6395 | args[i] = ir_build_implicit_cast(irb, scope, arg_node, arg, result_loc_cast); | |
| 6396 | } | |
| 6397 | ||
| 6398 | IrInstruction *fn_call = ir_build_call_src(irb, scope, node, nullptr, fn_ref, arg_count, args, false, | |
| 6399 | FnInlineAuto, node->data.fn_call_expr.modifier, false, nullptr, result_loc); | |
| 6400 | return ir_lval_wrap(irb, scope, fn_call, lval, result_loc); | |
| 6479 | return ir_gen_fn_call_with_args(irb, scope, node, fn_ref_node, node->data.fn_call_expr.modifier, | |
| 6480 | nullptr, node->data.fn_call_expr.params.items, node->data.fn_call_expr.params.length, lval, result_loc); | |
| 6401 | 6481 | } |
| 6402 | 6482 | |
| 6403 | 6483 | static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval, |
| ... | ... | @@ -13278,6 +13358,15 @@ static IrInstruction *ir_analyze_struct_value_field_value(IrAnalyze *ira, IrInst |
| 13278 | 13358 | return ir_get_deref(ira, source_instr, field_ptr, nullptr); |
| 13279 | 13359 | } |
| 13280 | 13360 | |
| 13361 | static IrInstruction *ir_analyze_optional_value_payload_value(IrAnalyze *ira, IrInstruction *source_instr, | |
| 13362 | IrInstruction *optional_operand, bool safety_check_on) | |
| 13363 | { | |
| 13364 | IrInstruction *opt_ptr = ir_get_ref(ira, source_instr, optional_operand, true, false); | |
| 13365 | IrInstruction *payload_ptr = ir_analyze_unwrap_optional_payload(ira, source_instr, opt_ptr, | |
| 13366 | safety_check_on, false); | |
| 13367 | return ir_get_deref(ira, source_instr, payload_ptr, nullptr); | |
| 13368 | } | |
| 13369 | ||
| 13281 | 13370 | static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr, |
| 13282 | 13371 | ZigType *wanted_type, IrInstruction *value) |
| 13283 | 13372 | { |
| ... | ... | @@ -13911,6 +14000,20 @@ static IrInstruction *ir_implicit_cast(IrAnalyze *ira, IrInstruction *value, Zig |
| 13911 | 14000 | return ir_implicit_cast2(ira, value, value, expected_type); |
| 13912 | 14001 | } |
| 13913 | 14002 | |
| 14003 | static ZigType *get_ptr_elem_type(CodeGen *g, IrInstruction *ptr) { | |
| 14004 | ir_assert(ptr->value->type->id == ZigTypeIdPointer, ptr); | |
| 14005 | ZigType *elem_type = ptr->value->type->data.pointer.child_type; | |
| 14006 | if (elem_type != g->builtin_types.entry_var) | |
| 14007 | return elem_type; | |
| 14008 | ||
| 14009 | if (ir_resolve_lazy(g, ptr->source_node, ptr->value)) | |
| 14010 | return g->builtin_types.entry_invalid; | |
| 14011 | ||
| 14012 | assert(value_is_comptime(ptr->value)); | |
| 14013 | ZigValue *pointee = const_ptr_pointee_unchecked(g, ptr->value); | |
| 14014 | return pointee->type; | |
| 14015 | } | |
| 14016 | ||
| 13914 | 14017 | static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruction, IrInstruction *ptr, |
| 13915 | 14018 | ResultLoc *result_loc) |
| 13916 | 14019 | { |
| ... | ... | @@ -13927,6 +14030,8 @@ static IrInstruction *ir_get_deref(IrAnalyze *ira, IrInstruction *source_instruc |
| 13927 | 14030 | } |
| 13928 | 14031 | |
| 13929 | 14032 | ZigType *child_type = ptr_type->data.pointer.child_type; |
| 14033 | if (type_is_invalid(child_type)) | |
| 14034 | return ira->codegen->invalid_instruction; | |
| 13930 | 14035 | // if the child type has one possible value, the deref is comptime |
| 13931 | 14036 | switch (type_has_one_possible_value(ira->codegen, child_type)) { |
| 13932 | 14037 | case OnePossibleValueInvalid: |
| ... | ... | @@ -14102,9 +14207,7 @@ static bool ir_resolve_atomic_order(IrAnalyze *ira, IrInstruction *value, Atomic |
| 14102 | 14207 | if (type_is_invalid(value->value->type)) |
| 14103 | 14208 | return false; |
| 14104 | 14209 | |
| 14105 | ZigValue *atomic_order_val = get_builtin_value(ira->codegen, "AtomicOrder"); | |
| 14106 | assert(atomic_order_val->type->id == ZigTypeIdMetaType); | |
| 14107 | ZigType *atomic_order_type = atomic_order_val->data.x_type; | |
| 14210 | ZigType *atomic_order_type = get_builtin_type(ira->codegen, "AtomicOrder"); | |
| 14108 | 14211 | |
| 14109 | 14212 | IrInstruction *casted_value = ir_implicit_cast(ira, value, atomic_order_type); |
| 14110 | 14213 | if (type_is_invalid(casted_value->value->type)) |
| ... | ... | @@ -14122,9 +14225,7 @@ static bool ir_resolve_atomic_rmw_op(IrAnalyze *ira, IrInstruction *value, Atomi |
| 14122 | 14225 | if (type_is_invalid(value->value->type)) |
| 14123 | 14226 | return false; |
| 14124 | 14227 | |
| 14125 | ZigValue *atomic_rmw_op_val = get_builtin_value(ira->codegen, "AtomicRmwOp"); | |
| 14126 | assert(atomic_rmw_op_val->type->id == ZigTypeIdMetaType); | |
| 14127 | ZigType *atomic_rmw_op_type = atomic_rmw_op_val->data.x_type; | |
| 14228 | ZigType *atomic_rmw_op_type = get_builtin_type(ira->codegen, "AtomicRmwOp"); | |
| 14128 | 14229 | |
| 14129 | 14230 | IrInstruction *casted_value = ir_implicit_cast(ira, value, atomic_rmw_op_type); |
| 14130 | 14231 | if (type_is_invalid(casted_value->value->type)) |
| ... | ... | @@ -14142,9 +14243,7 @@ static bool ir_resolve_global_linkage(IrAnalyze *ira, IrInstruction *value, Glob |
| 14142 | 14243 | if (type_is_invalid(value->value->type)) |
| 14143 | 14244 | return false; |
| 14144 | 14245 | |
| 14145 | ZigValue *global_linkage_val = get_builtin_value(ira->codegen, "GlobalLinkage"); | |
| 14146 | assert(global_linkage_val->type->id == ZigTypeIdMetaType); | |
| 14147 | ZigType *global_linkage_type = global_linkage_val->data.x_type; | |
| 14246 | ZigType *global_linkage_type = get_builtin_type(ira->codegen, "GlobalLinkage"); | |
| 14148 | 14247 | |
| 14149 | 14248 | IrInstruction *casted_value = ir_implicit_cast(ira, value, global_linkage_type); |
| 14150 | 14249 | if (type_is_invalid(casted_value->value->type)) |
| ... | ... | @@ -14162,9 +14261,7 @@ static bool ir_resolve_float_mode(IrAnalyze *ira, IrInstruction *value, FloatMod |
| 14162 | 14261 | if (type_is_invalid(value->value->type)) |
| 14163 | 14262 | return false; |
| 14164 | 14263 | |
| 14165 | ZigValue *float_mode_val = get_builtin_value(ira->codegen, "FloatMode"); | |
| 14166 | assert(float_mode_val->type->id == ZigTypeIdMetaType); | |
| 14167 | ZigType *float_mode_type = float_mode_val->data.x_type; | |
| 14264 | ZigType *float_mode_type = get_builtin_type(ira->codegen, "FloatMode"); | |
| 14168 | 14265 | |
| 14169 | 14266 | IrInstruction *casted_value = ir_implicit_cast(ira, value, float_mode_type); |
| 14170 | 14267 | if (type_is_invalid(casted_value->value->type)) |
| ... | ... | @@ -16972,11 +17069,11 @@ static IrInstruction *ir_analyze_instruction_reset_result(IrAnalyze *ira, IrInst |
| 16972 | 17069 | return ir_const_void(ira, &instruction->base); |
| 16973 | 17070 | } |
| 16974 | 17071 | |
| 16975 | static IrInstruction *get_async_call_result_loc(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, | |
| 16976 | ZigType *fn_ret_type) | |
| 17072 | static IrInstruction *get_async_call_result_loc(IrAnalyze *ira, IrInstruction *source_instr, | |
| 17073 | ZigType *fn_ret_type, bool is_async_call_builtin, IrInstruction **args_ptr, size_t args_len, | |
| 17074 | IrInstruction *ret_ptr_uncasted) | |
| 16977 | 17075 | { |
| 16978 | ir_assert(call_instruction->is_async_call_builtin, &call_instruction->base); | |
| 16979 | IrInstruction *ret_ptr_uncasted = call_instruction->args[call_instruction->arg_count]->child; | |
| 17076 | ir_assert(is_async_call_builtin, source_instr); | |
| 16980 | 17077 | if (type_is_invalid(ret_ptr_uncasted->value->type)) |
| 16981 | 17078 | return ira->codegen->invalid_instruction; |
| 16982 | 17079 | if (ret_ptr_uncasted->value->type->id == ZigTypeIdVoid) { |
| ... | ... | @@ -16986,9 +17083,10 @@ static IrInstruction *get_async_call_result_loc(IrAnalyze *ira, IrInstructionCal |
| 16986 | 17083 | return ir_implicit_cast(ira, ret_ptr_uncasted, get_pointer_to_type(ira->codegen, fn_ret_type, false)); |
| 16987 | 17084 | } |
| 16988 | 17085 | |
| 16989 | static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, ZigFn *fn_entry, | |
| 17086 | static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstruction *source_instr, ZigFn *fn_entry, | |
| 16990 | 17087 | ZigType *fn_type, IrInstruction *fn_ref, IrInstruction **casted_args, size_t arg_count, |
| 16991 | IrInstruction *casted_new_stack) | |
| 17088 | IrInstruction *casted_new_stack, bool is_async_call_builtin, IrInstruction *ret_ptr_uncasted, | |
| 17089 | ResultLoc *call_result_loc) | |
| 16992 | 17090 | { |
| 16993 | 17091 | if (fn_entry == nullptr) { |
| 16994 | 17092 | if (fn_type->data.fn.fn_type_id.cc != CallingConventionAsync) { |
| ... | ... | @@ -17003,19 +17101,20 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc |
| 17003 | 17101 | } |
| 17004 | 17102 | if (casted_new_stack != nullptr) { |
| 17005 | 17103 | ZigType *fn_ret_type = fn_type->data.fn.fn_type_id.return_type; |
| 17006 | IrInstruction *ret_ptr = get_async_call_result_loc(ira, call_instruction, fn_ret_type); | |
| 17104 | IrInstruction *ret_ptr = get_async_call_result_loc(ira, source_instr, fn_ret_type, is_async_call_builtin, | |
| 17105 | casted_args, arg_count, ret_ptr_uncasted); | |
| 17007 | 17106 | if (ret_ptr != nullptr && type_is_invalid(ret_ptr->value->type)) |
| 17008 | 17107 | return ira->codegen->invalid_instruction; |
| 17009 | 17108 | |
| 17010 | 17109 | ZigType *anyframe_type = get_any_frame_type(ira->codegen, fn_ret_type); |
| 17011 | 17110 | |
| 17012 | IrInstructionCallGen *call_gen = ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, | |
| 17013 | arg_count, casted_args, FnInlineAuto, CallModifierAsync, casted_new_stack, | |
| 17014 | call_instruction->is_async_call_builtin, ret_ptr, anyframe_type); | |
| 17111 | IrInstructionCallGen *call_gen = ir_build_call_gen(ira, source_instr, fn_entry, fn_ref, | |
| 17112 | arg_count, casted_args, CallModifierAsync, casted_new_stack, | |
| 17113 | is_async_call_builtin, ret_ptr, anyframe_type); | |
| 17015 | 17114 | return &call_gen->base; |
| 17016 | 17115 | } else { |
| 17017 | 17116 | ZigType *frame_type = get_fn_frame_type(ira->codegen, fn_entry); |
| 17018 | IrInstruction *result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, | |
| 17117 | IrInstruction *result_loc = ir_resolve_result(ira, source_instr, call_result_loc, | |
| 17019 | 17118 | frame_type, nullptr, true, true, false); |
| 17020 | 17119 | if (type_is_invalid(result_loc->value->type) || instr_is_unreachable(result_loc)) { |
| 17021 | 17120 | return result_loc; |
| ... | ... | @@ -17023,9 +17122,9 @@ static IrInstruction *ir_analyze_async_call(IrAnalyze *ira, IrInstructionCallSrc |
| 17023 | 17122 | result_loc = ir_implicit_cast(ira, result_loc, get_pointer_to_type(ira->codegen, frame_type, false)); |
| 17024 | 17123 | if (type_is_invalid(result_loc->value->type)) |
| 17025 | 17124 | return ira->codegen->invalid_instruction; |
| 17026 | return &ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, arg_count, | |
| 17027 | casted_args, FnInlineAuto, CallModifierAsync, casted_new_stack, | |
| 17028 | call_instruction->is_async_call_builtin, result_loc, frame_type)->base; | |
| 17125 | return &ir_build_call_gen(ira, source_instr, fn_entry, fn_ref, arg_count, | |
| 17126 | casted_args, CallModifierAsync, casted_new_stack, | |
| 17127 | is_async_call_builtin, result_loc, frame_type)->base; | |
| 17029 | 17128 | } |
| 17030 | 17129 | } |
| 17031 | 17130 | static bool ir_analyze_fn_call_inline_arg(IrAnalyze *ira, AstNode *fn_proto_node, |
| ... | ... | @@ -17288,9 +17387,7 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source |
| 17288 | 17387 | copy_const_val(casted_ptr->value, ptr->value); |
| 17289 | 17388 | casted_ptr->value->type = struct_ptr_type; |
| 17290 | 17389 | } else { |
| 17291 | casted_ptr = ir_build_cast(&ira->new_irb, source_instr->scope, | |
| 17292 | source_instr->source_node, struct_ptr_type, ptr, CastOpNoop); | |
| 17293 | casted_ptr->value->type = struct_ptr_type; | |
| 17390 | casted_ptr = ptr; | |
| 17294 | 17391 | } |
| 17295 | 17392 | if (instr_is_comptime(casted_ptr)) { |
| 17296 | 17393 | ZigValue *ptr_val = ir_resolve_const(ira, casted_ptr, UndefBad); |
| ... | ... | @@ -17371,6 +17468,12 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source |
| 17371 | 17468 | } |
| 17372 | 17469 | } |
| 17373 | 17470 | |
| 17471 | if (ptr->value->type->data.pointer.inferred_struct_field != nullptr && | |
| 17472 | child_type == ira->codegen->builtin_types.entry_var) | |
| 17473 | { | |
| 17474 | child_type = ptr->value->type->data.pointer.inferred_struct_field->inferred_struct_type; | |
| 17475 | } | |
| 17476 | ||
| 17374 | 17477 | switch (type_requires_comptime(ira->codegen, child_type)) { |
| 17375 | 17478 | case ReqCompTimeInvalid: |
| 17376 | 17479 | return ira->codegen->invalid_instruction; |
| ... | ... | @@ -17417,25 +17520,21 @@ static IrInstruction *ir_analyze_store_ptr(IrAnalyze *ira, IrInstruction *source |
| 17417 | 17520 | return &store_ptr->base; |
| 17418 | 17521 | } |
| 17419 | 17522 | |
| 17420 | static IrInstruction *analyze_casted_new_stack(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, | |
| 17421 | ZigFn *fn_entry) | |
| 17523 | static IrInstruction *analyze_casted_new_stack(IrAnalyze *ira, IrInstruction *source_instr, | |
| 17524 | IrInstruction *new_stack, bool is_async_call_builtin, ZigFn *fn_entry) | |
| 17422 | 17525 | { |
| 17423 | if (call_instruction->new_stack == nullptr) | |
| 17526 | if (new_stack == nullptr) | |
| 17424 | 17527 | return nullptr; |
| 17425 | 17528 | |
| 17426 | if (!call_instruction->is_async_call_builtin && | |
| 17529 | if (!is_async_call_builtin && | |
| 17427 | 17530 | arch_stack_pointer_register_name(ira->codegen->zig_target->arch) == nullptr) |
| 17428 | 17531 | { |
| 17429 | ir_add_error(ira, &call_instruction->base, | |
| 17430 | buf_sprintf("target arch '%s' does not support @newStackCall", | |
| 17532 | ir_add_error(ira, source_instr, | |
| 17533 | buf_sprintf("target arch '%s' does not support calling with a new stack", | |
| 17431 | 17534 | target_arch_name(ira->codegen->zig_target->arch))); |
| 17432 | 17535 | } |
| 17433 | 17536 | |
| 17434 | IrInstruction *new_stack = call_instruction->new_stack->child; | |
| 17435 | if (type_is_invalid(new_stack->value->type)) | |
| 17436 | return ira->codegen->invalid_instruction; | |
| 17437 | ||
| 17438 | if (call_instruction->is_async_call_builtin && | |
| 17537 | if (is_async_call_builtin && | |
| 17439 | 17538 | fn_entry != nullptr && new_stack->value->type->id == ZigTypeIdPointer && |
| 17440 | 17539 | new_stack->value->type->data.pointer.child_type->id == ZigTypeIdFnFrame) |
| 17441 | 17540 | { |
| ... | ... | @@ -17451,9 +17550,11 @@ static IrInstruction *analyze_casted_new_stack(IrAnalyze *ira, IrInstructionCall |
| 17451 | 17550 | } |
| 17452 | 17551 | } |
| 17453 | 17552 | |
| 17454 | static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, | |
| 17553 | static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstruction *source_instr, | |
| 17455 | 17554 | ZigFn *fn_entry, ZigType *fn_type, IrInstruction *fn_ref, |
| 17456 | IrInstruction *first_arg_ptr, bool comptime_fn_call, FnInline fn_inline) | |
| 17555 | IrInstruction *first_arg_ptr, CallModifier modifier, | |
| 17556 | IrInstruction *new_stack, bool is_async_call_builtin, | |
| 17557 | IrInstruction **args_ptr, size_t args_len, IrInstruction *ret_ptr, ResultLoc *call_result_loc) | |
| 17457 | 17558 | { |
| 17458 | 17559 | Error err; |
| 17459 | 17560 | FnTypeId *fn_type_id = &fn_type->data.fn.fn_type_id; |
| ... | ... | @@ -17469,16 +17570,16 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 17469 | 17570 | } |
| 17470 | 17571 | size_t src_param_count = fn_type_id->param_count - var_args_1_or_0; |
| 17471 | 17572 | |
| 17472 | size_t call_param_count = call_instruction->arg_count + first_arg_1_or_0; | |
| 17473 | for (size_t i = 0; i < call_instruction->arg_count; i += 1) { | |
| 17474 | ZigValue *arg_tuple_value = call_instruction->args[i]->child->value; | |
| 17573 | size_t call_param_count = args_len + first_arg_1_or_0; | |
| 17574 | for (size_t i = 0; i < args_len; i += 1) { | |
| 17575 | ZigValue *arg_tuple_value = args_ptr[i]->value; | |
| 17475 | 17576 | if (arg_tuple_value->type->id == ZigTypeIdArgTuple) { |
| 17476 | 17577 | call_param_count -= 1; |
| 17477 | 17578 | call_param_count += arg_tuple_value->data.x_arg_tuple.end_index - |
| 17478 | 17579 | arg_tuple_value->data.x_arg_tuple.start_index; |
| 17479 | 17580 | } |
| 17480 | 17581 | } |
| 17481 | AstNode *source_node = call_instruction->base.source_node; | |
| 17582 | AstNode *source_node = source_instr->source_node; | |
| 17482 | 17583 | |
| 17483 | 17584 | AstNode *fn_proto_node = fn_entry ? fn_entry->proto_node : nullptr;; |
| 17484 | 17585 | |
| ... | ... | @@ -17511,14 +17612,14 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 17511 | 17612 | return ira->codegen->invalid_instruction; |
| 17512 | 17613 | } |
| 17513 | 17614 | |
| 17514 | if (comptime_fn_call) { | |
| 17615 | if (modifier == CallModifierCompileTime) { | |
| 17515 | 17616 | // No special handling is needed for compile time evaluation of generic functions. |
| 17516 | 17617 | if (!fn_entry || fn_entry->body_node == nullptr) { |
| 17517 | 17618 | ir_add_error(ira, fn_ref, buf_sprintf("unable to evaluate constant expression")); |
| 17518 | 17619 | return ira->codegen->invalid_instruction; |
| 17519 | 17620 | } |
| 17520 | 17621 | |
| 17521 | if (!ir_emit_backward_branch(ira, &call_instruction->base)) | |
| 17622 | if (!ir_emit_backward_branch(ira, source_instr)) | |
| 17522 | 17623 | return ira->codegen->invalid_instruction; |
| 17523 | 17624 | |
| 17524 | 17625 | // Fork a scope of the function with known values for the parameters. |
| ... | ... | @@ -17550,16 +17651,14 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 17550 | 17651 | } |
| 17551 | 17652 | |
| 17552 | 17653 | if (fn_proto_node->data.fn_proto.is_var_args) { |
| 17553 | ir_add_error(ira, &call_instruction->base, | |
| 17654 | ir_add_error(ira, source_instr, | |
| 17554 | 17655 | buf_sprintf("compiler bug: unable to call var args function at compile time. https://github.com/ziglang/zig/issues/313")); |
| 17555 | 17656 | return ira->codegen->invalid_instruction; |
| 17556 | 17657 | } |
| 17557 | 17658 | |
| 17558 | 17659 | |
| 17559 | for (size_t call_i = 0; call_i < call_instruction->arg_count; call_i += 1) { | |
| 17560 | IrInstruction *old_arg = call_instruction->args[call_i]->child; | |
| 17561 | if (type_is_invalid(old_arg->value->type)) | |
| 17562 | return ira->codegen->invalid_instruction; | |
| 17660 | for (size_t call_i = 0; call_i < args_len; call_i += 1) { | |
| 17661 | IrInstruction *old_arg = args_ptr[call_i]; | |
| 17563 | 17662 | |
| 17564 | 17663 | if (!ir_analyze_fn_call_inline_arg(ira, fn_proto_node, old_arg, &exec_scope, &next_proto_i)) |
| 17565 | 17664 | return ira->codegen->invalid_instruction; |
| ... | ... | @@ -17593,7 +17692,7 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 17593 | 17692 | AstNode *body_node = fn_entry->body_node; |
| 17594 | 17693 | result = ir_eval_const_value(ira->codegen, exec_scope, body_node, return_type, |
| 17595 | 17694 | ira->new_irb.exec->backward_branch_count, ira->new_irb.exec->backward_branch_quota, fn_entry, |
| 17596 | nullptr, call_instruction->base.source_node, nullptr, ira->new_irb.exec, return_type_node, | |
| 17695 | nullptr, source_instr->source_node, nullptr, ira->new_irb.exec, return_type_node, | |
| 17597 | 17696 | UndefOk); |
| 17598 | 17697 | |
| 17599 | 17698 | if (inferred_err_set_type != nullptr) { |
| ... | ... | @@ -17623,24 +17722,21 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 17623 | 17722 | } |
| 17624 | 17723 | } |
| 17625 | 17724 | |
| 17626 | IrInstruction *new_instruction = ir_const_move(ira, &call_instruction->base, result); | |
| 17725 | IrInstruction *new_instruction = ir_const_move(ira, source_instr, result); | |
| 17627 | 17726 | return ir_finish_anal(ira, new_instruction); |
| 17628 | 17727 | } |
| 17629 | 17728 | |
| 17630 | 17729 | if (fn_type->data.fn.is_generic) { |
| 17631 | 17730 | if (!fn_entry) { |
| 17632 | ir_add_error(ira, call_instruction->fn_ref, | |
| 17731 | ir_add_error(ira, fn_ref, | |
| 17633 | 17732 | buf_sprintf("calling a generic function requires compile-time known function value")); |
| 17634 | 17733 | return ira->codegen->invalid_instruction; |
| 17635 | 17734 | } |
| 17636 | 17735 | |
| 17637 | 17736 | // Count the arguments of the function type id we are creating |
| 17638 | 17737 | size_t new_fn_arg_count = first_arg_1_or_0; |
| 17639 | for (size_t call_i = 0; call_i < call_instruction->arg_count; call_i += 1) { | |
| 17640 | IrInstruction *arg = call_instruction->args[call_i]->child; | |
| 17641 | if (type_is_invalid(arg->value->type)) | |
| 17642 | return ira->codegen->invalid_instruction; | |
| 17643 | ||
| 17738 | for (size_t call_i = 0; call_i < args_len; call_i += 1) { | |
| 17739 | IrInstruction *arg = args_ptr[call_i]; | |
| 17644 | 17740 | if (arg->value->type->id == ZigTypeIdArgTuple) { |
| 17645 | 17741 | new_fn_arg_count += arg->value->data.x_arg_tuple.end_index - arg->value->data.x_arg_tuple.start_index; |
| 17646 | 17742 | } else { |
| ... | ... | @@ -17702,10 +17798,8 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 17702 | 17798 | |
| 17703 | 17799 | ZigFn *parent_fn_entry = exec_fn_entry(ira->new_irb.exec); |
| 17704 | 17800 | assert(parent_fn_entry); |
| 17705 | for (size_t call_i = 0; call_i < call_instruction->arg_count; call_i += 1) { | |
| 17706 | IrInstruction *arg = call_instruction->args[call_i]->child; | |
| 17707 | if (type_is_invalid(arg->value->type)) | |
| 17708 | return ira->codegen->invalid_instruction; | |
| 17801 | for (size_t call_i = 0; call_i < args_len; call_i += 1) { | |
| 17802 | IrInstruction *arg = args_ptr[call_i]; | |
| 17709 | 17803 | |
| 17710 | 17804 | if (arg->value->type->id == ZigTypeIdArgTuple) { |
| 17711 | 17805 | for (size_t arg_tuple_i = arg->value->data.x_arg_tuple.start_index; |
| ... | ... | @@ -17804,8 +17898,9 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 17804 | 17898 | switch (type_requires_comptime(ira->codegen, specified_return_type)) { |
| 17805 | 17899 | case ReqCompTimeYes: |
| 17806 | 17900 | // Throw out our work and call the function as if it were comptime. |
| 17807 | return ir_analyze_fn_call(ira, call_instruction, fn_entry, fn_type, fn_ref, first_arg_ptr, | |
| 17808 | true, FnInlineAuto); | |
| 17901 | return ir_analyze_fn_call(ira, source_instr, fn_entry, fn_type, fn_ref, first_arg_ptr, | |
| 17902 | CallModifierCompileTime, new_stack, is_async_call_builtin, args_ptr, args_len, | |
| 17903 | ret_ptr, call_result_loc); | |
| 17809 | 17904 | case ReqCompTimeInvalid: |
| 17810 | 17905 | return ira->codegen->invalid_instruction; |
| 17811 | 17906 | case ReqCompTimeNo: |
| ... | ... | @@ -17823,9 +17918,9 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 17823 | 17918 | if (type_is_invalid(impl_fn->type_entry)) |
| 17824 | 17919 | return ira->codegen->invalid_instruction; |
| 17825 | 17920 | |
| 17826 | impl_fn->ir_executable->source_node = call_instruction->base.source_node; | |
| 17921 | impl_fn->ir_executable->source_node = source_instr->source_node; | |
| 17827 | 17922 | impl_fn->ir_executable->parent_exec = ira->new_irb.exec; |
| 17828 | impl_fn->analyzed_executable.source_node = call_instruction->base.source_node; | |
| 17923 | impl_fn->analyzed_executable.source_node = source_instr->source_node; | |
| 17829 | 17924 | impl_fn->analyzed_executable.parent_exec = ira->new_irb.exec; |
| 17830 | 17925 | impl_fn->analyzed_executable.backward_branch_quota = ira->new_irb.exec->backward_branch_quota; |
| 17831 | 17926 | impl_fn->analyzed_executable.is_generic_instantiation = true; |
| ... | ... | @@ -17839,32 +17934,35 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 17839 | 17934 | parent_fn_entry->calls_or_awaits_errorable_fn = true; |
| 17840 | 17935 | } |
| 17841 | 17936 | |
| 17842 | IrInstruction *casted_new_stack = analyze_casted_new_stack(ira, call_instruction, impl_fn); | |
| 17937 | IrInstruction *casted_new_stack = analyze_casted_new_stack(ira, source_instr, new_stack, | |
| 17938 | is_async_call_builtin, impl_fn); | |
| 17843 | 17939 | if (casted_new_stack != nullptr && type_is_invalid(casted_new_stack->value->type)) |
| 17844 | 17940 | return ira->codegen->invalid_instruction; |
| 17845 | 17941 | |
| 17846 | 17942 | size_t impl_param_count = impl_fn_type_id->param_count; |
| 17847 | if (call_instruction->modifier == CallModifierAsync) { | |
| 17848 | IrInstruction *result = ir_analyze_async_call(ira, call_instruction, impl_fn, impl_fn->type_entry, | |
| 17849 | nullptr, casted_args, impl_param_count, casted_new_stack); | |
| 17943 | if (modifier == CallModifierAsync) { | |
| 17944 | IrInstruction *result = ir_analyze_async_call(ira, source_instr, impl_fn, impl_fn->type_entry, | |
| 17945 | nullptr, casted_args, impl_param_count, casted_new_stack, is_async_call_builtin, ret_ptr, | |
| 17946 | call_result_loc); | |
| 17850 | 17947 | return ir_finish_anal(ira, result); |
| 17851 | 17948 | } |
| 17852 | 17949 | |
| 17853 | 17950 | IrInstruction *result_loc; |
| 17854 | 17951 | if (handle_is_ptr(impl_fn_type_id->return_type)) { |
| 17855 | result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, | |
| 17952 | result_loc = ir_resolve_result(ira, source_instr, call_result_loc, | |
| 17856 | 17953 | impl_fn_type_id->return_type, nullptr, true, true, false); |
| 17857 | 17954 | if (result_loc != nullptr) { |
| 17858 | 17955 | if (type_is_invalid(result_loc->value->type) || instr_is_unreachable(result_loc)) { |
| 17859 | 17956 | return result_loc; |
| 17860 | 17957 | } |
| 17861 | 17958 | if (!handle_is_ptr(result_loc->value->type->data.pointer.child_type)) { |
| 17862 | ir_reset_result(call_instruction->result_loc); | |
| 17959 | ir_reset_result(call_result_loc); | |
| 17863 | 17960 | result_loc = nullptr; |
| 17864 | 17961 | } |
| 17865 | 17962 | } |
| 17866 | } else if (call_instruction->is_async_call_builtin) { | |
| 17867 | result_loc = get_async_call_result_loc(ira, call_instruction, impl_fn_type_id->return_type); | |
| 17963 | } else if (is_async_call_builtin) { | |
| 17964 | result_loc = get_async_call_result_loc(ira, source_instr, impl_fn_type_id->return_type, | |
| 17965 | is_async_call_builtin, args_ptr, args_len, ret_ptr); | |
| 17868 | 17966 | if (result_loc != nullptr && type_is_invalid(result_loc->value->type)) |
| 17869 | 17967 | return ira->codegen->invalid_instruction; |
| 17870 | 17968 | } else { |
| ... | ... | @@ -17873,18 +17971,17 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 17873 | 17971 | |
| 17874 | 17972 | if (impl_fn_type_id->cc == CallingConventionAsync && |
| 17875 | 17973 | parent_fn_entry->inferred_async_node == nullptr && |
| 17876 | call_instruction->modifier != CallModifierNoAsync) | |
| 17974 | modifier != CallModifierNoAsync) | |
| 17877 | 17975 | { |
| 17878 | 17976 | parent_fn_entry->inferred_async_node = fn_ref->source_node; |
| 17879 | 17977 | parent_fn_entry->inferred_async_fn = impl_fn; |
| 17880 | 17978 | } |
| 17881 | 17979 | |
| 17882 | IrInstructionCallGen *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, | |
| 17883 | impl_fn, nullptr, impl_param_count, casted_args, fn_inline, | |
| 17884 | call_instruction->modifier, casted_new_stack, call_instruction->is_async_call_builtin, result_loc, | |
| 17885 | impl_fn_type_id->return_type); | |
| 17980 | IrInstructionCallGen *new_call_instruction = ir_build_call_gen(ira, source_instr, | |
| 17981 | impl_fn, nullptr, impl_param_count, casted_args, modifier, casted_new_stack, | |
| 17982 | is_async_call_builtin, result_loc, impl_fn_type_id->return_type); | |
| 17886 | 17983 | |
| 17887 | if (get_scope_typeof(call_instruction->base.scope) == nullptr) { | |
| 17984 | if (get_scope_typeof(source_instr->scope) == nullptr) { | |
| 17888 | 17985 | parent_fn_entry->call_list.append(new_call_instruction); |
| 17889 | 17986 | } |
| 17890 | 17987 | |
| ... | ... | @@ -17926,8 +18023,8 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 17926 | 18023 | casted_args[next_arg_index] = casted_arg; |
| 17927 | 18024 | next_arg_index += 1; |
| 17928 | 18025 | } |
| 17929 | for (size_t call_i = 0; call_i < call_instruction->arg_count; call_i += 1) { | |
| 17930 | IrInstruction *old_arg = call_instruction->args[call_i]->child; | |
| 18026 | for (size_t call_i = 0; call_i < args_len; call_i += 1) { | |
| 18027 | IrInstruction *old_arg = args_ptr[call_i]; | |
| 17931 | 18028 | if (type_is_invalid(old_arg->value->type)) |
| 17932 | 18029 | return ira->codegen->invalid_instruction; |
| 17933 | 18030 | |
| ... | ... | @@ -17988,25 +18085,26 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 17988 | 18085 | if (type_is_invalid(return_type)) |
| 17989 | 18086 | return ira->codegen->invalid_instruction; |
| 17990 | 18087 | |
| 17991 | if (fn_entry != nullptr && fn_entry->fn_inline == FnInlineAlways && fn_inline == FnInlineNever) { | |
| 17992 | ir_add_error(ira, &call_instruction->base, | |
| 18088 | if (fn_entry != nullptr && fn_entry->fn_inline == FnInlineAlways && modifier == CallModifierNeverInline) { | |
| 18089 | ir_add_error(ira, source_instr, | |
| 17993 | 18090 | buf_sprintf("no-inline call of inline function")); |
| 17994 | 18091 | return ira->codegen->invalid_instruction; |
| 17995 | 18092 | } |
| 17996 | 18093 | |
| 17997 | IrInstruction *casted_new_stack = analyze_casted_new_stack(ira, call_instruction, fn_entry); | |
| 18094 | IrInstruction *casted_new_stack = analyze_casted_new_stack(ira, source_instr, new_stack, | |
| 18095 | is_async_call_builtin, fn_entry); | |
| 17998 | 18096 | if (casted_new_stack != nullptr && type_is_invalid(casted_new_stack->value->type)) |
| 17999 | 18097 | return ira->codegen->invalid_instruction; |
| 18000 | 18098 | |
| 18001 | if (call_instruction->modifier == CallModifierAsync) { | |
| 18002 | IrInstruction *result = ir_analyze_async_call(ira, call_instruction, fn_entry, fn_type, fn_ref, | |
| 18003 | casted_args, call_param_count, casted_new_stack); | |
| 18099 | if (modifier == CallModifierAsync) { | |
| 18100 | IrInstruction *result = ir_analyze_async_call(ira, source_instr, fn_entry, fn_type, fn_ref, | |
| 18101 | casted_args, call_param_count, casted_new_stack, is_async_call_builtin, ret_ptr, call_result_loc); | |
| 18004 | 18102 | return ir_finish_anal(ira, result); |
| 18005 | 18103 | } |
| 18006 | 18104 | |
| 18007 | 18105 | if (fn_type_id->cc == CallingConventionAsync && |
| 18008 | 18106 | parent_fn_entry->inferred_async_node == nullptr && |
| 18009 | call_instruction->modifier != CallModifierNoAsync) | |
| 18107 | modifier != CallModifierNoAsync) | |
| 18010 | 18108 | { |
| 18011 | 18109 | parent_fn_entry->inferred_async_node = fn_ref->source_node; |
| 18012 | 18110 | parent_fn_entry->inferred_async_fn = fn_entry; |
| ... | ... | @@ -18014,41 +18112,202 @@ static IrInstruction *ir_analyze_fn_call(IrAnalyze *ira, IrInstructionCallSrc *c |
| 18014 | 18112 | |
| 18015 | 18113 | IrInstruction *result_loc; |
| 18016 | 18114 | if (handle_is_ptr(return_type)) { |
| 18017 | result_loc = ir_resolve_result(ira, &call_instruction->base, call_instruction->result_loc, | |
| 18115 | result_loc = ir_resolve_result(ira, source_instr, call_result_loc, | |
| 18018 | 18116 | return_type, nullptr, true, true, false); |
| 18019 | 18117 | if (result_loc != nullptr) { |
| 18020 | 18118 | if (type_is_invalid(result_loc->value->type) || instr_is_unreachable(result_loc)) { |
| 18021 | 18119 | return result_loc; |
| 18022 | 18120 | } |
| 18023 | 18121 | if (!handle_is_ptr(result_loc->value->type->data.pointer.child_type)) { |
| 18024 | ir_reset_result(call_instruction->result_loc); | |
| 18122 | ir_reset_result(call_result_loc); | |
| 18025 | 18123 | result_loc = nullptr; |
| 18026 | 18124 | } |
| 18027 | 18125 | } |
| 18028 | } else if (call_instruction->is_async_call_builtin) { | |
| 18029 | result_loc = get_async_call_result_loc(ira, call_instruction, return_type); | |
| 18126 | } else if (is_async_call_builtin) { | |
| 18127 | result_loc = get_async_call_result_loc(ira, source_instr, return_type, is_async_call_builtin, | |
| 18128 | args_ptr, args_len, ret_ptr); | |
| 18030 | 18129 | if (result_loc != nullptr && type_is_invalid(result_loc->value->type)) |
| 18031 | 18130 | return ira->codegen->invalid_instruction; |
| 18032 | 18131 | } else { |
| 18033 | 18132 | result_loc = nullptr; |
| 18034 | 18133 | } |
| 18035 | 18134 | |
| 18036 | IrInstructionCallGen *new_call_instruction = ir_build_call_gen(ira, &call_instruction->base, fn_entry, fn_ref, | |
| 18037 | call_param_count, casted_args, fn_inline, call_instruction->modifier, casted_new_stack, | |
| 18038 | call_instruction->is_async_call_builtin, result_loc, return_type); | |
| 18039 | if (get_scope_typeof(call_instruction->base.scope) == nullptr) { | |
| 18135 | IrInstructionCallGen *new_call_instruction = ir_build_call_gen(ira, source_instr, fn_entry, fn_ref, | |
| 18136 | call_param_count, casted_args, modifier, casted_new_stack, | |
| 18137 | is_async_call_builtin, result_loc, return_type); | |
| 18138 | if (get_scope_typeof(source_instr->scope) == nullptr) { | |
| 18040 | 18139 | parent_fn_entry->call_list.append(new_call_instruction); |
| 18041 | 18140 | } |
| 18042 | 18141 | return ir_finish_anal(ira, &new_call_instruction->base); |
| 18043 | 18142 | } |
| 18044 | 18143 | |
| 18144 | static IrInstruction *ir_analyze_fn_call_src(IrAnalyze *ira, IrInstructionCallSrc *call_instruction, | |
| 18145 | ZigFn *fn_entry, ZigType *fn_type, IrInstruction *fn_ref, | |
| 18146 | IrInstruction *first_arg_ptr, CallModifier modifier) | |
| 18147 | { | |
| 18148 | IrInstruction *new_stack = nullptr; | |
| 18149 | if (call_instruction->new_stack) { | |
| 18150 | new_stack = call_instruction->new_stack->child; | |
| 18151 | if (type_is_invalid(new_stack->value->type)) | |
| 18152 | return ira->codegen->invalid_instruction; | |
| 18153 | } | |
| 18154 | IrInstruction **args_ptr = allocate<IrInstruction *>(call_instruction->arg_count, "IrInstruction *"); | |
| 18155 | for (size_t i = 0; i < call_instruction->arg_count; i += 1) { | |
| 18156 | args_ptr[i] = call_instruction->args[i]->child; | |
| 18157 | if (type_is_invalid(args_ptr[i]->value->type)) | |
| 18158 | return ira->codegen->invalid_instruction; | |
| 18159 | } | |
| 18160 | IrInstruction *ret_ptr = nullptr; | |
| 18161 | if (call_instruction->ret_ptr != nullptr) { | |
| 18162 | ret_ptr = call_instruction->ret_ptr->child; | |
| 18163 | if (type_is_invalid(ret_ptr->value->type)) | |
| 18164 | return ira->codegen->invalid_instruction; | |
| 18165 | } | |
| 18166 | IrInstruction *result = ir_analyze_fn_call(ira, &call_instruction->base, fn_entry, fn_type, fn_ref, | |
| 18167 | first_arg_ptr, modifier, new_stack, call_instruction->is_async_call_builtin, | |
| 18168 | args_ptr, call_instruction->arg_count, ret_ptr, call_instruction->result_loc); | |
| 18169 | deallocate(args_ptr, call_instruction->arg_count, "IrInstruction *"); | |
| 18170 | return result; | |
| 18171 | } | |
| 18172 | ||
| 18173 | static IrInstruction *ir_analyze_call_extra(IrAnalyze *ira, IrInstruction *source_instr, | |
| 18174 | IrInstruction *pass1_options, IrInstruction *pass1_fn_ref, IrInstruction **args_ptr, size_t args_len, | |
| 18175 | ResultLoc *result_loc) | |
| 18176 | { | |
| 18177 | IrInstruction *options = pass1_options->child; | |
| 18178 | if (type_is_invalid(options->value->type)) | |
| 18179 | return ira->codegen->invalid_instruction; | |
| 18180 | ||
| 18181 | IrInstruction *fn_ref = pass1_fn_ref->child; | |
| 18182 | if (type_is_invalid(fn_ref->value->type)) | |
| 18183 | return ira->codegen->invalid_instruction; | |
| 18184 | IrInstruction *first_arg_ptr = nullptr; | |
| 18185 | ZigFn *fn = nullptr; | |
| 18186 | if (fn_ref->value->type->id == ZigTypeIdBoundFn) { | |
| 18187 | assert(fn_ref->value->special == ConstValSpecialStatic); | |
| 18188 | fn = fn_ref->value->data.x_bound_fn.fn; | |
| 18189 | first_arg_ptr = fn_ref->value->data.x_bound_fn.first_arg; | |
| 18190 | if (type_is_invalid(first_arg_ptr->value->type)) | |
| 18191 | return ira->codegen->invalid_instruction; | |
| 18192 | } else { | |
| 18193 | fn = ir_resolve_fn(ira, fn_ref); | |
| 18194 | } | |
| 18195 | ZigType *fn_type = (fn != nullptr) ? fn->type_entry : fn_ref->value->type; | |
| 18196 | ||
| 18197 | TypeStructField *modifier_field = find_struct_type_field(options->value->type, buf_create_from_str("modifier")); | |
| 18198 | ir_assert(modifier_field != nullptr, source_instr); | |
| 18199 | IrInstruction *modifier_inst = ir_analyze_struct_value_field_value(ira, source_instr, options, modifier_field); | |
| 18200 | ZigValue *modifier_val = ir_resolve_const(ira, modifier_inst, UndefBad); | |
| 18201 | if (modifier_val == nullptr) | |
| 18202 | return ira->codegen->invalid_instruction; | |
| 18203 | CallModifier modifier = (CallModifier)bigint_as_u32(&modifier_val->data.x_enum_tag); | |
| 18204 | if (modifier == CallModifierAsync) { | |
| 18205 | ir_add_error(ira, source_instr, buf_sprintf("TODO: @call with async modifier")); | |
| 18206 | return ira->codegen->invalid_instruction; | |
| 18207 | } | |
| 18208 | if (ir_should_inline(ira->new_irb.exec, source_instr->scope)) { | |
| 18209 | switch (modifier) { | |
| 18210 | case CallModifierBuiltin: | |
| 18211 | zig_unreachable(); | |
| 18212 | case CallModifierAsync: | |
| 18213 | ir_add_error(ira, source_instr, buf_sprintf("TODO: comptime @call with async modifier")); | |
| 18214 | return ira->codegen->invalid_instruction; | |
| 18215 | case CallModifierCompileTime: | |
| 18216 | case CallModifierNone: | |
| 18217 | case CallModifierAlwaysInline: | |
| 18218 | case CallModifierAlwaysTail: | |
| 18219 | case CallModifierNoAsync: | |
| 18220 | modifier = CallModifierCompileTime; | |
| 18221 | break; | |
| 18222 | case CallModifierNeverInline: | |
| 18223 | ir_add_error(ira, source_instr, | |
| 18224 | buf_sprintf("unable to perform 'never_inline' call at compile-time")); | |
| 18225 | return ira->codegen->invalid_instruction; | |
| 18226 | case CallModifierNeverTail: | |
| 18227 | ir_add_error(ira, source_instr, | |
| 18228 | buf_sprintf("unable to perform 'never_tail' call at compile-time")); | |
| 18229 | return ira->codegen->invalid_instruction; | |
| 18230 | } | |
| 18231 | } | |
| 18232 | ||
| 18233 | TypeStructField *stack_field = find_struct_type_field(options->value->type, buf_create_from_str("stack")); | |
| 18234 | ir_assert(stack_field != nullptr, source_instr); | |
| 18235 | IrInstruction *opt_stack = ir_analyze_struct_value_field_value(ira, source_instr, options, stack_field); | |
| 18236 | if (type_is_invalid(opt_stack->value->type)) | |
| 18237 | return ira->codegen->invalid_instruction; | |
| 18238 | IrInstruction *stack_is_non_null_inst = ir_analyze_test_non_null(ira, source_instr, opt_stack); | |
| 18239 | bool stack_is_non_null; | |
| 18240 | if (!ir_resolve_bool(ira, stack_is_non_null_inst, &stack_is_non_null)) | |
| 18241 | return ira->codegen->invalid_instruction; | |
| 18242 | IrInstruction *stack; | |
| 18243 | if (stack_is_non_null) { | |
| 18244 | stack = ir_analyze_optional_value_payload_value(ira, source_instr, opt_stack, false); | |
| 18245 | if (type_is_invalid(stack->value->type)) | |
| 18246 | return ira->codegen->invalid_instruction; | |
| 18247 | } else { | |
| 18248 | stack = nullptr; | |
| 18249 | } | |
| 18250 | ||
| 18251 | return ir_analyze_fn_call(ira, source_instr, fn, fn_type, fn_ref, first_arg_ptr, | |
| 18252 | modifier, stack, false, args_ptr, args_len, nullptr, result_loc); | |
| 18253 | } | |
| 18254 | ||
| 18255 | static IrInstruction *ir_analyze_instruction_call_extra(IrAnalyze *ira, IrInstructionCallExtra *instruction) { | |
| 18256 | IrInstruction *args = instruction->args->child; | |
| 18257 | ZigType *args_type = args->value->type; | |
| 18258 | if (type_is_invalid(args_type)) | |
| 18259 | return ira->codegen->invalid_instruction; | |
| 18260 | ||
| 18261 | if (args_type->id != ZigTypeIdStruct) { | |
| 18262 | ir_add_error(ira, args, | |
| 18263 | buf_sprintf("expected tuple or struct, found '%s'", buf_ptr(&args_type->name))); | |
| 18264 | return ira->codegen->invalid_instruction; | |
| 18265 | } | |
| 18266 | ||
| 18267 | IrInstruction **args_ptr = nullptr; | |
| 18268 | size_t args_len = 0; | |
| 18269 | ||
| 18270 | if (is_tuple(args_type)) { | |
| 18271 | args_len = args_type->data.structure.src_field_count; | |
| 18272 | args_ptr = allocate<IrInstruction *>(args_len, "IrInstruction *"); | |
| 18273 | for (size_t i = 0; i < args_len; i += 1) { | |
| 18274 | TypeStructField *arg_field = args_type->data.structure.fields[i]; | |
| 18275 | args_ptr[i] = ir_analyze_struct_value_field_value(ira, &instruction->base, args, arg_field); | |
| 18276 | if (type_is_invalid(args_ptr[i]->value->type)) | |
| 18277 | return ira->codegen->invalid_instruction; | |
| 18278 | } | |
| 18279 | } else { | |
| 18280 | ir_add_error(ira, args, buf_sprintf("TODO: struct args")); | |
| 18281 | return ira->codegen->invalid_instruction; | |
| 18282 | } | |
| 18283 | IrInstruction *result = ir_analyze_call_extra(ira, &instruction->base, instruction->options, | |
| 18284 | instruction->fn_ref, args_ptr, args_len, instruction->result_loc); | |
| 18285 | deallocate(args_ptr, args_len, "IrInstruction *"); | |
| 18286 | return result; | |
| 18287 | } | |
| 18288 | ||
| 18289 | static IrInstruction *ir_analyze_instruction_call_args(IrAnalyze *ira, IrInstructionCallSrcArgs *instruction) { | |
| 18290 | IrInstruction **args_ptr = allocate<IrInstruction *>(instruction->args_len, "IrInstruction *"); | |
| 18291 | for (size_t i = 0; i < instruction->args_len; i += 1) { | |
| 18292 | args_ptr[i] = instruction->args_ptr[i]->child; | |
| 18293 | if (type_is_invalid(args_ptr[i]->value->type)) | |
| 18294 | return ira->codegen->invalid_instruction; | |
| 18295 | } | |
| 18296 | ||
| 18297 | IrInstruction *result = ir_analyze_call_extra(ira, &instruction->base, instruction->options, | |
| 18298 | instruction->fn_ref, args_ptr, instruction->args_len, instruction->result_loc); | |
| 18299 | deallocate(args_ptr, instruction->args_len, "IrInstruction *"); | |
| 18300 | return result; | |
| 18301 | } | |
| 18302 | ||
| 18045 | 18303 | static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionCallSrc *call_instruction) { |
| 18046 | 18304 | IrInstruction *fn_ref = call_instruction->fn_ref->child; |
| 18047 | 18305 | if (type_is_invalid(fn_ref->value->type)) |
| 18048 | 18306 | return ira->codegen->invalid_instruction; |
| 18049 | 18307 | |
| 18050 | bool is_comptime = call_instruction->is_comptime || | |
| 18308 | bool is_comptime = (call_instruction->modifier == CallModifierCompileTime) || | |
| 18051 | 18309 | ir_should_inline(ira->new_irb.exec, call_instruction->base.scope); |
| 18310 | CallModifier modifier = is_comptime ? CallModifierCompileTime : call_instruction->modifier; | |
| 18052 | 18311 | |
| 18053 | 18312 | if (is_comptime || instr_is_comptime(fn_ref)) { |
| 18054 | 18313 | if (fn_ref->value->type->id == ZigTypeIdMetaType) { |
| ... | ... | @@ -18063,14 +18322,16 @@ static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionC |
| 18063 | 18322 | } else if (fn_ref->value->type->id == ZigTypeIdFn) { |
| 18064 | 18323 | ZigFn *fn_table_entry = ir_resolve_fn(ira, fn_ref); |
| 18065 | 18324 | ZigType *fn_type = fn_table_entry ? fn_table_entry->type_entry : fn_ref->value->type; |
| 18066 | return ir_analyze_fn_call(ira, call_instruction, fn_table_entry, fn_type, | |
| 18067 | fn_ref, nullptr, is_comptime, call_instruction->fn_inline); | |
| 18325 | CallModifier modifier = is_comptime ? CallModifierCompileTime : call_instruction->modifier; | |
| 18326 | return ir_analyze_fn_call_src(ira, call_instruction, fn_table_entry, fn_type, | |
| 18327 | fn_ref, nullptr, modifier); | |
| 18068 | 18328 | } else if (fn_ref->value->type->id == ZigTypeIdBoundFn) { |
| 18069 | 18329 | assert(fn_ref->value->special == ConstValSpecialStatic); |
| 18070 | 18330 | ZigFn *fn_table_entry = fn_ref->value->data.x_bound_fn.fn; |
| 18071 | 18331 | IrInstruction *first_arg_ptr = fn_ref->value->data.x_bound_fn.first_arg; |
| 18072 | return ir_analyze_fn_call(ira, call_instruction, fn_table_entry, fn_table_entry->type_entry, | |
| 18073 | fn_ref, first_arg_ptr, is_comptime, call_instruction->fn_inline); | |
| 18332 | CallModifier modifier = is_comptime ? CallModifierCompileTime : call_instruction->modifier; | |
| 18333 | return ir_analyze_fn_call_src(ira, call_instruction, fn_table_entry, fn_table_entry->type_entry, | |
| 18334 | fn_ref, first_arg_ptr, modifier); | |
| 18074 | 18335 | } else { |
| 18075 | 18336 | ir_add_error_node(ira, fn_ref->source_node, |
| 18076 | 18337 | buf_sprintf("type '%s' not a function", buf_ptr(&fn_ref->value->type->name))); |
| ... | ... | @@ -18079,8 +18340,8 @@ static IrInstruction *ir_analyze_instruction_call(IrAnalyze *ira, IrInstructionC |
| 18079 | 18340 | } |
| 18080 | 18341 | |
| 18081 | 18342 | if (fn_ref->value->type->id == ZigTypeIdFn) { |
| 18082 | return ir_analyze_fn_call(ira, call_instruction, nullptr, fn_ref->value->type, | |
| 18083 | fn_ref, nullptr, false, call_instruction->fn_inline); | |
| 18343 | return ir_analyze_fn_call_src(ira, call_instruction, nullptr, fn_ref->value->type, | |
| 18344 | fn_ref, nullptr, modifier); | |
| 18084 | 18345 | } else { |
| 18085 | 18346 | ir_add_error_node(ira, fn_ref->source_node, |
| 18086 | 18347 | buf_sprintf("type '%s' not a function", buf_ptr(&fn_ref->value->type->name))); |
| ... | ... | @@ -19356,8 +19617,18 @@ static IrInstruction *ir_analyze_inferred_field_ptr(IrAnalyze *ira, Buf *field_n |
| 19356 | 19617 | PtrLenSingle, 0, 0, 0, false, VECTOR_INDEX_NONE, inferred_struct_field, nullptr); |
| 19357 | 19618 | |
| 19358 | 19619 | if (instr_is_comptime(container_ptr)) { |
| 19359 | IrInstruction *result = ir_const(ira, source_instr, field_ptr_type); | |
| 19360 | copy_const_val(result->value, container_ptr->value); | |
| 19620 | ZigValue *ptr_val = ir_resolve_const(ira, container_ptr, UndefBad); | |
| 19621 | if (ptr_val == nullptr) | |
| 19622 | return ira->codegen->invalid_instruction; | |
| 19623 | ||
| 19624 | IrInstruction *result; | |
| 19625 | if (ptr_val->data.x_ptr.mut == ConstPtrMutInfer) { | |
| 19626 | result = ir_build_cast(&ira->new_irb, source_instr->scope, | |
| 19627 | source_instr->source_node, container_ptr_type, container_ptr, CastOpNoop); | |
| 19628 | } else { | |
| 19629 | result = ir_const(ira, source_instr, field_ptr_type); | |
| 19630 | } | |
| 19631 | copy_const_val(result->value, ptr_val); | |
| 19361 | 19632 | result->value->type = field_ptr_type; |
| 19362 | 19633 | return result; |
| 19363 | 19634 | } |
| ... | ... | @@ -20374,20 +20645,6 @@ static IrInstruction *ir_analyze_instruction_test_non_null(IrAnalyze *ira, IrIns |
| 20374 | 20645 | return ir_analyze_test_non_null(ira, &instruction->base, value); |
| 20375 | 20646 | } |
| 20376 | 20647 | |
| 20377 | static ZigType *get_ptr_elem_type(CodeGen *g, IrInstruction *ptr) { | |
| 20378 | ir_assert(ptr->value->type->id == ZigTypeIdPointer, ptr); | |
| 20379 | ZigType *elem_type = ptr->value->type->data.pointer.child_type; | |
| 20380 | if (elem_type != g->builtin_types.entry_var) | |
| 20381 | return elem_type; | |
| 20382 | ||
| 20383 | if (ir_resolve_lazy(g, ptr->source_node, ptr->value)) | |
| 20384 | return g->builtin_types.entry_invalid; | |
| 20385 | ||
| 20386 | assert(value_is_comptime(ptr->value)); | |
| 20387 | ZigValue *pointee = const_ptr_pointee_unchecked(g, ptr->value); | |
| 20388 | return pointee->type; | |
| 20389 | } | |
| 20390 | ||
| 20391 | 20648 | static IrInstruction *ir_analyze_unwrap_optional_payload(IrAnalyze *ira, IrInstruction *source_instr, |
| 20392 | 20649 | IrInstruction *base_ptr, bool safety_check_on, bool initializing) |
| 20393 | 20650 | { |
| ... | ... | @@ -21796,9 +22053,7 @@ static void ensure_field_index(ZigType *type, const char *field_name, size_t ind |
| 21796 | 22053 | |
| 21797 | 22054 | static ZigType *ir_type_info_get_type(IrAnalyze *ira, const char *type_name, ZigType *root) { |
| 21798 | 22055 | Error err; |
| 21799 | ZigValue *type_info_var = get_builtin_value(ira->codegen, "TypeInfo"); | |
| 21800 | assert(type_info_var->type->id == ZigTypeIdMetaType); | |
| 21801 | ZigType *type_info_type = type_info_var->data.x_type; | |
| 22056 | ZigType *type_info_type = get_builtin_type(ira->codegen, "TypeInfo"); | |
| 21802 | 22057 | assert(type_info_type->id == ZigTypeIdUnion); |
| 21803 | 22058 | if ((err = type_resolve(ira->codegen, type_info_type, ResolveStatusSizeKnown))) { |
| 21804 | 22059 | zig_unreachable(); |
| ... | ... | @@ -23034,9 +23289,7 @@ static IrInstruction *ir_analyze_instruction_type_id(IrAnalyze *ira, |
| 23034 | 23289 | if (type_is_invalid(type_entry)) |
| 23035 | 23290 | return ira->codegen->invalid_instruction; |
| 23036 | 23291 | |
| 23037 | ZigValue *var_value = get_builtin_value(ira->codegen, "TypeId"); | |
| 23038 | assert(var_value->type->id == ZigTypeIdMetaType); | |
| 23039 | ZigType *result_type = var_value->data.x_type; | |
| 23292 | ZigType *result_type = get_builtin_type(ira->codegen, "TypeId"); | |
| 23040 | 23293 | |
| 23041 | 23294 | IrInstruction *result = ir_const(ira, &instruction->base, result_type); |
| 23042 | 23295 | bigint_init_unsigned(&result->value->data.x_enum_tag, type_id_index(type_entry)); |
| ... | ... | @@ -27787,6 +28040,10 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction |
| 27787 | 28040 | return ir_analyze_instruction_field_ptr(ira, (IrInstructionFieldPtr *)instruction); |
| 27788 | 28041 | case IrInstructionIdCallSrc: |
| 27789 | 28042 | return ir_analyze_instruction_call(ira, (IrInstructionCallSrc *)instruction); |
| 28043 | case IrInstructionIdCallSrcArgs: | |
| 28044 | return ir_analyze_instruction_call_args(ira, (IrInstructionCallSrcArgs *)instruction); | |
| 28045 | case IrInstructionIdCallExtra: | |
| 28046 | return ir_analyze_instruction_call_extra(ira, (IrInstructionCallExtra *)instruction); | |
| 27790 | 28047 | case IrInstructionIdBr: |
| 27791 | 28048 | return ir_analyze_instruction_br(ira, (IrInstructionBr *)instruction); |
| 27792 | 28049 | case IrInstructionIdCondBr: |
| ... | ... | @@ -28184,7 +28441,9 @@ bool ir_has_side_effects(IrInstruction *instruction) { |
| 28184 | 28441 | case IrInstructionIdDeclVarGen: |
| 28185 | 28442 | case IrInstructionIdStorePtr: |
| 28186 | 28443 | case IrInstructionIdVectorStoreElem: |
| 28444 | case IrInstructionIdCallExtra: | |
| 28187 | 28445 | case IrInstructionIdCallSrc: |
| 28446 | case IrInstructionIdCallSrcArgs: | |
| 28188 | 28447 | case IrInstructionIdCallGen: |
| 28189 | 28448 | case IrInstructionIdReturn: |
| 28190 | 28449 | case IrInstructionIdUnreachable: |
src/ir_print.cpp+71-4| ... | ... | @@ -92,8 +92,12 @@ const char* ir_instruction_type_str(IrInstructionId id) { |
| 92 | 92 | return "VarPtr"; |
| 93 | 93 | case IrInstructionIdReturnPtr: |
| 94 | 94 | return "ReturnPtr"; |
| 95 | case IrInstructionIdCallExtra: | |
| 96 | return "CallExtra"; | |
| 95 | 97 | case IrInstructionIdCallSrc: |
| 96 | 98 | return "CallSrc"; |
| 99 | case IrInstructionIdCallSrcArgs: | |
| 100 | return "CallSrcArgs"; | |
| 97 | 101 | case IrInstructionIdCallGen: |
| 98 | 102 | return "CallGen"; |
| 99 | 103 | case IrInstructionIdConst: |
| ... | ... | @@ -636,15 +640,57 @@ static void ir_print_result_loc(IrPrint *irp, ResultLoc *result_loc) { |
| 636 | 640 | zig_unreachable(); |
| 637 | 641 | } |
| 638 | 642 | |
| 643 | static void ir_print_call_extra(IrPrint *irp, IrInstructionCallExtra *instruction) { | |
| 644 | fprintf(irp->f, "opts="); | |
| 645 | ir_print_other_instruction(irp, instruction->options); | |
| 646 | fprintf(irp->f, ", fn="); | |
| 647 | ir_print_other_instruction(irp, instruction->fn_ref); | |
| 648 | fprintf(irp->f, ", args="); | |
| 649 | ir_print_other_instruction(irp, instruction->args); | |
| 650 | fprintf(irp->f, ", result="); | |
| 651 | ir_print_result_loc(irp, instruction->result_loc); | |
| 652 | } | |
| 653 | ||
| 654 | static void ir_print_call_src_args(IrPrint *irp, IrInstructionCallSrcArgs *instruction) { | |
| 655 | fprintf(irp->f, "opts="); | |
| 656 | ir_print_other_instruction(irp, instruction->options); | |
| 657 | fprintf(irp->f, ", fn="); | |
| 658 | ir_print_other_instruction(irp, instruction->fn_ref); | |
| 659 | fprintf(irp->f, ", args=("); | |
| 660 | for (size_t i = 0; i < instruction->args_len; i += 1) { | |
| 661 | IrInstruction *arg = instruction->args_ptr[i]; | |
| 662 | if (i != 0) | |
| 663 | fprintf(irp->f, ", "); | |
| 664 | ir_print_other_instruction(irp, arg); | |
| 665 | } | |
| 666 | fprintf(irp->f, "), result="); | |
| 667 | ir_print_result_loc(irp, instruction->result_loc); | |
| 668 | } | |
| 669 | ||
| 639 | 670 | static void ir_print_call_src(IrPrint *irp, IrInstructionCallSrc *call_instruction) { |
| 640 | 671 | switch (call_instruction->modifier) { |
| 641 | 672 | case CallModifierNone: |
| 642 | 673 | break; |
| 674 | case CallModifierNoAsync: | |
| 675 | fprintf(irp->f, "noasync "); | |
| 676 | break; | |
| 643 | 677 | case CallModifierAsync: |
| 644 | 678 | fprintf(irp->f, "async "); |
| 645 | 679 | break; |
| 646 | case CallModifierNoAsync: | |
| 647 | fprintf(irp->f, "noasync "); | |
| 680 | case CallModifierNeverTail: | |
| 681 | fprintf(irp->f, "notail "); | |
| 682 | break; | |
| 683 | case CallModifierNeverInline: | |
| 684 | fprintf(irp->f, "noinline "); | |
| 685 | break; | |
| 686 | case CallModifierAlwaysTail: | |
| 687 | fprintf(irp->f, "tail "); | |
| 688 | break; | |
| 689 | case CallModifierAlwaysInline: | |
| 690 | fprintf(irp->f, "inline "); | |
| 691 | break; | |
| 692 | case CallModifierCompileTime: | |
| 693 | fprintf(irp->f, "comptime "); | |
| 648 | 694 | break; |
| 649 | 695 | case CallModifierBuiltin: |
| 650 | 696 | zig_unreachable(); |
| ... | ... | @@ -670,11 +716,26 @@ static void ir_print_call_gen(IrPrint *irp, IrInstructionCallGen *call_instructi |
| 670 | 716 | switch (call_instruction->modifier) { |
| 671 | 717 | case CallModifierNone: |
| 672 | 718 | break; |
| 719 | case CallModifierNoAsync: | |
| 720 | fprintf(irp->f, "noasync "); | |
| 721 | break; | |
| 673 | 722 | case CallModifierAsync: |
| 674 | 723 | fprintf(irp->f, "async "); |
| 675 | 724 | break; |
| 676 | case CallModifierNoAsync: | |
| 677 | fprintf(irp->f, "noasync "); | |
| 725 | case CallModifierNeverTail: | |
| 726 | fprintf(irp->f, "notail "); | |
| 727 | break; | |
| 728 | case CallModifierNeverInline: | |
| 729 | fprintf(irp->f, "noinline "); | |
| 730 | break; | |
| 731 | case CallModifierAlwaysTail: | |
| 732 | fprintf(irp->f, "tail "); | |
| 733 | break; | |
| 734 | case CallModifierAlwaysInline: | |
| 735 | fprintf(irp->f, "inline "); | |
| 736 | break; | |
| 737 | case CallModifierCompileTime: | |
| 738 | fprintf(irp->f, "comptime "); | |
| 678 | 739 | break; |
| 679 | 740 | case CallModifierBuiltin: |
| 680 | 741 | zig_unreachable(); |
| ... | ... | @@ -2082,9 +2143,15 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction, bool |
| 2082 | 2143 | case IrInstructionIdCast: |
| 2083 | 2144 | ir_print_cast(irp, (IrInstructionCast *)instruction); |
| 2084 | 2145 | break; |
| 2146 | case IrInstructionIdCallExtra: | |
| 2147 | ir_print_call_extra(irp, (IrInstructionCallExtra *)instruction); | |
| 2148 | break; | |
| 2085 | 2149 | case IrInstructionIdCallSrc: |
| 2086 | 2150 | ir_print_call_src(irp, (IrInstructionCallSrc *)instruction); |
| 2087 | 2151 | break; |
| 2152 | case IrInstructionIdCallSrcArgs: | |
| 2153 | ir_print_call_src_args(irp, (IrInstructionCallSrcArgs *)instruction); | |
| 2154 | break; | |
| 2088 | 2155 | case IrInstructionIdCallGen: |
| 2089 | 2156 | ir_print_call_gen(irp, (IrInstructionCallGen *)instruction); |
| 2090 | 2157 | break; |
src/zig_llvm.cpp+12-6| ... | ... | @@ -269,19 +269,25 @@ ZIG_EXTERN_C LLVMTypeRef ZigLLVMTokenTypeInContext(LLVMContextRef context_ref) { |
| 269 | 269 | } |
| 270 | 270 | |
| 271 | 271 | LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args, |
| 272 | unsigned NumArgs, unsigned CC, ZigLLVM_FnInline fn_inline, const char *Name) | |
| 272 | unsigned NumArgs, unsigned CC, ZigLLVM_CallAttr attr, const char *Name) | |
| 273 | 273 | { |
| 274 | 274 | CallInst *call_inst = CallInst::Create(unwrap(Fn), makeArrayRef(unwrap(Args), NumArgs), Name); |
| 275 | 275 | call_inst->setCallingConv(CC); |
| 276 | switch (fn_inline) { | |
| 277 | case ZigLLVM_FnInlineAuto: | |
| 276 | switch (attr) { | |
| 277 | case ZigLLVM_CallAttrAuto: | |
| 278 | 278 | break; |
| 279 | case ZigLLVM_FnInlineAlways: | |
| 280 | call_inst->addAttribute(AttributeList::FunctionIndex, Attribute::AlwaysInline); | |
| 279 | case ZigLLVM_CallAttrNeverTail: | |
| 280 | call_inst->setTailCallKind(CallInst::TCK_NoTail); | |
| 281 | 281 | break; |
| 282 | case ZigLLVM_FnInlineNever: | |
| 282 | case ZigLLVM_CallAttrNeverInline: | |
| 283 | 283 | call_inst->addAttribute(AttributeList::FunctionIndex, Attribute::NoInline); |
| 284 | 284 | break; |
| 285 | case ZigLLVM_CallAttrAlwaysTail: | |
| 286 | call_inst->setTailCallKind(CallInst::TCK_MustTail); | |
| 287 | break; | |
| 288 | case ZigLLVM_CallAttrAlwaysInline: | |
| 289 | call_inst->addAttribute(AttributeList::FunctionIndex, Attribute::AlwaysInline); | |
| 290 | break; | |
| 285 | 291 | } |
| 286 | 292 | return wrap(unwrap(B)->Insert(call_inst)); |
| 287 | 293 | } |
src/zig_llvm.h+7-5| ... | ... | @@ -64,13 +64,15 @@ ZIG_EXTERN_C LLVMTargetMachineRef ZigLLVMCreateTargetMachine(LLVMTargetRef T, co |
| 64 | 64 | |
| 65 | 65 | ZIG_EXTERN_C LLVMTypeRef ZigLLVMTokenTypeInContext(LLVMContextRef context_ref); |
| 66 | 66 | |
| 67 | enum ZigLLVM_FnInline { | |
| 68 | ZigLLVM_FnInlineAuto, | |
| 69 | ZigLLVM_FnInlineAlways, | |
| 70 | ZigLLVM_FnInlineNever, | |
| 67 | enum ZigLLVM_CallAttr { | |
| 68 | ZigLLVM_CallAttrAuto, | |
| 69 | ZigLLVM_CallAttrNeverTail, | |
| 70 | ZigLLVM_CallAttrNeverInline, | |
| 71 | ZigLLVM_CallAttrAlwaysTail, | |
| 72 | ZigLLVM_CallAttrAlwaysInline, | |
| 71 | 73 | }; |
| 72 | 74 | ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildCall(LLVMBuilderRef B, LLVMValueRef Fn, LLVMValueRef *Args, |
| 73 | unsigned NumArgs, unsigned CC, enum ZigLLVM_FnInline fn_inline, const char *Name); | |
| 75 | unsigned NumArgs, unsigned CC, enum ZigLLVM_CallAttr attr, const char *Name); | |
| 74 | 76 | |
| 75 | 77 | ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign, |
| 76 | 78 | LLVMValueRef Src, unsigned SrcAlign, LLVMValueRef Size, bool isVolatile); |
test/compile_errors.zig+34-15| ... | ... | @@ -2,6 +2,36 @@ const tests = @import("tests.zig"); |
| 2 | 2 | const builtin = @import("builtin"); |
| 3 | 3 | |
| 4 | 4 | pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 5 | cases.add( | |
| 6 | "bad usage of @call", | |
| 7 | \\export fn entry1() void { | |
| 8 | \\ @call(.{}, foo, {}); | |
| 9 | \\} | |
| 10 | \\export fn entry2() void { | |
| 11 | \\ comptime @call(.{ .modifier = .never_inline }, foo, .{}); | |
| 12 | \\} | |
| 13 | \\export fn entry3() void { | |
| 14 | \\ comptime @call(.{ .modifier = .never_tail }, foo, .{}); | |
| 15 | \\} | |
| 16 | \\export fn entry4() void { | |
| 17 | \\ @call(.{ .modifier = .never_inline }, bar, .{}); | |
| 18 | \\} | |
| 19 | \\export fn entry5(c: bool) void { | |
| 20 | \\ var baz = if (c) baz1 else baz2; | |
| 21 | \\ @call(.{ .modifier = .compile_time }, baz, .{}); | |
| 22 | \\} | |
| 23 | \\fn foo() void {} | |
| 24 | \\inline fn bar() void {} | |
| 25 | \\fn baz1() void {} | |
| 26 | \\fn baz2() void {} | |
| 27 | , | |
| 28 | "tmp.zig:2:21: error: expected tuple or struct, found 'void'", | |
| 29 | "tmp.zig:5:14: error: unable to perform 'never_inline' call at compile-time", | |
| 30 | "tmp.zig:8:14: error: unable to perform 'never_tail' call at compile-time", | |
| 31 | "tmp.zig:11:5: error: no-inline call of inline function", | |
| 32 | "tmp.zig:15:43: error: unable to evaluate constant expression", | |
| 33 | ); | |
| 34 | ||
| 5 | 35 | cases.add( |
| 6 | 36 | \\export async fn foo() void {} |
| 7 | 37 | , "tmp.zig:1:1: error: exported function cannot be async"); |
| ... | ... | @@ -14,13 +44,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 14 | 44 | ); |
| 15 | 45 | |
| 16 | 46 | cases.addCase(x: { |
| 17 | var tc = cases.create("@newStackCall on unsupported target", | |
| 47 | var tc = cases.create("call with new stack on unsupported target", | |
| 48 | \\var buf: [10]u8 align(16) = undefined; | |
| 18 | 49 | \\export fn entry() void { |
| 19 | \\ var buf: [10]u8 align(16) = undefined; | |
| 20 | \\ @newStackCall(&buf, foo); | |
| 50 | \\ @call(.{.stack = &buf}, foo, .{}); | |
| 21 | 51 | \\} |
| 22 | 52 | \\fn foo() void {} |
| 23 | , "tmp.zig:3:5: error: target arch 'wasm32' does not support @newStackCall"); | |
| 53 | , "tmp.zig:3:5: error: target arch 'wasm32' does not support calling with a new stack"); | |
| 24 | 54 | tc.target = tests.Target{ |
| 25 | 55 | .Cross = tests.CrossTarget{ |
| 26 | 56 | .arch = .wasm32, |
| ... | ... | @@ -1927,17 +1957,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 1927 | 1957 | "tmp.zig:2:12: error: use of undeclared identifier 'SomeNonexistentType'", |
| 1928 | 1958 | ); |
| 1929 | 1959 | |
| 1930 | cases.add( | |
| 1931 | "@noInlineCall on an inline function", | |
| 1932 | \\inline fn foo() void {} | |
| 1933 | \\ | |
| 1934 | \\export fn entry() void { | |
| 1935 | \\ @noInlineCall(foo); | |
| 1936 | \\} | |
| 1937 | , | |
| 1938 | "tmp.zig:4:5: error: no-inline call of inline function", | |
| 1939 | ); | |
| 1940 | ||
| 1941 | 1960 | cases.add( |
| 1942 | 1961 | "comptime continue inside runtime catch", |
| 1943 | 1962 | \\export fn entry(c: bool) void { |
test/stage1/behavior.zig+1| ... | ... | @@ -52,6 +52,7 @@ comptime { |
| 52 | 52 | _ = @import("behavior/bugs/920.zig"); |
| 53 | 53 | _ = @import("behavior/byteswap.zig"); |
| 54 | 54 | _ = @import("behavior/byval_arg_var.zig"); |
| 55 | _ = @import("behavior/call.zig"); | |
| 55 | 56 | _ = @import("behavior/cast.zig"); |
| 56 | 57 | _ = @import("behavior/const_slice_child.zig"); |
| 57 | 58 | _ = @import("behavior/defer.zig"); |
test/stage1/behavior/call.zig created+48| ... | ... | @@ -0,0 +1,48 @@ |
| 1 | const std = @import("std"); | |
| 2 | const expect = std.testing.expect; | |
| 3 | ||
| 4 | test "basic invocations" { | |
| 5 | const foo = struct { | |
| 6 | fn foo() i32 { | |
| 7 | return 1234; | |
| 8 | } | |
| 9 | }.foo; | |
| 10 | expect(@call(.{}, foo, .{}) == 1234); | |
| 11 | comptime { | |
| 12 | // modifiers that allow comptime calls | |
| 13 | expect(@call(.{}, foo, .{}) == 1234); | |
| 14 | expect(@call(.{ .modifier = .no_async }, foo, .{}) == 1234); | |
| 15 | expect(@call(.{ .modifier = .always_tail }, foo, .{}) == 1234); | |
| 16 | expect(@call(.{ .modifier = .always_inline }, foo, .{}) == 1234); | |
| 17 | } | |
| 18 | { | |
| 19 | // comptime call without comptime keyword | |
| 20 | const result = @call(.{ .modifier = .compile_time }, foo, .{}) == 1234; | |
| 21 | comptime expect(result); | |
| 22 | } | |
| 23 | } | |
| 24 | ||
| 25 | test "tuple parameters" { | |
| 26 | const add = struct { | |
| 27 | fn add(a: i32, b: i32) i32 { | |
| 28 | return a + b; | |
| 29 | } | |
| 30 | }.add; | |
| 31 | var a: i32 = 12; | |
| 32 | var b: i32 = 34; | |
| 33 | expect(@call(.{}, add, .{ a, 34 }) == 46); | |
| 34 | expect(@call(.{}, add, .{ 12, b }) == 46); | |
| 35 | expect(@call(.{}, add, .{ a, b }) == 46); | |
| 36 | expect(@call(.{}, add, .{ 12, 34 }) == 46); | |
| 37 | comptime expect(@call(.{}, add, .{ 12, 34 }) == 46); | |
| 38 | { | |
| 39 | const separate_args0 = .{ a, b }; | |
| 40 | //TODO const separate_args1 = .{ a, 34 }; | |
| 41 | const separate_args2 = .{ 12, 34 }; | |
| 42 | //TODO const separate_args3 = .{ 12, b }; | |
| 43 | expect(@call(.{ .modifier = .always_inline }, add, separate_args0) == 46); | |
| 44 | // TODO expect(@call(.{ .modifier = .always_inline }, add, separate_args1) == 46); | |
| 45 | expect(@call(.{ .modifier = .always_inline }, add, separate_args2) == 46); | |
| 46 | // TODO expect(@call(.{ .modifier = .always_inline }, add, separate_args3) == 46); | |
| 47 | } | |
| 48 | } |
test/stage1/behavior/fn.zig+1-9| ... | ... | @@ -96,14 +96,6 @@ fn fn4() u32 { |
| 96 | 96 | return 8; |
| 97 | 97 | } |
| 98 | 98 | |
| 99 | test "inline function call" { | |
| 100 | expect(@inlineCall(add, 3, 9) == 12); | |
| 101 | } | |
| 102 | ||
| 103 | fn add(a: i32, b: i32) i32 { | |
| 104 | return a + b; | |
| 105 | } | |
| 106 | ||
| 107 | 99 | test "number literal as an argument" { |
| 108 | 100 | numberLiteralArg(3); |
| 109 | 101 | comptime numberLiteralArg(3); |
| ... | ... | @@ -251,7 +243,7 @@ test "discard the result of a function that returns a struct" { |
| 251 | 243 | test "function call with anon list literal" { |
| 252 | 244 | const S = struct { |
| 253 | 245 | fn doTheTest() void { |
| 254 | consumeVec(.{9, 8, 7}); | |
| 246 | consumeVec(.{ 9, 8, 7 }); | |
| 255 | 247 | } |
| 256 | 248 | |
| 257 | 249 | fn consumeVec(vec: [3]f32) void { |
test/stage1/behavior/new_stack_call.zig+2-2| ... | ... | @@ -18,8 +18,8 @@ test "calling a function with a new stack" { |
| 18 | 18 | |
| 19 | 19 | const arg = 1234; |
| 20 | 20 | |
| 21 | const a = @newStackCall(new_stack_bytes[0..512], targetFunction, arg); | |
| 22 | const b = @newStackCall(new_stack_bytes[512..], targetFunction, arg); | |
| 21 | const a = @call(.{ .stack = new_stack_bytes[0..512] }, targetFunction, .{arg}); | |
| 22 | const b = @call(.{ .stack = new_stack_bytes[512..] }, targetFunction, .{arg}); | |
| 23 | 23 | _ = targetFunction(arg); |
| 24 | 24 | |
| 25 | 25 | expect(arg == 1234); |