asmExpr
Function parameters
Parameters
- gz:*GenZir
- scope:*Scope
- node:Ast.Node.Index
- full:Ast.full.Asm
Functions in this namespace
Functions
Source
Implementation
fn asmExpr(
gz: *GenZir,
scope: *Scope,
ri: ResultInfo,
node: Ast.Node.Index,
full: Ast.full.Asm,
) InnerError!Zir.Inst.Ref {
const astgen = gz.astgen;
const tree = astgen.tree;
const TagAndTmpl = struct { tag: Zir.Inst.Extended, tmpl: Zir.NullTerminatedString };
const tag_and_tmpl: TagAndTmpl = switch (tree.nodeTag(full.ast.template)) {
.string_literal => .{
.tag = .@"asm",
.tmpl = (try astgen.strLitAsString(tree.nodeMainToken(full.ast.template))).index,
},
.multiline_string_literal => .{
.tag = .@"asm",
.tmpl = (try astgen.strLitNodeAsString(full.ast.template)).index,
},
else => .{
.tag = .asm_expr,
.tmpl = @enumFromInt(@intFromEnum(try comptimeExpr(gz, scope, .{ .rl = .none }, full.ast.template, .inline_assembly_code))),
},
};
// See https://github.com/ziglang/zig/issues/215 and related issues discussing
// possible inline assembly improvements. Until then here is status quo AstGen
// for assembly syntax. It's used by std lib crypto aesni.zig.
const is_container_asm = astgen.fn_block == null;
if (is_container_asm) {
if (full.volatile_token) |t|
return astgen.failTok(t, "volatile is meaningless on global assembly", .{});
if (full.outputs.len != 0 or full.inputs.len != 0 or full.ast.clobbers != .none)
return astgen.failNode(node, "global assembly cannot have inputs, outputs, or clobbers", .{});
} else {
if (full.outputs.len == 0 and full.volatile_token == null) {
return astgen.failNode(node, "assembly expression with no output must be marked volatile", .{});
}
}
if (full.outputs.len >= 16) {
return astgen.failNode(full.outputs[16], "too many asm outputs", .{});
}
var outputs_buffer: [15]Zir.Inst.Asm.Output = undefined;
const outputs = outputs_buffer[0..full.outputs.len];
var output_type_bits: u32 = 0;
for (full.outputs, 0..) |output_node, i| {
const symbolic_name = tree.nodeMainToken(output_node);
const name = try astgen.identAsString(symbolic_name);
const constraint_token = symbolic_name + 2;
const constraint = (try astgen.strLitAsString(constraint_token)).index;
const has_arrow = tree.tokenTag(symbolic_name + 4) == .arrow;
if (has_arrow) {
if (output_type_bits != 0) {
return astgen.failNode(output_node, "inline assembly allows up to one output value", .{});
}
output_type_bits |= @as(u32, 1) << @intCast(i);
const out_type_node = tree.nodeData(output_node).opt_node_and_token[0].unwrap().?;
const out_type_inst = try typeExpr(gz, scope, out_type_node);
outputs[i] = .{
.name = name,
.constraint = constraint,
.operand = out_type_inst,
};
} else {
const ident_token = symbolic_name + 4;
// TODO have a look at #215 and related issues and decide how to
// handle outputs. Do we want this to be identifiers?
// Or maybe we want to force this to be expressions with a pointer type.
outputs[i] = .{
.name = name,
.constraint = constraint,
.operand = try localVarRef(gz, scope, .{ .rl = .ref }, node, ident_token),
};
}
}
if (full.inputs.len >= 32) {
return astgen.failNode(full.inputs[32], "too many asm inputs", .{});
}
var inputs_buffer: [31]Zir.Inst.Asm.Input = undefined;
const inputs = inputs_buffer[0..full.inputs.len];
for (full.inputs, 0..) |input_node, i| {
const symbolic_name = tree.nodeMainToken(input_node);
const name = try astgen.identAsString(symbolic_name);
const constraint_token = symbolic_name + 2;
const constraint = (try astgen.strLitAsString(constraint_token)).index;
const operand = try expr(gz, scope, .{ .rl = .none }, tree.nodeData(input_node).node_and_token[0]);
inputs[i] = .{
.name = name,
.constraint = constraint,
.operand = operand,
};
}
const clobbers: Zir.Inst.Ref = if (full.ast.clobbers.unwrap()) |clobbers_node|
try comptimeExpr(gz, scope, .{ .rl = .{
.coerced_ty = try gz.addBuiltinValue(clobbers_node, .clobbers),
} }, clobbers_node, .clobber)
else
.none;
const result = try gz.addAsm(.{
.tag = tag_and_tmpl.tag,
.node = node,
.asm_source = tag_and_tmpl.tmpl,
.is_volatile = full.volatile_token != null,
.output_type_bits = output_type_bits,
.outputs = outputs,
.inputs = inputs,
.clobbers = clobbers,
});
return rvalue(gz, ri, result, node);
}