authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-20 21:48:35-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-20 21:48:35-07:00
log8bad5dfa72a33dec3919c3c3cb7590e51d03723b
treed70339e575f8f209364ef6066bf6d3e2cece7ca9
parent260c610708451624eab783bc4e99388e2b28a3ba

astgen: implement inline assembly


5 files changed, 71 insertions(+), 45 deletions(-)

BRANCH_TODO+1-1
...@@ -29,4 +29,4 @@ Performance optimizations to look into:...@@ -29,4 +29,4 @@ Performance optimizations to look into:
29 tags associated with them.29 tags associated with them.
30 * use a smaller encoding for the auto generated return void at the end of30 * use a smaller encoding for the auto generated return void at the end of
31 function ZIR.31 function ZIR.
3232 * enum literals can use small strings
src/Module.zig+27-8
...@@ -1183,6 +1183,22 @@ pub const Scope = struct {...@@ -1183,6 +1183,22 @@ pub const Scope = struct {
1183 });1183 });
1184 }1184 }
11851185
1186 pub fn addStrTok(
1187 gz: *GenZir,
1188 tag: zir.Inst.Tag,
1189 str_index: u32,
1190 /// Absolute token index. This function does the conversion to Decl offset.
1191 abs_tok_index: ast.TokenIndex,
1192 ) !zir.Inst.Ref {
1193 return gz.add(.{
1194 .tag = tag,
1195 .data = .{ .str_tok = .{
1196 .start = str_index,
1197 .src_tok = abs_tok_index - gz.zir_code.decl.srcToken(),
1198 } },
1199 });
1200 }
1201
1186 pub fn addBin(1202 pub fn addBin(
1187 gz: *GenZir,1203 gz: *GenZir,
1188 tag: zir.Inst.Tag,1204 tag: zir.Inst.Tag,
...@@ -4090,10 +4106,10 @@ pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex)...@@ -4090,10 +4106,10 @@ pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex)
4090 if (!mem.startsWith(u8, ident_name, "@")) {4106 if (!mem.startsWith(u8, ident_name, "@")) {
4091 return ident_name;4107 return ident_name;
4092 }4108 }
4093 var buf = std.ArrayList(u8).init(mod.gpa);4109 var buf: std.ArrayListUnmanaged(u8) = .{};
4094 defer buf.deinit();4110 defer buf.deinit(mod.gpa);
4095 try parseStrLit(mod, scope, token, &buf, ident_name, 1);4111 try parseStrLit(mod, scope, token, &buf, ident_name, 1);
4096 return buf.toOwnedSlice();4112 return buf.toOwnedSlice(mod.gpa);
4097}4113}
40984114
4099/// Given an identifier token, obtain the string for it (possibly parsing as a string4115/// Given an identifier token, obtain the string for it (possibly parsing as a string
...@@ -4103,16 +4119,16 @@ pub fn appendIdentStr(...@@ -4103,16 +4119,16 @@ pub fn appendIdentStr(
4103 mod: *Module,4119 mod: *Module,
4104 scope: *Scope,4120 scope: *Scope,
4105 token: ast.TokenIndex,4121 token: ast.TokenIndex,
4106 buf: *ArrayList(u8),4122 buf: *std.ArrayListUnmanaged(u8),
4107) InnerError!void {4123) InnerError!void {
4108 const tree = scope.tree();4124 const tree = scope.tree();
4109 const token_tags = tree.tokens.items(.tag);4125 const token_tags = tree.tokens.items(.tag);
4110 assert(token_tags[token] == .identifier);4126 assert(token_tags[token] == .identifier);
4111 const ident_name = tree.tokenSlice(token);4127 const ident_name = tree.tokenSlice(token);
4112 if (!mem.startsWith(u8, ident_name, "@")) {4128 if (!mem.startsWith(u8, ident_name, "@")) {
4113 return buf.appendSlice(ident_name);4129 return buf.appendSlice(mod.gpa, ident_name);
4114 } else {4130 } else {
4115 return parseStrLit(scope, token, buf, ident_name, 1);4131 return mod.parseStrLit(scope, token, buf, ident_name, 1);
4116 }4132 }
4117}4133}
41184134
...@@ -4121,14 +4137,17 @@ pub fn parseStrLit(...@@ -4121,14 +4137,17 @@ pub fn parseStrLit(
4121 mod: *Module,4137 mod: *Module,
4122 scope: *Scope,4138 scope: *Scope,
4123 token: ast.TokenIndex,4139 token: ast.TokenIndex,
4124 buf: *std.ArrayList(u8),4140 buf: *std.ArrayListUnmanaged(u8),
4125 bytes: []const u8,4141 bytes: []const u8,
4126 offset: u32,4142 offset: u32,
4127) InnerError!void {4143) InnerError!void {
4128 const tree = scope.tree();4144 const tree = scope.tree();
4129 const token_starts = tree.tokens.items(.start);4145 const token_starts = tree.tokens.items(.start);
4130 const raw_string = bytes[offset..];4146 const raw_string = bytes[offset..];
4131 switch (try std.zig.string_literal.parseAppend(buf, raw_string)) {4147 var buf_managed = buf.toManaged(mod.gpa);
4148 const result = std.zig.string_literal.parseAppend(&buf_managed, raw_string);
4149 buf.* = buf_managed.toUnmanaged();
4150 switch (try result) {
4132 .success => return,4151 .success => return,
4133 .invalid_character => |bad_index| {4152 .invalid_character => |bad_index| {
4134 return mod.failOff(4153 return mod.failOff(
src/Sema.zig+1-2
...@@ -787,8 +787,7 @@ fn zirBlockFlat(...@@ -787,8 +787,7 @@ fn zirBlockFlat(
787 try parent_block.instructions.appendSlice(sema.gpa, copied_instructions);787 try parent_block.instructions.appendSlice(sema.gpa, copied_instructions);
788788
789 // The result of a flat block is the last instruction.789 // The result of a flat block is the last instruction.
790 const last_zir_inst = body[body.len - 1];790 return sema.inst_map[body[body.len - 1]];
791 return sema.resolveInst(last_zir_inst);
792}791}
793792
794fn zirBlock(793fn zirBlock(
src/astgen.zig+41-33
...@@ -383,8 +383,8 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In...@@ -383,8 +383,8 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
383383
384 .identifier => return identifier(mod, scope, rl, node),384 .identifier => return identifier(mod, scope, rl, node),
385385
386 .asm_simple => return asmExpr(mod, scope, rl, tree.asmSimple(node)),386 .asm_simple => return asmExpr(mod, scope, rl, node, tree.asmSimple(node)),
387 .@"asm" => return asmExpr(mod, scope, rl, tree.asmFull(node)),387 .@"asm" => return asmExpr(mod, scope, rl, node, tree.asmFull(node)),
388388
389 .string_literal => return stringLiteral(mod, scope, rl, node),389 .string_literal => return stringLiteral(mod, scope, rl, node),
390 .multiline_string_literal => return multilineStringLiteral(mod, scope, rl, node),390 .multiline_string_literal => return multilineStringLiteral(mod, scope, rl, node),
...@@ -497,15 +497,13 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In...@@ -497,15 +497,13 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
497 return blockExpr(mod, scope, rl, node, statements);497 return blockExpr(mod, scope, rl, node, statements);
498 },498 },
499 .enum_literal => {499 .enum_literal => {
500 if (true) @panic("TODO update for zir-memory-layout");
501 const ident_token = main_tokens[node];500 const ident_token = main_tokens[node];
502 const gen_zir = scope.getGenZir();501 const string_bytes = &gz.zir_code.string_bytes;
503 const string_bytes = &gen_zir.zir_exec.string_bytes;502 const str_index = @intCast(u32, string_bytes.items.len);
504 const str_index = string_bytes.items.len;
505 try mod.appendIdentStr(scope, ident_token, string_bytes);503 try mod.appendIdentStr(scope, ident_token, string_bytes);
506 const str_len = string_bytes.items.len - str_index;504 try string_bytes.append(mod.gpa, 0);
507 const result = try gen_zir.addStr(.enum_literal, str_index, str_len);505 const result = try gz.addStrTok(.enum_literal, str_index, ident_token);
508 return rvalue(mod, scope, rl, result);506 return rvalue(mod, scope, rl, result, node);
509 },507 },
510 .error_value => {508 .error_value => {
511 if (true) @panic("TODO update for zir-memory-layout");509 if (true) @panic("TODO update for zir-memory-layout");
...@@ -2994,48 +2992,58 @@ fn floatLiteral(...@@ -2994,48 +2992,58 @@ fn floatLiteral(
2994 return rvalue(mod, scope, rl, result);2992 return rvalue(mod, scope, rl, result);
2995}2993}
29962994
2997fn asmExpr(mod: *Module, scope: *Scope, rl: ResultLoc, full: ast.full.Asm) InnerError!zir.Inst.Ref {2995fn asmExpr(
2998 if (true) @panic("TODO update for zir-memory-layout");2996 mod: *Module,
2997 scope: *Scope,
2998 rl: ResultLoc,
2999 node: ast.Node.Index,
3000 full: ast.full.Asm,
3001) InnerError!zir.Inst.Ref {
2999 const arena = scope.arena();3002 const arena = scope.arena();
3000 const tree = scope.tree();3003 const tree = scope.tree();
3001 const main_tokens = tree.nodes.items(.main_token);3004 const main_tokens = tree.nodes.items(.main_token);
3002 const token_starts = tree.tokens.items(.start);3005 const token_starts = tree.tokens.items(.start);
3003 const node_datas = tree.nodes.items(.data);3006 const node_datas = tree.nodes.items(.data);
3007 const gz = scope.getGenZir();
3008
3009 const str_type = @enumToInt(zir.Const.const_slice_u8_type);
3010 const str_type_rl: ResultLoc = .{ .ty = str_type };
3011 const asm_source = try expr(mod, scope, str_type_rl, full.ast.template);
30043012
3005 if (full.outputs.len != 0) {3013 if (full.outputs.len != 0) {
3006 return mod.failTok(scope, full.ast.asm_token, "TODO implement asm with an output", .{});3014 return mod.failTok(scope, full.ast.asm_token, "TODO implement asm with an output", .{});
3007 }3015 }
3016 const return_type = @enumToInt(zir.Const.void_type);
30083017
3009 const inputs = try arena.alloc([]const u8, full.inputs.len);3018 const constraints = try arena.alloc(u32, full.inputs.len);
3010 const args = try arena.alloc(zir.Inst.Ref, full.inputs.len);3019 const args = try arena.alloc(zir.Inst.Ref, full.inputs.len);
30113020
3012 const str_type = try addZIRInstConst(mod, scope, src, .{
3013 .ty = Type.initTag(.type),
3014 .val = Value.initTag(.const_slice_u8_type),
3015 });
3016 const str_type_rl: ResultLoc = .{ .ty = str_type };
3017
3018 for (full.inputs) |input, i| {3021 for (full.inputs) |input, i| {
3019 // TODO semantically analyze constraints
3020 const constraint_token = main_tokens[input] + 2;3022 const constraint_token = main_tokens[input] + 2;
3021 inputs[i] = try parseStringLiteral(mod, scope, constraint_token);3023 const string_bytes = &gz.zir_code.string_bytes;
3022 args[i] = try expr(mod, scope, .none, node_datas[input].lhs);3024 constraints[i] = @intCast(u32, string_bytes.items.len);
3025 try mod.appendIdentStr(scope, constraint_token, string_bytes);
3026 try string_bytes.append(mod.gpa, 0);
3027
3028 const usize_rl: ResultLoc = .{ .ty = @enumToInt(zir.Const.usize_type) };
3029 args[i] = try expr(mod, scope, usize_rl, node_datas[input].lhs);
3023 }3030 }
30243031
3025 const return_type = try addZIRInstConst(mod, scope, src, .{3032 const tag: zir.Inst.Tag = if (full.volatile_token != null) .asm_volatile else .@"asm";
3026 .ty = Type.initTag(.type),3033 const result = try gz.addPlNode(.@"asm", node, zir.Inst.Asm{
3027 .val = Value.initTag(.void_type),3034 .asm_source = asm_source,
3028 });
3029 const asm_inst = try addZIRInst(mod, scope, src, zir.Inst.Asm, .{
3030 .asm_source = try expr(mod, scope, str_type_rl, full.ast.template),
3031 .return_type = return_type,3035 .return_type = return_type,
3032 }, .{3036 .output = 0,
3033 .@"volatile" = full.volatile_token != null,3037 .args_len = @intCast(u32, full.inputs.len),
3034 //.clobbers = TODO handle clobbers3038 .clobbers_len = 0, // TODO implement asm clobbers
3035 .inputs = inputs,
3036 .args = args,
3037 });3039 });
3038 return rvalue(mod, scope, rl, asm_inst);3040
3041 try gz.zir_code.extra.ensureCapacity(mod.gpa, gz.zir_code.extra.items.len +
3042 args.len + constraints.len);
3043 gz.zir_code.extra.appendSliceAssumeCapacity(args);
3044 gz.zir_code.extra.appendSliceAssumeCapacity(constraints);
3045
3046 return rvalue(mod, scope, rl, result, node);
3039}3047}
30403048
3041fn as(3049fn as(
src/zir.zig+1-1
...@@ -1145,7 +1145,7 @@ pub const Inst = struct {...@@ -1145,7 +1145,7 @@ pub const Inst = struct {
1145 /// Stored in extra. Trailing is:1145 /// Stored in extra. Trailing is:
1146 /// * output_name: u32 // index into string_bytes (null terminated) if output is present1146 /// * output_name: u32 // index into string_bytes (null terminated) if output is present
1147 /// * arg: Ref // for every args_len.1147 /// * arg: Ref // for every args_len.
1148 /// * arg_name: u32 // index into string_bytes (null terminated) for every args_len.1148 /// * constraint: u32 // index into string_bytes (null terminated) for every args_len.
1149 /// * clobber: u32 // index into string_bytes (null terminated) for every clobbers_len.1149 /// * clobber: u32 // index into string_bytes (null terminated) for every clobbers_len.
1150 pub const Asm = struct {1150 pub const Asm = struct {
1151 asm_source: Ref,1151 asm_source: Ref,