authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-21 22:43:57-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-04-21 22:43:57-07:00
log389020009a9afea3cc01e8e408aa33dbc63c156c
tree688dc53c1a917b9bca1761dbea90886bbb0b0ea2
parentea00ddfe3710e386b62849fa4d275b5cbd82e28c

AstGen: implement alignment on locals


4 files changed, 139 insertions(+), 16 deletions(-)

src/AstGen.zig+61-15
...@@ -1902,9 +1902,6 @@ fn varDecl(...@@ -1902,9 +1902,6 @@ fn varDecl(
1902) InnerError!*Scope {1902) InnerError!*Scope {
1903 try emitDbgNode(gz, node);1903 try emitDbgNode(gz, node);
1904 const astgen = gz.astgen;1904 const astgen = gz.astgen;
1905 if (var_decl.ast.align_node != 0) {
1906 return astgen.failNode(var_decl.ast.align_node, "TODO implement alignment on locals", .{});
1907 }
1908 const gpa = astgen.gpa;1905 const gpa = astgen.gpa;
1909 const tree = &astgen.file.tree;1906 const tree = &astgen.file.tree;
1910 const token_tags = tree.tokens.items(.tag);1907 const token_tags = tree.tokens.items(.tag);
...@@ -1919,12 +1916,12 @@ fn varDecl(...@@ -1919,12 +1916,12 @@ fn varDecl(
1919 .local_val => {1916 .local_val => {
1920 const local_val = s.cast(Scope.LocalVal).?;1917 const local_val = s.cast(Scope.LocalVal).?;
1921 if (mem.eql(u8, local_val.name, ident_name)) {1918 if (mem.eql(u8, local_val.name, ident_name)) {
1922 return astgen.failTokNotes(name_token, "redefinition of '{s}'", .{1919 return astgen.failTokNotes(name_token, "redeclaration of '{s}'", .{
1923 ident_name,1920 ident_name,
1924 }, &[_]u32{1921 }, &[_]u32{
1925 try astgen.errNoteTok(1922 try astgen.errNoteTok(
1926 local_val.token_src,1923 local_val.token_src,
1927 "previous definition is here",1924 "previous declaration is here",
1928 .{},1925 .{},
1929 ),1926 ),
1930 });1927 });
...@@ -1934,12 +1931,12 @@ fn varDecl(...@@ -1934,12 +1931,12 @@ fn varDecl(
1934 .local_ptr => {1931 .local_ptr => {
1935 const local_ptr = s.cast(Scope.LocalPtr).?;1932 const local_ptr = s.cast(Scope.LocalPtr).?;
1936 if (mem.eql(u8, local_ptr.name, ident_name)) {1933 if (mem.eql(u8, local_ptr.name, ident_name)) {
1937 return astgen.failTokNotes(name_token, "redefinition of '{s}'", .{1934 return astgen.failTokNotes(name_token, "redeclaration of '{s}'", .{
1938 ident_name,1935 ident_name,
1939 }, &[_]u32{1936 }, &[_]u32{
1940 try astgen.errNoteTok(1937 try astgen.errNoteTok(
1941 local_ptr.token_src,1938 local_ptr.token_src,
1942 "previous definition is here",1939 "previous declaration is here",
1943 .{},1940 .{},
1944 ),1941 ),
1945 });1942 });
...@@ -1957,15 +1954,21 @@ fn varDecl(...@@ -1957,15 +1954,21 @@ fn varDecl(
1957 return astgen.failNode(node, "variables must be initialized", .{});1954 return astgen.failNode(node, "variables must be initialized", .{});
1958 }1955 }
19591956
1957 const align_inst: Zir.Inst.Ref = if (var_decl.ast.align_node != 0)
1958 try expr(gz, scope, align_rl, var_decl.ast.align_node)
1959 else
1960 .none;
1961
1960 switch (token_tags[var_decl.ast.mut_token]) {1962 switch (token_tags[var_decl.ast.mut_token]) {
1961 .keyword_const => {1963 .keyword_const => {
1962 if (var_decl.comptime_token) |comptime_token| {1964 if (var_decl.comptime_token) |comptime_token| {
1963 return astgen.failTok(comptime_token, "'comptime const' is redundant; instead wrap the initialization expression with 'comptime'", .{});1965 return astgen.failTok(comptime_token, "'comptime const' is redundant; instead wrap the initialization expression with 'comptime'", .{});
1964 }1966 }
1967
1965 // Depending on the type of AST the initialization expression is, we may need an lvalue1968 // Depending on the type of AST the initialization expression is, we may need an lvalue
1966 // or an rvalue as a result location. If it is an rvalue, we can use the instruction as1969 // or an rvalue as a result location. If it is an rvalue, we can use the instruction as
1967 // the variable, no memory location needed.1970 // the variable, no memory location needed.
1968 if (!nodeMayNeedMemoryLocation(tree, var_decl.ast.init_node)) {1971 if (align_inst == .none and !nodeMayNeedMemoryLocation(tree, var_decl.ast.init_node)) {
1969 const result_loc: ResultLoc = if (var_decl.ast.type_node != 0) .{1972 const result_loc: ResultLoc = if (var_decl.ast.type_node != 0) .{
1970 .ty = try typeExpr(gz, scope, var_decl.ast.type_node),1973 .ty = try typeExpr(gz, scope, var_decl.ast.type_node),
1971 } else .none;1974 } else .none;
...@@ -1997,10 +2000,29 @@ fn varDecl(...@@ -1997,10 +2000,29 @@ fn varDecl(
1997 if (var_decl.ast.type_node != 0) {2000 if (var_decl.ast.type_node != 0) {
1998 const type_inst = try typeExpr(gz, &init_scope.base, var_decl.ast.type_node);2001 const type_inst = try typeExpr(gz, &init_scope.base, var_decl.ast.type_node);
1999 opt_type_inst = type_inst;2002 opt_type_inst = type_inst;
2000 init_scope.rl_ptr = try init_scope.addUnNode(.alloc, type_inst, node);2003 if (align_inst == .none) {
2004 init_scope.rl_ptr = try init_scope.addUnNode(.alloc, type_inst, node);
2005 } else {
2006 init_scope.rl_ptr = try gz.addAllocExtended(.{
2007 .node = node,
2008 .type_inst = type_inst,
2009 .align_inst = align_inst,
2010 .is_const = true,
2011 .is_comptime = false,
2012 });
2013 }
2001 init_scope.rl_ty_inst = type_inst;2014 init_scope.rl_ty_inst = type_inst;
2002 } else {2015 } else {
2003 const alloc = try init_scope.addNode(.alloc_inferred, node);2016 const alloc = if (align_inst == .none)
2017 try init_scope.addNode(.alloc_inferred, node)
2018 else
2019 try gz.addAllocExtended(.{
2020 .node = node,
2021 .type_inst = .none,
2022 .align_inst = align_inst,
2023 .is_const = true,
2024 .is_comptime = false,
2025 });
2004 resolve_inferred_alloc = alloc;2026 resolve_inferred_alloc = alloc;
2005 init_scope.rl_ptr = alloc;2027 init_scope.rl_ptr = alloc;
2006 }2028 }
...@@ -2010,7 +2032,7 @@ fn varDecl(...@@ -2010,7 +2032,7 @@ fn varDecl(
2010 const zir_datas = astgen.instructions.items(.data);2032 const zir_datas = astgen.instructions.items(.data);
20112033
2012 const parent_zir = &gz.instructions;2034 const parent_zir = &gz.instructions;
2013 if (init_scope.rvalue_rl_count == 1) {2035 if (align_inst == .none and init_scope.rvalue_rl_count == 1) {
2014 // Result location pointer not used. We don't need an alloc for this2036 // Result location pointer not used. We don't need an alloc for this
2015 // const local, and type inference becomes trivial.2037 // const local, and type inference becomes trivial.
2016 // Move the init_scope instructions into the parent scope, eliding2038 // Move the init_scope instructions into the parent scope, eliding
...@@ -2070,12 +2092,36 @@ fn varDecl(...@@ -2070,12 +2092,36 @@ fn varDecl(
2070 alloc: Zir.Inst.Ref,2092 alloc: Zir.Inst.Ref,
2071 } = if (var_decl.ast.type_node != 0) a: {2093 } = if (var_decl.ast.type_node != 0) a: {
2072 const type_inst = try typeExpr(gz, scope, var_decl.ast.type_node);2094 const type_inst = try typeExpr(gz, scope, var_decl.ast.type_node);
2073 const tag: Zir.Inst.Tag = if (is_comptime) .alloc_comptime else .alloc_mut;2095 const alloc = alloc: {
2074 const alloc = try gz.addUnNode(tag, type_inst, node);2096 if (align_inst == .none) {
2097 const tag: Zir.Inst.Tag = if (is_comptime) .alloc_comptime else .alloc_mut;
2098 break :alloc try gz.addUnNode(tag, type_inst, node);
2099 } else {
2100 break :alloc try gz.addAllocExtended(.{
2101 .node = node,
2102 .type_inst = type_inst,
2103 .align_inst = align_inst,
2104 .is_const = false,
2105 .is_comptime = is_comptime,
2106 });
2107 }
2108 };
2075 break :a .{ .alloc = alloc, .result_loc = .{ .ptr = alloc } };2109 break :a .{ .alloc = alloc, .result_loc = .{ .ptr = alloc } };
2076 } else a: {2110 } else a: {
2077 const tag: Zir.Inst.Tag = if (is_comptime) .alloc_inferred_comptime else .alloc_inferred_mut;2111 const alloc = alloc: {
2078 const alloc = try gz.addNode(tag, node);2112 if (align_inst == .none) {
2113 const tag: Zir.Inst.Tag = if (is_comptime) .alloc_inferred_comptime else .alloc_inferred_mut;
2114 break :alloc try gz.addNode(tag, node);
2115 } else {
2116 break :alloc try gz.addAllocExtended(.{
2117 .node = node,
2118 .type_inst = .none,
2119 .align_inst = align_inst,
2120 .is_const = false,
2121 .is_comptime = is_comptime,
2122 });
2123 }
2124 };
2079 resolve_inferred_alloc = alloc;2125 resolve_inferred_alloc = alloc;
2080 break :a .{ .alloc = alloc, .result_loc = .{ .inferred_ptr = alloc } };2126 break :a .{ .alloc = alloc, .result_loc = .{ .inferred_ptr = alloc } };
2081 };2127 };
src/Module.zig+51
...@@ -1630,6 +1630,57 @@ pub const Scope = struct {...@@ -1630,6 +1630,57 @@ pub const Scope = struct {
1630 });1630 });
1631 }1631 }
16321632
1633 pub fn addAllocExtended(
1634 gz: *GenZir,
1635 args: struct {
1636 /// Absolute node index. This function does the conversion to offset from Decl.
1637 node: ast.Node.Index,
1638 type_inst: Zir.Inst.Ref,
1639 align_inst: Zir.Inst.Ref,
1640 is_const: bool,
1641 is_comptime: bool,
1642 },
1643 ) !Zir.Inst.Ref {
1644 const astgen = gz.astgen;
1645 const gpa = astgen.gpa;
1646
1647 try gz.instructions.ensureUnusedCapacity(gpa, 1);
1648 try astgen.instructions.ensureUnusedCapacity(gpa, 1);
1649 try astgen.extra.ensureUnusedCapacity(
1650 gpa,
1651 @typeInfo(Zir.Inst.AllocExtended).Struct.fields.len +
1652 @as(usize, @boolToInt(args.type_inst != .none)) +
1653 @as(usize, @boolToInt(args.align_inst != .none)),
1654 );
1655 const payload_index = gz.astgen.addExtra(Zir.Inst.AllocExtended{
1656 .src_node = gz.nodeIndexToRelative(args.node),
1657 }) catch unreachable; // ensureUnusedCapacity above
1658 if (args.type_inst != .none) {
1659 astgen.extra.appendAssumeCapacity(@enumToInt(args.type_inst));
1660 }
1661 if (args.align_inst != .none) {
1662 astgen.extra.appendAssumeCapacity(@enumToInt(args.align_inst));
1663 }
1664
1665 const has_type: u4 = @boolToInt(args.type_inst != .none);
1666 const has_align: u4 = @boolToInt(args.align_inst != .none);
1667 const is_const: u4 = @boolToInt(args.is_const);
1668 const is_comptime: u4 = @boolToInt(args.is_comptime);
1669 const small: u16 = has_type | (has_align << 1) | (is_const << 2) | (is_comptime << 3);
1670
1671 const new_index = @intCast(Zir.Inst.Index, astgen.instructions.len);
1672 astgen.instructions.appendAssumeCapacity(.{
1673 .tag = .extended,
1674 .data = .{ .extended = .{
1675 .opcode = .alloc,
1676 .small = small,
1677 .operand = payload_index,
1678 } },
1679 });
1680 gz.instructions.appendAssumeCapacity(new_index);
1681 return gz.indexToRef(new_index);
1682 }
1683
1633 /// Asserts that `str` is 8 or fewer bytes.1684 /// Asserts that `str` is 8 or fewer bytes.
1634 pub fn addSmallStr(1685 pub fn addSmallStr(
1635 gz: *GenZir,1686 gz: *GenZir,
src/Sema.zig+11
...@@ -516,6 +516,7 @@ fn zirExtended(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErro...@@ -516,6 +516,7 @@ fn zirExtended(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerErro
516 .error_return_trace => return sema.zirErrorReturnTrace(block, extended),516 .error_return_trace => return sema.zirErrorReturnTrace(block, extended),
517 .frame => return sema.zirFrame( block, extended),517 .frame => return sema.zirFrame( block, extended),
518 .frame_address => return sema.zirFrameAddress( block, extended),518 .frame_address => return sema.zirFrameAddress( block, extended),
519 .alloc => return sema.zirAllocExtended( block, extended),
519 .c_undef => return sema.zirCUndef( block, extended),520 .c_undef => return sema.zirCUndef( block, extended),
520 .c_include => return sema.zirCInclude( block, extended),521 .c_include => return sema.zirCInclude( block, extended),
521 .c_define => return sema.zirCDefine( block, extended),522 .c_define => return sema.zirCDefine( block, extended),
...@@ -1131,6 +1132,16 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) In...@@ -1131,6 +1132,16 @@ fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) In
1131 return sema.analyzeLoad(block, src, result_ptr, result_ptr.src);1132 return sema.analyzeLoad(block, src, result_ptr, result_ptr.src);
1132}1133}
11331134
1135fn zirAllocExtended(
1136 sema: *Sema,
1137 block: *Scope.Block,
1138 extended: Zir.Inst.Extended.InstData,
1139) InnerError!*Inst {
1140 const extra = sema.code.extraData(Zir.Inst.AllocExtended, extended.operand);
1141 const src: LazySrcLoc = .{ .node_offset = extra.data.src_node };
1142 return sema.mod.fail(&block.base, src, "TODO implement Sema.zirAllocExtended", .{});
1143}
1144
1134fn zirAllocComptime(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {1145fn zirAllocComptime(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) InnerError!*Inst {
1135 const inst_data = sema.code.instructions.items(.data)[inst].un_node;1146 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
1136 const src = inst_data.src();1147 const src = inst_data.src();
src/Zir.zig+16-1
...@@ -926,7 +926,6 @@ pub const Inst = struct {...@@ -926,7 +926,6 @@ pub const Inst = struct {
926 /// Allocates stack local memory.926 /// Allocates stack local memory.
927 /// Uses the `un_node` union field. The operand is the type of the allocated object.927 /// Uses the `un_node` union field. The operand is the type of the allocated object.
928 /// The node source location points to a var decl node.928 /// The node source location points to a var decl node.
929 /// Indicates the beginning of a new statement in debug info.
930 alloc,929 alloc,
931 /// Same as `alloc` except mutable.930 /// Same as `alloc` except mutable.
932 alloc_mut,931 alloc_mut,
...@@ -1251,6 +1250,14 @@ pub const Inst = struct {...@@ -1251,6 +1250,14 @@ pub const Inst = struct {
1251 /// Implements the `@frameAddress` builtin.1250 /// Implements the `@frameAddress` builtin.
1252 /// `operand` is `src_node: i32`.1251 /// `operand` is `src_node: i32`.
1253 frame_address,1252 frame_address,
1253 /// Same as `alloc` from `Tag` but may contain an alignment instruction.
1254 /// `operand` is payload index to `AllocExtended`.
1255 /// `small`:
1256 /// * 0b000X - has type
1257 /// * 0b00X0 - has alignment
1258 /// * 0b0X00 - 1=const, 0=var
1259 /// * 0bX000 - is comptime
1260 alloc,
1254 /// `operand` is payload index to `UnNode`.1261 /// `operand` is payload index to `UnNode`.
1255 c_undef,1262 c_undef,
1256 /// `operand` is payload index to `UnNode`.1263 /// `operand` is payload index to `UnNode`.
...@@ -2200,6 +2207,13 @@ pub const Inst = struct {...@@ -2200,6 +2207,13 @@ pub const Inst = struct {
2200 args: Ref,2207 args: Ref,
2201 };2208 };
22022209
2210 /// Trailing:
2211 /// 0. type_inst: Ref, // if small 0b000X is set
2212 /// 1. align_inst: Ref, // if small 0b00X0 is set
2213 pub const AllocExtended = struct {
2214 src_node: i32,
2215 };
2216
2203 /// Trailing: `CompileErrors.Item` for each `items_len`.2217 /// Trailing: `CompileErrors.Item` for each `items_len`.
2204 pub const CompileErrors = struct {2218 pub const CompileErrors = struct {
2205 items_len: u32,2219 items_len: u32,
...@@ -2571,6 +2585,7 @@ const Writer = struct {...@@ -2571,6 +2585,7 @@ const Writer = struct {
2571 => try self.writeExtNode(stream, extended),2585 => try self.writeExtNode(stream, extended),
25722586
2573 .func,2587 .func,
2588 .alloc,
2574 .c_undef,2589 .c_undef,
2575 .c_include,2590 .c_include,
2576 .c_define,2591 .c_define,