AstGen: implement function prototypes with alignment exprs

This commit is contained in:
Andrew Kelley 2021-04-29 18:25:25 -07:00
parent 2eef83e85f
commit ba9b9cb38d
5 changed files with 51 additions and 10 deletions

View File

@ -1,3 +1,4 @@
* decouple AstGen from Module, Compilation
* modify dbg_stmt ZIR instructions to have line/column rather than node indexes
* AstGen threadlocal
* extern "foo" for vars and for functions

View File

@ -1048,10 +1048,12 @@ pub fn fnProtoExpr(
assert(param_type_i == param_count);
}
if (fn_proto.ast.align_expr != 0) {
return astgen.failNode(fn_proto.ast.align_expr, "TODO: AstGen: implement function prototypes with alignment expressions", .{});
const align_inst: Zir.Inst.Ref = if (fn_proto.ast.align_expr == 0) .none else inst: {
break :inst try expr(gz, scope, align_rl, fn_proto.ast.align_expr);
};
if (fn_proto.ast.section_expr != 0) {
return astgen.failNode(fn_proto.ast.section_expr, "linksection not allowed on function prototypes", .{});
}
assert(fn_proto.ast.section_expr == 0); // caught by the parser
const maybe_bang = tree.firstToken(fn_proto.ast.return_type) - 1;
const is_inferred_error = token_tags[maybe_bang] == .bang;
@ -1081,6 +1083,7 @@ pub fn fnProtoExpr(
.param_types = param_types,
.body = &[0]Zir.Inst.Index{},
.cc = cc,
.align_inst = align_inst,
.lib_name = 0,
.is_var_args = is_var_args,
.is_inferred_error = false,
@ -2794,6 +2797,7 @@ fn fnDecl(
.param_types = param_types,
.body = &[0]Zir.Inst.Index{},
.cc = cc,
.align_inst = .none, // passed in the per-decl data
.lib_name = lib_name,
.is_var_args = is_var_args,
.is_inferred_error = false,
@ -2866,6 +2870,7 @@ fn fnDecl(
.param_types = param_types,
.body = fn_gz.instructions.items,
.cc = cc,
.align_inst = .none, // passed in the per-decl data
.lib_name = lib_name,
.is_var_args = is_var_args,
.is_inferred_error = is_inferred_error,
@ -3167,6 +3172,7 @@ fn testDecl(
.param_types = &[0]Zir.Inst.Ref{},
.body = fn_block.instructions.items,
.cc = .none,
.align_inst = .none,
.lib_name = 0,
.is_var_args = false,
.is_inferred_error = true,

View File

@ -1372,6 +1372,7 @@ pub const Scope = struct {
body: []const Zir.Inst.Index,
ret_ty: Zir.Inst.Ref,
cc: Zir.Inst.Ref,
align_inst: Zir.Inst.Ref,
lib_name: u32,
is_var_args: bool,
is_inferred_error: bool,
@ -1385,12 +1386,15 @@ pub const Scope = struct {
try gz.instructions.ensureUnusedCapacity(gpa, 1);
try astgen.instructions.ensureUnusedCapacity(gpa, 1);
if (args.cc != .none or args.lib_name != 0 or args.is_var_args or args.is_test) {
if (args.cc != .none or args.lib_name != 0 or
args.is_var_args or args.is_test or args.align_inst != .none)
{
try astgen.extra.ensureUnusedCapacity(
gpa,
@typeInfo(Zir.Inst.ExtendedFunc).Struct.fields.len +
args.param_types.len + args.body.len +
@boolToInt(args.lib_name != 0) +
@boolToInt(args.align_inst != .none) +
@boolToInt(args.cc != .none),
);
const payload_index = astgen.addExtraAssumeCapacity(Zir.Inst.ExtendedFunc{
@ -1399,11 +1403,14 @@ pub const Scope = struct {
.param_types_len = @intCast(u32, args.param_types.len),
.body_len = @intCast(u32, args.body.len),
});
if (args.lib_name != 0) {
astgen.extra.appendAssumeCapacity(args.lib_name);
}
if (args.cc != .none) {
astgen.extra.appendAssumeCapacity(@enumToInt(args.cc));
}
if (args.lib_name != 0) {
astgen.extra.appendAssumeCapacity(args.lib_name);
if (args.align_inst != .none) {
astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst));
}
astgen.appendRefsAssumeCapacity(args.param_types);
astgen.extra.appendSliceAssumeCapacity(args.body);
@ -1418,6 +1425,7 @@ pub const Scope = struct {
.is_inferred_error = args.is_inferred_error,
.has_lib_name = args.lib_name != 0,
.has_cc = args.cc != .none,
.has_align = args.align_inst != .none,
.is_test = args.is_test,
}),
.operand = payload_index,

View File

@ -2737,6 +2737,7 @@ fn zirFunc(
body,
extra.data.return_type,
.Unspecified,
Value.initTag(.null_value),
false,
inferred_error_set,
);
@ -2750,6 +2751,7 @@ fn funcCommon(
body: []const Zir.Inst.Index,
zir_return_type: Zir.Inst.Ref,
cc: std.builtin.CallingConvention,
align_val: Value,
var_args: bool,
inferred_error_set: bool,
) InnerError!*Inst {
@ -2762,7 +2764,7 @@ fn funcCommon(
}
// Hot path for some common function types.
if (zir_param_types.len == 0 and !var_args) {
if (zir_param_types.len == 0 and !var_args and align_val.tag() == .null_value) {
if (return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {
return sema.mod.constType(sema.arena, src, Type.initTag(.fn_noreturn_no_args));
}
@ -2789,6 +2791,10 @@ fn funcCommon(
param_types[i] = try sema.resolveType(block, src, param_type);
}
if (align_val.tag() != .null_value) {
return sema.mod.fail(&block.base, src, "TODO implement support for function prototypes to have alignment specified", .{});
}
const fn_ty = try Type.Tag.function.create(sema.arena, .{
.param_types = param_types,
.return_type = return_type,
@ -5432,6 +5438,7 @@ fn zirFuncExtended(
const extra = sema.code.extraData(Zir.Inst.ExtendedFunc, extended.operand);
const src: LazySrcLoc = .{ .node_offset = extra.data.src_node };
const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = extra.data.src_node };
const align_src: LazySrcLoc = src; // TODO add a LazySrcLoc that points at align
const small = @bitCast(Zir.Inst.ExtendedFunc.Small, extended.small);
var extra_index: usize = extra.end;
@ -5455,6 +5462,13 @@ fn zirFuncExtended(
break :blk cc;
} else .Unspecified;
const align_val: Value = if (small.has_align) blk: {
const align_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
extra_index += 1;
const align_tv = try sema.resolveInstConst(block, align_src, align_ref);
break :blk align_tv.val;
} else Value.initTag(.null_value);
const param_types = sema.code.refSlice(extra_index, extra.data.param_types_len);
extra_index += param_types.len;
@ -5467,6 +5481,7 @@ fn zirFuncExtended(
body,
extra.data.return_type,
cc,
align_val,
small.is_var_args,
small.is_inferred_error,
);

View File

@ -2189,8 +2189,9 @@ pub const Inst = struct {
/// Trailing:
/// 0. lib_name: u32, // null terminated string index, if has_lib_name is set
/// 1. cc: Ref, // if has_cc is set
/// 2. param_type: Ref // for each param_types_len
/// 3. body: Index // for each body_len
/// 2. align: Ref, // if has_align is set
/// 3. param_type: Ref // for each param_types_len
/// 4. body: Index // for each body_len
pub const ExtendedFunc = struct {
src_node: i32,
return_type: Ref,
@ -2202,8 +2203,9 @@ pub const Inst = struct {
is_inferred_error: bool,
has_lib_name: bool,
has_cc: bool,
has_align: bool,
is_test: bool,
_: u11 = undefined,
_: u10 = undefined,
};
};
@ -3966,6 +3968,7 @@ const Writer = struct {
inferred_error_set,
false,
.none,
.none,
body,
src,
);
@ -3988,6 +3991,11 @@ const Writer = struct {
extra_index += 1;
break :blk cc;
};
const align_inst: Inst.Ref = if (!small.has_align) .none else blk: {
const align_inst = @intToEnum(Zir.Inst.Ref, self.code.extra[extra_index]);
extra_index += 1;
break :blk align_inst;
};
const param_types = self.code.refSlice(extra_index, extra.data.param_types_len);
extra_index += param_types.len;
@ -4001,6 +4009,7 @@ const Writer = struct {
small.is_inferred_error,
small.is_var_args,
cc,
align_inst,
body,
src,
);
@ -4053,6 +4062,7 @@ const Writer = struct {
inferred_error_set: bool,
var_args: bool,
cc: Inst.Ref,
align_inst: Inst.Ref,
body: []const Inst.Index,
src: LazySrcLoc,
) !void {
@ -4064,6 +4074,7 @@ const Writer = struct {
try stream.writeAll("], ");
try self.writeInstRef(stream, ret_ty);
try self.writeOptionalInstRef(stream, ", cc=", cc);
try self.writeOptionalInstRef(stream, ", align=", align_inst);
try self.writeFlag(stream, ", vargs", var_args);
try self.writeFlag(stream, ", inferror", inferred_error_set);