From 8bad5dfa72a33dec3919c3c3cb7590e51d03723b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sat, 20 Mar 2021 21:48:35 -0700 Subject: [PATCH] astgen: implement inline assembly --- BRANCH_TODO | 2 +- src/Module.zig | 35 ++++++++++++++++++------ src/Sema.zig | 3 +- src/astgen.zig | 74 ++++++++++++++++++++++++++++---------------------- src/zir.zig | 2 +- 5 files changed, 71 insertions(+), 45 deletions(-) diff --git a/BRANCH_TODO b/BRANCH_TODO index 159518c6d9..73fd28b676 100644 --- a/BRANCH_TODO +++ b/BRANCH_TODO @@ -29,4 +29,4 @@ Performance optimizations to look into: tags associated with them. * use a smaller encoding for the auto generated return void at the end of function ZIR. - + * enum literals can use small strings diff --git a/src/Module.zig b/src/Module.zig index cb1c11cda7..9830e43d4a 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -1183,6 +1183,22 @@ pub const Scope = struct { }); } + pub fn addStrTok( + gz: *GenZir, + tag: zir.Inst.Tag, + str_index: u32, + /// Absolute token index. This function does the conversion to Decl offset. + abs_tok_index: ast.TokenIndex, + ) !zir.Inst.Ref { + return gz.add(.{ + .tag = tag, + .data = .{ .str_tok = .{ + .start = str_index, + .src_tok = abs_tok_index - gz.zir_code.decl.srcToken(), + } }, + }); + } + pub fn addBin( gz: *GenZir, tag: zir.Inst.Tag, @@ -4090,10 +4106,10 @@ pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex) if (!mem.startsWith(u8, ident_name, "@")) { return ident_name; } - var buf = std.ArrayList(u8).init(mod.gpa); - defer buf.deinit(); + var buf: std.ArrayListUnmanaged(u8) = .{}; + defer buf.deinit(mod.gpa); try parseStrLit(mod, scope, token, &buf, ident_name, 1); - return buf.toOwnedSlice(); + return buf.toOwnedSlice(mod.gpa); } /// Given an identifier token, obtain the string for it (possibly parsing as a string @@ -4103,16 +4119,16 @@ pub fn appendIdentStr( mod: *Module, scope: *Scope, token: ast.TokenIndex, - buf: *ArrayList(u8), + buf: *std.ArrayListUnmanaged(u8), ) InnerError!void { const tree = scope.tree(); const token_tags = tree.tokens.items(.tag); assert(token_tags[token] == .identifier); const ident_name = tree.tokenSlice(token); if (!mem.startsWith(u8, ident_name, "@")) { - return buf.appendSlice(ident_name); + return buf.appendSlice(mod.gpa, ident_name); } else { - return parseStrLit(scope, token, buf, ident_name, 1); + return mod.parseStrLit(scope, token, buf, ident_name, 1); } } @@ -4121,14 +4137,17 @@ pub fn parseStrLit( mod: *Module, scope: *Scope, token: ast.TokenIndex, - buf: *std.ArrayList(u8), + buf: *std.ArrayListUnmanaged(u8), bytes: []const u8, offset: u32, ) InnerError!void { const tree = scope.tree(); const token_starts = tree.tokens.items(.start); const raw_string = bytes[offset..]; - switch (try std.zig.string_literal.parseAppend(buf, raw_string)) { + var buf_managed = buf.toManaged(mod.gpa); + const result = std.zig.string_literal.parseAppend(&buf_managed, raw_string); + buf.* = buf_managed.toUnmanaged(); + switch (try result) { .success => return, .invalid_character => |bad_index| { return mod.failOff( diff --git a/src/Sema.zig b/src/Sema.zig index 91d170493f..d039b5abd4 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -787,8 +787,7 @@ fn zirBlockFlat( try parent_block.instructions.appendSlice(sema.gpa, copied_instructions); // The result of a flat block is the last instruction. - const last_zir_inst = body[body.len - 1]; - return sema.resolveInst(last_zir_inst); + return sema.inst_map[body[body.len - 1]]; } fn zirBlock( diff --git a/src/astgen.zig b/src/astgen.zig index 554ec822bc..17ec1c8d32 100644 --- a/src/astgen.zig +++ b/src/astgen.zig @@ -383,8 +383,8 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In .identifier => return identifier(mod, scope, rl, node), - .asm_simple => return asmExpr(mod, scope, rl, tree.asmSimple(node)), - .@"asm" => return asmExpr(mod, scope, rl, tree.asmFull(node)), + .asm_simple => return asmExpr(mod, scope, rl, node, tree.asmSimple(node)), + .@"asm" => return asmExpr(mod, scope, rl, node, tree.asmFull(node)), .string_literal => return stringLiteral(mod, scope, rl, node), .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 return blockExpr(mod, scope, rl, node, statements); }, .enum_literal => { - if (true) @panic("TODO update for zir-memory-layout"); const ident_token = main_tokens[node]; - const gen_zir = scope.getGenZir(); - const string_bytes = &gen_zir.zir_exec.string_bytes; - const str_index = string_bytes.items.len; + const string_bytes = &gz.zir_code.string_bytes; + const str_index = @intCast(u32, string_bytes.items.len); try mod.appendIdentStr(scope, ident_token, string_bytes); - const str_len = string_bytes.items.len - str_index; - const result = try gen_zir.addStr(.enum_literal, str_index, str_len); - return rvalue(mod, scope, rl, result); + try string_bytes.append(mod.gpa, 0); + const result = try gz.addStrTok(.enum_literal, str_index, ident_token); + return rvalue(mod, scope, rl, result, node); }, .error_value => { if (true) @panic("TODO update for zir-memory-layout"); @@ -2994,48 +2992,58 @@ fn floatLiteral( return rvalue(mod, scope, rl, result); } -fn asmExpr(mod: *Module, scope: *Scope, rl: ResultLoc, full: ast.full.Asm) InnerError!zir.Inst.Ref { - if (true) @panic("TODO update for zir-memory-layout"); +fn asmExpr( + mod: *Module, + scope: *Scope, + rl: ResultLoc, + node: ast.Node.Index, + full: ast.full.Asm, +) InnerError!zir.Inst.Ref { const arena = scope.arena(); const tree = scope.tree(); const main_tokens = tree.nodes.items(.main_token); const token_starts = tree.tokens.items(.start); const node_datas = tree.nodes.items(.data); + const gz = scope.getGenZir(); + + const str_type = @enumToInt(zir.Const.const_slice_u8_type); + const str_type_rl: ResultLoc = .{ .ty = str_type }; + const asm_source = try expr(mod, scope, str_type_rl, full.ast.template); if (full.outputs.len != 0) { return mod.failTok(scope, full.ast.asm_token, "TODO implement asm with an output", .{}); } + const return_type = @enumToInt(zir.Const.void_type); - const inputs = try arena.alloc([]const u8, full.inputs.len); + const constraints = try arena.alloc(u32, full.inputs.len); const args = try arena.alloc(zir.Inst.Ref, full.inputs.len); - const str_type = try addZIRInstConst(mod, scope, src, .{ - .ty = Type.initTag(.type), - .val = Value.initTag(.const_slice_u8_type), - }); - const str_type_rl: ResultLoc = .{ .ty = str_type }; - for (full.inputs) |input, i| { - // TODO semantically analyze constraints const constraint_token = main_tokens[input] + 2; - inputs[i] = try parseStringLiteral(mod, scope, constraint_token); - args[i] = try expr(mod, scope, .none, node_datas[input].lhs); + const string_bytes = &gz.zir_code.string_bytes; + constraints[i] = @intCast(u32, string_bytes.items.len); + try mod.appendIdentStr(scope, constraint_token, string_bytes); + try string_bytes.append(mod.gpa, 0); + + const usize_rl: ResultLoc = .{ .ty = @enumToInt(zir.Const.usize_type) }; + args[i] = try expr(mod, scope, usize_rl, node_datas[input].lhs); } - const return_type = try addZIRInstConst(mod, scope, src, .{ - .ty = Type.initTag(.type), - .val = Value.initTag(.void_type), - }); - const asm_inst = try addZIRInst(mod, scope, src, zir.Inst.Asm, .{ - .asm_source = try expr(mod, scope, str_type_rl, full.ast.template), + const tag: zir.Inst.Tag = if (full.volatile_token != null) .asm_volatile else .@"asm"; + const result = try gz.addPlNode(.@"asm", node, zir.Inst.Asm{ + .asm_source = asm_source, .return_type = return_type, - }, .{ - .@"volatile" = full.volatile_token != null, - //.clobbers = TODO handle clobbers - .inputs = inputs, - .args = args, + .output = 0, + .args_len = @intCast(u32, full.inputs.len), + .clobbers_len = 0, // TODO implement asm clobbers }); - return rvalue(mod, scope, rl, asm_inst); + + try gz.zir_code.extra.ensureCapacity(mod.gpa, gz.zir_code.extra.items.len + + args.len + constraints.len); + gz.zir_code.extra.appendSliceAssumeCapacity(args); + gz.zir_code.extra.appendSliceAssumeCapacity(constraints); + + return rvalue(mod, scope, rl, result, node); } fn as( diff --git a/src/zir.zig b/src/zir.zig index 2e70d1c8bd..5ddbcd659c 100644 --- a/src/zir.zig +++ b/src/zir.zig @@ -1145,7 +1145,7 @@ pub const Inst = struct { /// Stored in extra. Trailing is: /// * output_name: u32 // index into string_bytes (null terminated) if output is present /// * arg: Ref // for every args_len. - /// * arg_name: u32 // index into string_bytes (null terminated) for every args_len. + /// * constraint: u32 // index into string_bytes (null terminated) for every args_len. /// * clobber: u32 // index into string_bytes (null terminated) for every clobbers_len. pub const Asm = struct { asm_source: Ref,