Commit 71b7f4b47f
Changed files (6)
lib
std
special
src
src-self-hosted
test
stage1
behavior
doc/langref.html.in
@@ -6904,6 +6904,41 @@ pub const CallOptions = struct {
};
};
{#code_end#}
+
+ {#header_open|Calling with a New Stack#}
+ <p>
+ When the {#syntax#}stack{#endsyntax#} option is provided, instead of using the same stack as the caller, the function uses the provided stack.
+ </p>
+ {#code_begin|test|new_stack_call#}
+const std = @import("std");
+const assert = std.debug.assert;
+
+var new_stack_bytes: [1024]u8 align(16) = undefined;
+
+test "calling a function with a new stack" {
+ const arg = 1234;
+
+ const a = @call(.{.stack = new_stack_bytes[0..512]}, targetFunction, .{arg});
+ const b = @call(.{.stack = new_stack_bytes[512..]}, targetFunction, .{arg});
+ _ = targetFunction(arg);
+
+ assert(arg == 1234);
+ assert(a < b);
+}
+
+fn targetFunction(x: i32) usize {
+ assert(x == 1234);
+
+ var local_variable: i32 = 42;
+ const ptr = &local_variable;
+ ptr.* += 1;
+
+ assert(local_variable == 43);
+ return @ptrToInt(ptr);
+}
+ {#code_end#}
+ {#header_close#}
+
{#header_close#}
{#header_open|@cDefine#}
@@ -7649,48 +7684,6 @@ mem.set(u8, dest, c);{#endsyntax#}</pre>
</p>
{#header_close#}
- {#header_open|@newStackCall#}
- <pre>{#syntax#}@newStackCall(new_stack: []align(target_stack_align) u8, function: var, args: ...) var{#endsyntax#}</pre>
- <p>
- This calls a function, in the same way that invoking an expression with parentheses does. However,
- instead of using the same stack as the caller, the function uses the stack provided in the {#syntax#}new_stack{#endsyntax#}
- parameter.
- </p>
- <p>
- The new stack must be aligned to {#syntax#}target_stack_align{#endsyntax#} bytes. This is a target-specific
- number. A safe value that will work on all targets is {#syntax#}16{#endsyntax#}. This value can
- also be obtained by using {#link|@sizeOf#} on the {#link|@Frame#} type of {#link|Async Functions#}.
- </p>
- {#code_begin|test#}
-const std = @import("std");
-const assert = std.debug.assert;
-
-var new_stack_bytes: [1024]u8 align(16) = undefined;
-
-test "calling a function with a new stack" {
- const arg = 1234;
-
- const a = @newStackCall(new_stack_bytes[0..512], targetFunction, arg);
- const b = @newStackCall(new_stack_bytes[512..], targetFunction, arg);
- _ = targetFunction(arg);
-
- assert(arg == 1234);
- assert(a < b);
-}
-
-fn targetFunction(x: i32) usize {
- assert(x == 1234);
-
- var local_variable: i32 = 42;
- const ptr = &local_variable;
- ptr.* += 1;
-
- assert(local_variable == 43);
- return @ptrToInt(ptr);
-}
- {#code_end#}
- {#header_close#}
-
{#header_open|@OpaqueType#}
<pre>{#syntax#}@OpaqueType() type{#endsyntax#}</pre>
<p>
lib/std/special/start.zig
@@ -184,7 +184,7 @@ fn posixCallMainAndExit() noreturn {
// 0,
//) catch @panic("out of memory");
//std.os.mprotect(new_stack[0..std.mem.page_size], std.os.PROT_NONE) catch {};
- //std.os.exit(@newStackCall(new_stack, callMainWithArgs, argc, argv, envp));
+ //std.os.exit(@call(.{.stack = new_stack}, callMainWithArgs, .{argc, argv, envp}));
}
std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp }));
src/ir.cpp
@@ -13358,6 +13358,15 @@ static IrInstruction *ir_analyze_struct_value_field_value(IrAnalyze *ira, IrInst
return ir_get_deref(ira, source_instr, field_ptr, nullptr);
}
+static IrInstruction *ir_analyze_optional_value_payload_value(IrAnalyze *ira, IrInstruction *source_instr,
+ IrInstruction *optional_operand, bool safety_check_on)
+{
+ IrInstruction *opt_ptr = ir_get_ref(ira, source_instr, optional_operand, true, false);
+ IrInstruction *payload_ptr = ir_analyze_unwrap_optional_payload(ira, source_instr, opt_ptr,
+ safety_check_on, false);
+ return ir_get_deref(ira, source_instr, payload_ptr, nullptr);
+}
+
static IrInstruction *ir_analyze_cast(IrAnalyze *ira, IrInstruction *source_instr,
ZigType *wanted_type, IrInstruction *value)
{
@@ -17521,7 +17530,7 @@ static IrInstruction *analyze_casted_new_stack(IrAnalyze *ira, IrInstruction *so
arch_stack_pointer_register_name(ira->codegen->zig_target->arch) == nullptr)
{
ir_add_error(ira, source_instr,
- buf_sprintf("target arch '%s' does not support @newStackCall",
+ buf_sprintf("target arch '%s' does not support calling with a new stack",
target_arch_name(ira->codegen->zig_target->arch)));
}
@@ -18223,13 +18232,21 @@ static IrInstruction *ir_analyze_call_extra(IrAnalyze *ira, IrInstruction *sourc
TypeStructField *stack_field = find_struct_type_field(options->value->type, buf_create_from_str("stack"));
ir_assert(stack_field != nullptr, source_instr);
- IrInstruction *stack = ir_analyze_struct_value_field_value(ira, source_instr, options, stack_field);
- IrInstruction *stack_is_non_null_inst = ir_analyze_test_non_null(ira, source_instr, stack);
+ IrInstruction *opt_stack = ir_analyze_struct_value_field_value(ira, source_instr, options, stack_field);
+ if (type_is_invalid(opt_stack->value->type))
+ return ira->codegen->invalid_instruction;
+ IrInstruction *stack_is_non_null_inst = ir_analyze_test_non_null(ira, source_instr, opt_stack);
bool stack_is_non_null;
if (!ir_resolve_bool(ira, stack_is_non_null_inst, &stack_is_non_null))
return ira->codegen->invalid_instruction;
- if (!stack_is_non_null)
+ IrInstruction *stack;
+ if (stack_is_non_null) {
+ stack = ir_analyze_optional_value_payload_value(ira, source_instr, opt_stack, false);
+ if (type_is_invalid(stack->value->type))
+ return ira->codegen->invalid_instruction;
+ } else {
stack = nullptr;
+ }
return ir_analyze_fn_call(ira, source_instr, fn, fn_type, fn_ref, first_arg_ptr,
modifier, stack, false, args_ptr, args_len, nullptr, result_loc);
src-self-hosted/ir.zig
@@ -321,7 +321,7 @@ pub const Inst = struct {
}
const llvm_cc = llvm.CCallConv;
- const fn_inline = llvm.FnInline.Auto;
+ const call_attr = llvm.CallAttr.Auto;
return llvm.BuildCall(
ofile.builder,
@@ -329,7 +329,7 @@ pub const Inst = struct {
args.ptr,
@intCast(c_uint, args.len),
llvm_cc,
- fn_inline,
+ call_attr,
"",
) orelse error.OutOfMemory;
}
test/stage1/behavior/new_stack_call.zig
@@ -18,8 +18,8 @@ test "calling a function with a new stack" {
const arg = 1234;
- const a = @newStackCall(new_stack_bytes[0..512], targetFunction, arg);
- const b = @newStackCall(new_stack_bytes[512..], targetFunction, arg);
+ const a = @call(.{ .stack = new_stack_bytes[0..512] }, targetFunction, .{arg});
+ const b = @call(.{ .stack = new_stack_bytes[512..] }, targetFunction, .{arg});
_ = targetFunction(arg);
expect(arg == 1234);
test/compile_errors.zig
@@ -26,8 +26,8 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
\\fn baz2() void {}
,
"tmp.zig:2:21: error: expected tuple or struct, found 'void'",
- "tmp.zig:5:58: error: unable to perform 'never_inline' call at compile-time",
- "tmp.zig:8:56: error: unable to perform 'never_tail' call at compile-time",
+ "tmp.zig:5:14: error: unable to perform 'never_inline' call at compile-time",
+ "tmp.zig:8:14: error: unable to perform 'never_tail' call at compile-time",
"tmp.zig:11:5: error: no-inline call of inline function",
"tmp.zig:15:43: error: unable to evaluate constant expression",
);
@@ -44,13 +44,13 @@ pub fn addCases(cases: *tests.CompileErrorContext) void {
);
cases.addCase(x: {
- var tc = cases.create("@newStackCall on unsupported target",
+ var tc = cases.create("call with new stack on unsupported target",
\\export fn entry() void {
\\ var buf: [10]u8 align(16) = undefined;
- \\ @newStackCall(&buf, foo);
+ \\ @call(.{.stack = &buf}, foo);
\\}
\\fn foo() void {}
- , "tmp.zig:3:5: error: target arch 'wasm32' does not support @newStackCall");
+ , "tmp.zig:3:5: error: target arch 'wasm32' does not support calling with a new stack");
tc.target = tests.Target{
.Cross = tests.CrossTarget{
.arch = .wasm32,