builtinCall
Function parameters
Parameters
- gz:*GenZir
- scope:*Scope
- node:Ast.Node.Index
- params:[]const Ast.Node.Index
- allow_branch_hint:bool
Functions in this namespace
Functions
Source
Implementation
fn builtinCall(
gz: *GenZir,
scope: *Scope,
ri: ResultInfo,
node: Ast.Node.Index,
params: []const Ast.Node.Index,
allow_branch_hint: bool,
) InnerError!Zir.Inst.Ref {
const astgen = gz.astgen;
const tree = astgen.tree;
const builtin_token = tree.nodeMainToken(node);
const builtin_name = tree.tokenSlice(builtin_token);
// We handle the different builtins manually because they have different semantics depending
// on the function. For example, `@as` and others participate in result location semantics,
// and `@cImport` creates a special scope that collects a .c source code text buffer.
// Also, some builtins have a variable number of parameters.
const info = BuiltinFn.list.get(builtin_name) orelse {
return astgen.failNode(node, "invalid builtin function: '{s}'", .{
builtin_name,
});
};
if (info.param_count) |expected| {
if (expected != params.len) {
const s = if (expected == 1) "" else "s";
return astgen.failNode(node, "expected {d} argument{s}, found {d}", .{
expected, s, params.len,
});
}
}
// Check function scope-only builtins
if (astgen.fn_block == null and info.illegal_outside_function)
return astgen.failNode(node, "'{s}' outside function scope", .{builtin_name});
switch (info.tag) {
.branch_hint => {
if (!allow_branch_hint) {
return astgen.failNode(node, "'@branchHint' must appear as the first statement in a function or conditional branch", .{});
}
const hint_ty = try gz.addBuiltinValue(node, .branch_hint);
const hint_val = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = hint_ty } }, params[0], .operand_branchHint);
_ = try gz.addExtendedPayload(.branch_hint, Zir.Inst.UnNode{
.node = gz.nodeIndexToRelative(node),
.operand = hint_val,
});
return rvalue(gz, ri, .void_value, node);
},
.import => {
const operand_node = params[0];
if (tree.nodeTag(operand_node) != .string_literal) {
// Spec reference: https://github.com/ziglang/zig/issues/2206
return astgen.failNode(operand_node, "@import operand must be a string literal", .{});
}
const str_lit_token = tree.nodeMainToken(operand_node);
const str = try astgen.strLitAsString(str_lit_token);
const str_slice = astgen.string_bytes.items[@intFromEnum(str.index)..][0..str.len];
if (mem.indexOfScalar(u8, str_slice, 0) != null) {
return astgen.failTok(str_lit_token, "import path cannot contain null bytes", .{});
} else if (str.len == 0) {
return astgen.failTok(str_lit_token, "import path cannot be empty", .{});
}
const res_ty = try ri.rl.resultType(gz, node) orelse .none;
const payload_index = try addExtra(gz.astgen, Zir.Inst.Import{
.res_ty = res_ty,
.path = str.index,
});
const result = try gz.add(.{
.tag = .import,
.data = .{ .pl_tok = .{
.src_tok = gz.tokenIndexToRelative(str_lit_token),
.payload_index = payload_index,
} },
});
const gop = try astgen.imports.getOrPut(astgen.gpa, str.index);
if (!gop.found_existing) {
gop.value_ptr.* = str_lit_token;
}
return rvalue(gz, ri, result, node);
},
.compile_log => {
const payload_index = try addExtra(gz.astgen, Zir.Inst.NodeMultiOp{
.src_node = gz.nodeIndexToRelative(node),
});
var extra_index = try reserveExtra(gz.astgen, params.len);
for (params) |param| {
const param_ref = try expr(gz, scope, .{ .rl = .none }, param);
astgen.extra.items[extra_index] = @intFromEnum(param_ref);
extra_index += 1;
}
const result = try gz.addExtendedMultiOpPayloadIndex(.compile_log, payload_index, params.len);
return rvalue(gz, ri, result, node);
},
.field => {
if (ri.rl == .ref or ri.rl == .ref_coerced_ty) {
return gz.addPlNode(.field_ptr_named, node, Zir.Inst.FieldNamed{
.lhs = try expr(gz, scope, .{ .rl = .ref }, params[0]),
.field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[1], .field_name),
});
}
const result = try gz.addPlNode(.field_val_named, node, Zir.Inst.FieldNamed{
.lhs = try expr(gz, scope, .{ .rl = .none }, params[0]),
.field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[1], .field_name),
});
return rvalue(gz, ri, result, node);
},
.FieldType => {
const ty_inst = try typeExpr(gz, scope, params[0]);
const name_inst = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[1], .field_name);
const result = try gz.addPlNode(.field_type_ref, node, Zir.Inst.FieldTypeRef{
.container_type = ty_inst,
.field_name = name_inst,
});
return rvalue(gz, ri, result, node);
},
// zig fmt: off
.as => return as( gz, scope, ri, node, params[0], params[1]),
.bit_cast => return bitCast( gz, scope, ri, node, params[0]),
.TypeOf => return typeOf( gz, scope, ri, node, params),
.union_init => return unionInit(gz, scope, ri, node, params),
.c_import => return cImport( gz, scope, node, params[0]),
.min => return minMax( gz, scope, ri, node, params, .min),
.max => return minMax( gz, scope, ri, node, params, .max),
// zig fmt: on
.@"export" => {
const exported = try expr(gz, scope, .{ .rl = .none }, params[0]);
const export_options_ty = try gz.addBuiltinValue(node, .export_options);
const options = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = export_options_ty } }, params[1], .export_options);
_ = try gz.addPlNode(.@"export", node, Zir.Inst.Export{
.exported = exported,
.options = options,
});
return rvalue(gz, ri, .void_value, node);
},
.@"extern" => {
const type_inst = try typeExpr(gz, scope, params[0]);
const extern_options_ty = try gz.addBuiltinValue(node, .extern_options);
const options = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = extern_options_ty } }, params[1], .extern_options);
const result = try gz.addExtendedPayload(.builtin_extern, Zir.Inst.BinNode{
.node = gz.nodeIndexToRelative(node),
.lhs = type_inst,
.rhs = options,
});
return rvalue(gz, ri, result, node);
},
.set_float_mode => {
const float_mode_ty = try gz.addBuiltinValue(node, .float_mode);
const order = try expr(gz, scope, .{ .rl = .{ .coerced_ty = float_mode_ty } }, params[0]);
_ = try gz.addExtendedPayload(.set_float_mode, Zir.Inst.UnNode{
.node = gz.nodeIndexToRelative(node),
.operand = order,
});
return rvalue(gz, ri, .void_value, node);
},
.src => {
// Incorporate the source location into the source hash, so that
// changes in the source location of `@src()` result in re-analysis.
astgen.src_hasher.update(
std.mem.asBytes(&astgen.source_line) ++
std.mem.asBytes(&astgen.source_column),
);
const node_start = tree.tokenStart(tree.firstToken(node));
astgen.advanceSourceCursor(node_start);
const result = try gz.addExtendedPayload(.builtin_src, Zir.Inst.Src{
.node = gz.nodeIndexToRelative(node),
.line = astgen.source_line,
.column = astgen.source_column,
});
return rvalue(gz, ri, result, node);
},
// zig fmt: off
.This => return rvalue(gz, ri, try gz.addNodeExtended(.this, node), node),
.return_address => return rvalue(gz, ri, try gz.addNodeExtended(.ret_addr, node), node),
.error_return_trace => return rvalue(gz, ri, try gz.addNodeExtended(.error_return_trace, node), node),
.frame => return rvalue(gz, ri, try gz.addNodeExtended(.frame, node), node),
.frame_address => return rvalue(gz, ri, try gz.addNodeExtended(.frame_address, node), node),
.breakpoint => return rvalue(gz, ri, try gz.addNodeExtended(.breakpoint, node), node),
.disable_instrumentation => return rvalue(gz, ri, try gz.addNodeExtended(.disable_instrumentation, node), node),
.disable_intrinsics => return rvalue(gz, ri, try gz.addNodeExtended(.disable_intrinsics, node), node),
.type_info => return simpleUnOpType(gz, scope, ri, node, params[0], .type_info),
.size_of => return simpleUnOpType(gz, scope, ri, node, params[0], .size_of),
.bit_size_of => return simpleUnOpType(gz, scope, ri, node, params[0], .bit_size_of),
.align_of => return simpleUnOpType(gz, scope, ri, node, params[0], .align_of),
.int_from_ptr => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .int_from_ptr),
.compile_error => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[0], .compile_error),
.set_eval_branch_quota => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .coerced_ty = .u32_type } }, params[0], .set_eval_branch_quota),
.int_from_enum => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .int_from_enum),
.int_from_bool => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .int_from_bool),
.embed_file => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[0], .embed_file),
.error_name => return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .coerced_ty = .anyerror_type } }, params[0], .error_name),
.set_runtime_safety => return simpleUnOp(gz, scope, ri, node, coerced_bool_ri, params[0], .set_runtime_safety),
.sqrt => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .sqrt),
.sin => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .sin),
.cos => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .cos),
.tan => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .tan),
.exp => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .exp),
.exp2 => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .exp2),
.log => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .log),
.log2 => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .log2),
.log10 => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .log10),
.abs => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .abs),
.floor => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .floor),
.ceil => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .ceil),
.trunc => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .trunc),
.round => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .round),
.tag_name => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .tag_name),
.type_name => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .type_name),
.Frame => return simpleUnOp(gz, scope, ri, node, .{ .rl = .none }, params[0], .frame_type),
.int_from_float => return typeCast(gz, scope, ri, node, params[0], .int_from_float, builtin_name),
.float_from_int => return typeCast(gz, scope, ri, node, params[0], .float_from_int, builtin_name),
.ptr_from_int => return typeCast(gz, scope, ri, node, params[0], .ptr_from_int, builtin_name),
.enum_from_int => return typeCast(gz, scope, ri, node, params[0], .enum_from_int, builtin_name),
.float_cast => return typeCast(gz, scope, ri, node, params[0], .float_cast, builtin_name),
.int_cast => return typeCast(gz, scope, ri, node, params[0], .int_cast, builtin_name),
.truncate => return typeCast(gz, scope, ri, node, params[0], .truncate, builtin_name),
// zig fmt: on
.in_comptime => if (gz.is_comptime) {
return astgen.failNode(node, "redundant '@inComptime' in comptime scope", .{});
} else {
return rvalue(gz, ri, try gz.addNodeExtended(.in_comptime, node), node);
},
.Type => {
return builtinReify(gz, scope, ri, node, params[0], .anon);
},
.panic => {
try emitDbgNode(gz, node);
return simpleUnOp(gz, scope, ri, node, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[0], .panic);
},
.trap => {
try emitDbgNode(gz, node);
_ = try gz.addNode(.trap, node);
return rvalue(gz, ri, .unreachable_value, node);
},
.int_from_error => {
const operand = try expr(gz, scope, .{ .rl = .none }, params[0]);
const result = try gz.addExtendedPayload(.int_from_error, Zir.Inst.UnNode{
.node = gz.nodeIndexToRelative(node),
.operand = operand,
});
return rvalue(gz, ri, result, node);
},
.error_from_int => {
const operand = try expr(gz, scope, .{ .rl = .none }, params[0]);
const result = try gz.addExtendedPayload(.error_from_int, Zir.Inst.UnNode{
.node = gz.nodeIndexToRelative(node),
.operand = operand,
});
return rvalue(gz, ri, result, node);
},
.error_cast => {
try emitDbgNode(gz, node);
const result = try gz.addExtendedPayload(.error_cast, Zir.Inst.BinNode{
.lhs = try ri.rl.resultTypeForCast(gz, node, builtin_name),
.rhs = try expr(gz, scope, .{ .rl = .none }, params[0]),
.node = gz.nodeIndexToRelative(node),
});
return rvalue(gz, ri, result, node);
},
.ptr_cast,
.align_cast,
.addrspace_cast,
.const_cast,
.volatile_cast,
=> return ptrCast(gz, scope, ri, node),
// zig fmt: off
.has_decl => return hasDeclOrField(gz, scope, ri, node, params[0], params[1], .has_decl),
.has_field => return hasDeclOrField(gz, scope, ri, node, params[0], params[1], .has_field),
.clz => return bitBuiltin(gz, scope, ri, node, params[0], .clz),
.ctz => return bitBuiltin(gz, scope, ri, node, params[0], .ctz),
.pop_count => return bitBuiltin(gz, scope, ri, node, params[0], .pop_count),
.byte_swap => return bitBuiltin(gz, scope, ri, node, params[0], .byte_swap),
.bit_reverse => return bitBuiltin(gz, scope, ri, node, params[0], .bit_reverse),
.div_exact => return divBuiltin(gz, scope, ri, node, params[0], params[1], .div_exact),
.div_floor => return divBuiltin(gz, scope, ri, node, params[0], params[1], .div_floor),
.div_trunc => return divBuiltin(gz, scope, ri, node, params[0], params[1], .div_trunc),
.mod => return divBuiltin(gz, scope, ri, node, params[0], params[1], .mod),
.rem => return divBuiltin(gz, scope, ri, node, params[0], params[1], .rem),
.shl_exact => return shiftOp(gz, scope, ri, node, params[0], params[1], .shl_exact),
.shr_exact => return shiftOp(gz, scope, ri, node, params[0], params[1], .shr_exact),
.bit_offset_of => return offsetOf(gz, scope, ri, node, params[0], params[1], .bit_offset_of),
.offset_of => return offsetOf(gz, scope, ri, node, params[0], params[1], .offset_of),
.c_undef => return simpleCBuiltin(gz, scope, ri, node, params[0], .c_undef),
.c_include => return simpleCBuiltin(gz, scope, ri, node, params[0], .c_include),
.cmpxchg_strong => return cmpxchg(gz, scope, ri, node, params, 1),
.cmpxchg_weak => return cmpxchg(gz, scope, ri, node, params, 0),
// zig fmt: on
.wasm_memory_size => {
const operand = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .u32_type } }, params[0], .wasm_memory_index);
const result = try gz.addExtendedPayload(.wasm_memory_size, Zir.Inst.UnNode{
.node = gz.nodeIndexToRelative(node),
.operand = operand,
});
return rvalue(gz, ri, result, node);
},
.wasm_memory_grow => {
const index_arg = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .u32_type } }, params[0], .wasm_memory_index);
const delta_arg = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, params[1]);
const result = try gz.addExtendedPayload(.wasm_memory_grow, Zir.Inst.BinNode{
.node = gz.nodeIndexToRelative(node),
.lhs = index_arg,
.rhs = delta_arg,
});
return rvalue(gz, ri, result, node);
},
.c_define => {
if (!gz.c_import) return gz.astgen.failNode(node, "C define valid only inside C import block", .{});
const name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[0], .operand_cDefine_macro_name);
const value = try comptimeExpr(gz, scope, .{ .rl = .none }, params[1], .operand_cDefine_macro_value);
const result = try gz.addExtendedPayload(.c_define, Zir.Inst.BinNode{
.node = gz.nodeIndexToRelative(node),
.lhs = name,
.rhs = value,
});
return rvalue(gz, ri, result, node);
},
.splat => {
const result_type = try ri.rl.resultTypeForCast(gz, node, builtin_name);
const elem_type = try gz.addUnNode(.splat_op_result_ty, result_type, node);
const scalar = try expr(gz, scope, .{ .rl = .{ .ty = elem_type } }, params[0]);
const result = try gz.addPlNode(.splat, node, Zir.Inst.Bin{
.lhs = result_type,
.rhs = scalar,
});
return rvalue(gz, ri, result, node);
},
.reduce => {
const reduce_op_ty = try gz.addBuiltinValue(node, .reduce_op);
const op = try expr(gz, scope, .{ .rl = .{ .coerced_ty = reduce_op_ty } }, params[0]);
const scalar = try expr(gz, scope, .{ .rl = .none }, params[1]);
const result = try gz.addPlNode(.reduce, node, Zir.Inst.Bin{
.lhs = op,
.rhs = scalar,
});
return rvalue(gz, ri, result, node);
},
.add_with_overflow => return overflowArithmetic(gz, scope, ri, node, params, .add_with_overflow),
.sub_with_overflow => return overflowArithmetic(gz, scope, ri, node, params, .sub_with_overflow),
.mul_with_overflow => return overflowArithmetic(gz, scope, ri, node, params, .mul_with_overflow),
.shl_with_overflow => return overflowArithmetic(gz, scope, ri, node, params, .shl_with_overflow),
.atomic_load => {
const atomic_order_type = try gz.addBuiltinValue(node, .atomic_order);
const result = try gz.addPlNode(.atomic_load, node, Zir.Inst.AtomicLoad{
// zig fmt: off
.elem_type = try typeExpr(gz, scope, params[0]),
.ptr = try expr (gz, scope, .{ .rl = .none }, params[1]),
.ordering = try expr (gz, scope, .{ .rl = .{ .coerced_ty = atomic_order_type } }, params[2]),
// zig fmt: on
});
return rvalue(gz, ri, result, node);
},
.atomic_rmw => {
const atomic_order_type = try gz.addBuiltinValue(node, .atomic_order);
const atomic_rmw_op_type = try gz.addBuiltinValue(node, .atomic_rmw_op);
const int_type = try typeExpr(gz, scope, params[0]);
const result = try gz.addPlNode(.atomic_rmw, node, Zir.Inst.AtomicRmw{
// zig fmt: off
.ptr = try expr(gz, scope, .{ .rl = .none }, params[1]),
.operation = try expr(gz, scope, .{ .rl = .{ .coerced_ty = atomic_rmw_op_type } }, params[2]),
.operand = try expr(gz, scope, .{ .rl = .{ .ty = int_type } }, params[3]),
.ordering = try expr(gz, scope, .{ .rl = .{ .coerced_ty = atomic_order_type } }, params[4]),
// zig fmt: on
});
return rvalue(gz, ri, result, node);
},
.atomic_store => {
const atomic_order_type = try gz.addBuiltinValue(node, .atomic_order);
const int_type = try typeExpr(gz, scope, params[0]);
_ = try gz.addPlNode(.atomic_store, node, Zir.Inst.AtomicStore{
// zig fmt: off
.ptr = try expr(gz, scope, .{ .rl = .none }, params[1]),
.operand = try expr(gz, scope, .{ .rl = .{ .ty = int_type } }, params[2]),
.ordering = try expr(gz, scope, .{ .rl = .{ .coerced_ty = atomic_order_type } }, params[3]),
// zig fmt: on
});
return rvalue(gz, ri, .void_value, node);
},
.mul_add => {
const float_type = try typeExpr(gz, scope, params[0]);
const mulend1 = try expr(gz, scope, .{ .rl = .{ .coerced_ty = float_type } }, params[1]);
const mulend2 = try expr(gz, scope, .{ .rl = .{ .coerced_ty = float_type } }, params[2]);
const addend = try expr(gz, scope, .{ .rl = .{ .ty = float_type } }, params[3]);
const result = try gz.addPlNode(.mul_add, node, Zir.Inst.MulAdd{
.mulend1 = mulend1,
.mulend2 = mulend2,
.addend = addend,
});
return rvalue(gz, ri, result, node);
},
.call => {
const call_modifier_ty = try gz.addBuiltinValue(node, .call_modifier);
const modifier = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = call_modifier_ty } }, params[0], .call_modifier);
const callee = try expr(gz, scope, .{ .rl = .none }, params[1]);
const args = try expr(gz, scope, .{ .rl = .none }, params[2]);
const result = try gz.addPlNode(.builtin_call, node, Zir.Inst.BuiltinCall{
.modifier = modifier,
.callee = callee,
.args = args,
.flags = .{
.is_nosuspend = gz.nosuspend_node != .none,
.ensure_result_used = false,
},
});
return rvalue(gz, ri, result, node);
},
.field_parent_ptr => {
const parent_ptr_type = try ri.rl.resultTypeForCast(gz, node, builtin_name);
const field_name = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .slice_const_u8_type } }, params[0], .field_name);
const result = try gz.addExtendedPayloadSmall(.field_parent_ptr, 0, Zir.Inst.FieldParentPtr{
.src_node = gz.nodeIndexToRelative(node),
.parent_ptr_type = parent_ptr_type,
.field_name = field_name,
.field_ptr = try expr(gz, scope, .{ .rl = .none }, params[1]),
});
return rvalue(gz, ri, result, node);
},
.memcpy => {
_ = try gz.addPlNode(.memcpy, node, Zir.Inst.Bin{
.lhs = try expr(gz, scope, .{ .rl = .none }, params[0]),
.rhs = try expr(gz, scope, .{ .rl = .none }, params[1]),
});
return rvalue(gz, ri, .void_value, node);
},
.memset => {
const lhs = try expr(gz, scope, .{ .rl = .none }, params[0]);
const lhs_ty = try gz.addUnNode(.typeof, lhs, params[0]);
const elem_ty = try gz.addUnNode(.indexable_ptr_elem_type, lhs_ty, params[0]);
_ = try gz.addPlNode(.memset, node, Zir.Inst.Bin{
.lhs = lhs,
.rhs = try expr(gz, scope, .{ .rl = .{ .coerced_ty = elem_ty } }, params[1]),
});
return rvalue(gz, ri, .void_value, node);
},
.memmove => {
_ = try gz.addPlNode(.memmove, node, Zir.Inst.Bin{
.lhs = try expr(gz, scope, .{ .rl = .none }, params[0]),
.rhs = try expr(gz, scope, .{ .rl = .none }, params[1]),
});
return rvalue(gz, ri, .void_value, node);
},
.shuffle => {
const result = try gz.addPlNode(.shuffle, node, Zir.Inst.Shuffle{
.elem_type = try typeExpr(gz, scope, params[0]),
.a = try expr(gz, scope, .{ .rl = .none }, params[1]),
.b = try expr(gz, scope, .{ .rl = .none }, params[2]),
.mask = try comptimeExpr(gz, scope, .{ .rl = .none }, params[3], .operand_shuffle_mask),
});
return rvalue(gz, ri, result, node);
},
.select => {
const result = try gz.addExtendedPayload(.select, Zir.Inst.Select{
.node = gz.nodeIndexToRelative(node),
.elem_type = try typeExpr(gz, scope, params[0]),
.pred = try expr(gz, scope, .{ .rl = .none }, params[1]),
.a = try expr(gz, scope, .{ .rl = .none }, params[2]),
.b = try expr(gz, scope, .{ .rl = .none }, params[3]),
});
return rvalue(gz, ri, result, node);
},
.Vector => {
const result = try gz.addPlNode(.vector_type, node, Zir.Inst.Bin{
.lhs = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .u32_type } }, params[0], .type),
.rhs = try typeExpr(gz, scope, params[1]),
});
return rvalue(gz, ri, result, node);
},
.prefetch => {
const prefetch_options_ty = try gz.addBuiltinValue(node, .prefetch_options);
const ptr = try expr(gz, scope, .{ .rl = .none }, params[0]);
const options = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = prefetch_options_ty } }, params[1], .prefetch_options);
_ = try gz.addExtendedPayload(.prefetch, Zir.Inst.BinNode{
.node = gz.nodeIndexToRelative(node),
.lhs = ptr,
.rhs = options,
});
return rvalue(gz, ri, .void_value, node);
},
.c_va_arg => {
const result = try gz.addExtendedPayload(.c_va_arg, Zir.Inst.BinNode{
.node = gz.nodeIndexToRelative(node),
.lhs = try expr(gz, scope, .{ .rl = .none }, params[0]),
.rhs = try typeExpr(gz, scope, params[1]),
});
return rvalue(gz, ri, result, node);
},
.c_va_copy => {
const result = try gz.addExtendedPayload(.c_va_copy, Zir.Inst.UnNode{
.node = gz.nodeIndexToRelative(node),
.operand = try expr(gz, scope, .{ .rl = .none }, params[0]),
});
return rvalue(gz, ri, result, node);
},
.c_va_end => {
const result = try gz.addExtendedPayload(.c_va_end, Zir.Inst.UnNode{
.node = gz.nodeIndexToRelative(node),
.operand = try expr(gz, scope, .{ .rl = .none }, params[0]),
});
return rvalue(gz, ri, result, node);
},
.c_va_start => {
if (!astgen.fn_var_args) {
return astgen.failNode(node, "'@cVaStart' in a non-variadic function", .{});
}
return rvalue(gz, ri, try gz.addNodeExtended(.c_va_start, node), node);
},
.work_item_id => {
const operand = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .u32_type } }, params[0], .work_group_dim_index);
const result = try gz.addExtendedPayload(.work_item_id, Zir.Inst.UnNode{
.node = gz.nodeIndexToRelative(node),
.operand = operand,
});
return rvalue(gz, ri, result, node);
},
.work_group_size => {
const operand = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .u32_type } }, params[0], .work_group_dim_index);
const result = try gz.addExtendedPayload(.work_group_size, Zir.Inst.UnNode{
.node = gz.nodeIndexToRelative(node),
.operand = operand,
});
return rvalue(gz, ri, result, node);
},
.work_group_id => {
const operand = try comptimeExpr(gz, scope, .{ .rl = .{ .coerced_ty = .u32_type } }, params[0], .work_group_dim_index);
const result = try gz.addExtendedPayload(.work_group_id, Zir.Inst.UnNode{
.node = gz.nodeIndexToRelative(node),
.operand = operand,
});
return rvalue(gz, ri, result, node);
},
}
}