AstGen: improved logic for nodeMayNeedMemoryLocation

* `@as` and `@bitCast` no longer unconditionally return `true` from
   this function; they forward the question to their sub-expression.
 * fix `@splat` incorrectly being marked as needing a memory location
   (this function returns a SIMD vector; it definitely does not want a
   memory location).

Makes AstGen generate slightly nicer ZIR, which in turn generates
slightly nicer AIR, generating slightly nicer machine code in debug
builds.

It also means I can procrastinate implementing the bitcast_result_ptr
ZIR instruction semantic analysis :^)
This commit is contained in:
Andrew Kelley 2021-09-28 20:33:50 -07:00
parent 51a40f9a66
commit 7efc2a0626
2 changed files with 37 additions and 15 deletions

View File

@ -8271,17 +8271,31 @@ fn nodeMayNeedMemoryLocation(tree: *const Ast, start_node: Ast.Node.Index) bool
}
},
.builtin_call,
.builtin_call_comma,
.builtin_call_two,
.builtin_call_two_comma,
=> {
.builtin_call_two, .builtin_call_two_comma => {
const builtin_token = main_tokens[node];
const builtin_name = tree.tokenSlice(builtin_token);
// If the builtin is an invalid name, we don't cause an error here; instead
// let it pass, and the error will be "invalid builtin function" later.
const builtin_info = BuiltinFn.list.get(builtin_name) orelse return false;
return builtin_info.needs_mem_loc;
switch (builtin_info.needs_mem_loc) {
.never => return false,
.always => return true,
.forward1 => node = node_datas[node].rhs,
}
},
.builtin_call, .builtin_call_comma => {
const params = tree.extra_data[node_datas[node].lhs..node_datas[node].rhs];
const builtin_token = main_tokens[node];
const builtin_name = tree.tokenSlice(builtin_token);
// If the builtin is an invalid name, we don't cause an error here; instead
// let it pass, and the error will be "invalid builtin function" later.
const builtin_info = BuiltinFn.list.get(builtin_name) orelse return false;
switch (builtin_info.needs_mem_loc) {
.never => return false,
.always => return true,
.forward1 => node = params[1],
}
},
}
}

View File

@ -110,10 +110,19 @@ pub const Tag = enum {
Vector,
};
pub const MemLocRequirement = enum {
/// The builtin never needs a memory location.
never,
/// The builtin always needs a memory location.
always,
/// The builtin forwards the question to argument at index 1.
forward1,
};
tag: Tag,
/// `true` if the builtin call can take advantage of a result location pointer.
needs_mem_loc: bool = false,
/// Info about the builtin call's ability to take advantage of a result location pointer.
needs_mem_loc: MemLocRequirement = .never,
/// `true` if the builtin call can be the left-hand side of an expression (assigned to).
allows_lvalue: bool = false,
/// The number of parameters to this builtin function. `null` means variable number
@ -148,7 +157,7 @@ pub const list = list: {
"@as",
.{
.tag = .as,
.needs_mem_loc = true,
.needs_mem_loc = .forward1,
.param_count = 2,
},
},
@ -184,7 +193,7 @@ pub const list = list: {
"@bitCast",
.{
.tag = .bit_cast,
.needs_mem_loc = true,
.needs_mem_loc = .forward1,
.param_count = 2,
},
},
@ -248,7 +257,7 @@ pub const list = list: {
"@call",
.{
.tag = .call,
.needs_mem_loc = true,
.needs_mem_loc = .always,
.param_count = 3,
},
},
@ -410,7 +419,7 @@ pub const list = list: {
"@field",
.{
.tag = .field,
.needs_mem_loc = true,
.needs_mem_loc = .always,
.param_count = 2,
.allows_lvalue = true,
},
@ -699,7 +708,6 @@ pub const list = list: {
"@splat",
.{
.tag = .splat,
.needs_mem_loc = true,
.param_count = 2,
},
},
@ -714,7 +722,7 @@ pub const list = list: {
"@src",
.{
.tag = .src,
.needs_mem_loc = true,
.needs_mem_loc = .always,
.param_count = 0,
},
},
@ -869,7 +877,7 @@ pub const list = list: {
"@unionInit",
.{
.tag = .union_init,
.needs_mem_loc = true,
.needs_mem_loc = .always,
.param_count = 3,
},
},