mirror of
https://github.com/ziglang/zig.git
synced 2024-11-27 15:42:49 +00:00
Accept comptime-known expression for asm
This commit is contained in:
parent
b7be57766b
commit
26c8930b95
@ -1495,13 +1495,13 @@ fn parseSwitchExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
|
||||
return &node.base;
|
||||
}
|
||||
|
||||
/// AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN STRINGLITERAL AsmOutput? RPAREN
|
||||
/// AsmExpr <- KEYWORD_asm KEYWORD_volatile? LPAREN Expr AsmOutput? RPAREN
|
||||
fn parseAsmExpr(arena: *Allocator, it: *TokenIterator, tree: *Tree) !?*Node {
|
||||
const asm_token = eatToken(it, .Keyword_asm) orelse return null;
|
||||
const volatile_token = eatToken(it, .Keyword_volatile);
|
||||
_ = try expectToken(it, tree, .LParen);
|
||||
const template = try expectNode(arena, it, tree, parseStringLiteral, AstError{
|
||||
.ExpectedStringLiteral = AstError.ExpectedStringLiteral{ .token = it.index },
|
||||
const template = try expectNode(arena, it, tree, parseExpr, AstError{
|
||||
.ExpectedExpr = AstError.ExpectedExpr{ .token = it.index },
|
||||
});
|
||||
|
||||
const node = try arena.create(Node.Asm);
|
||||
|
@ -1,3 +1,26 @@
|
||||
test "zig fmt: asm expression with comptime content" {
|
||||
try testCanonical(
|
||||
\\comptime {
|
||||
\\ asm ("foo" ++ "bar");
|
||||
\\}
|
||||
\\pub fn main() void {
|
||||
\\ asm volatile ("foo" ++ "bar");
|
||||
\\ asm volatile ("foo" ++ "bar"
|
||||
\\ : [_] "" (x)
|
||||
\\ );
|
||||
\\ asm volatile ("foo" ++ "bar"
|
||||
\\ : [_] "" (x)
|
||||
\\ : [_] "" (y)
|
||||
\\ );
|
||||
\\ asm volatile ("foo" ++ "bar"
|
||||
\\ : [_] "" (x)
|
||||
\\ : [_] "" (y)
|
||||
\\ : "h", "e", "l", "l", "o"
|
||||
\\ );
|
||||
\\}
|
||||
\\
|
||||
);
|
||||
}
|
||||
test "zig fmt: var struct field" {
|
||||
try testCanonical(
|
||||
\\pub const Pointer = struct {
|
||||
|
@ -949,7 +949,7 @@ struct AsmToken {
|
||||
|
||||
struct AstNodeAsmExpr {
|
||||
Token *volatile_token;
|
||||
Token *asm_template;
|
||||
AstNode *asm_template;
|
||||
ZigList<AsmOutput*> output_list;
|
||||
ZigList<AsmInput*> input_list;
|
||||
ZigList<Buf*> clobber_list;
|
||||
@ -2496,8 +2496,8 @@ enum IrInstructionId {
|
||||
IrInstructionIdArrayType,
|
||||
IrInstructionIdAnyFrameType,
|
||||
IrInstructionIdSliceType,
|
||||
IrInstructionIdGlobalAsm,
|
||||
IrInstructionIdAsm,
|
||||
IrInstructionIdAsmSrc,
|
||||
IrInstructionIdAsmGen,
|
||||
IrInstructionIdSizeOf,
|
||||
IrInstructionIdTestNonNull,
|
||||
IrInstructionIdOptionalUnwrapPtr,
|
||||
@ -3049,13 +3049,19 @@ struct IrInstructionSliceType {
|
||||
bool is_allow_zero;
|
||||
};
|
||||
|
||||
struct IrInstructionGlobalAsm {
|
||||
struct IrInstructionAsmSrc {
|
||||
IrInstruction base;
|
||||
|
||||
Buf *asm_code;
|
||||
IrInstruction *asm_template;
|
||||
IrInstruction **input_list;
|
||||
IrInstruction **output_types;
|
||||
ZigVar **output_vars;
|
||||
size_t return_count;
|
||||
bool has_side_effects;
|
||||
bool is_global;
|
||||
};
|
||||
|
||||
struct IrInstructionAsm {
|
||||
struct IrInstructionAsmGen {
|
||||
IrInstruction base;
|
||||
|
||||
Buf *asm_template;
|
||||
|
@ -884,7 +884,9 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
|
||||
{
|
||||
AstNodeAsmExpr *asm_expr = &node->data.asm_expr;
|
||||
const char *volatile_str = (asm_expr->volatile_token != nullptr) ? " volatile" : "";
|
||||
fprintf(ar->f, "asm%s (\"%s\"\n", volatile_str, buf_ptr(&asm_expr->asm_template->data.str_lit.str));
|
||||
fprintf(ar->f, "asm%s (", volatile_str);
|
||||
render_node_ungrouped(ar, asm_expr->asm_template);
|
||||
fprintf(ar->f, ")");
|
||||
print_indent(ar);
|
||||
fprintf(ar->f, ": ");
|
||||
for (size_t i = 0; i < asm_expr->output_list.length; i += 1) {
|
||||
|
@ -4437,7 +4437,7 @@ static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok, Buf *src_
|
||||
return SIZE_MAX;
|
||||
}
|
||||
|
||||
static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstructionAsm *instruction) {
|
||||
static LLVMValueRef ir_render_asm_gen(CodeGen *g, IrExecutable *executable, IrInstructionAsmGen *instruction) {
|
||||
AstNode *asm_node = instruction->base.source_node;
|
||||
assert(asm_node->type == NodeTypeAsmExpr);
|
||||
AstNodeAsmExpr *asm_expr = &asm_node->data.asm_expr;
|
||||
@ -6135,7 +6135,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
|
||||
case IrInstructionIdPtrCastSrc:
|
||||
case IrInstructionIdCmpxchgSrc:
|
||||
case IrInstructionIdLoadPtr:
|
||||
case IrInstructionIdGlobalAsm:
|
||||
case IrInstructionIdHasDecl:
|
||||
case IrInstructionIdUndeclaredIdent:
|
||||
case IrInstructionIdCallSrc:
|
||||
@ -6156,6 +6155,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
|
||||
case IrInstructionIdAwaitSrc:
|
||||
case IrInstructionIdSplatSrc:
|
||||
case IrInstructionIdMergeErrSets:
|
||||
case IrInstructionIdAsmSrc:
|
||||
zig_unreachable();
|
||||
|
||||
case IrInstructionIdDeclVarGen:
|
||||
@ -6192,8 +6192,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
|
||||
return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction);
|
||||
case IrInstructionIdUnionFieldPtr:
|
||||
return ir_render_union_field_ptr(g, executable, (IrInstructionUnionFieldPtr *)instruction);
|
||||
case IrInstructionIdAsm:
|
||||
return ir_render_asm(g, executable, (IrInstructionAsm *)instruction);
|
||||
case IrInstructionIdAsmGen:
|
||||
return ir_render_asm_gen(g, executable, (IrInstructionAsmGen *)instruction);
|
||||
case IrInstructionIdTestNonNull:
|
||||
return ir_render_test_non_null(g, executable, (IrInstructionTestNonNull *)instruction);
|
||||
case IrInstructionIdOptionalUnwrapPtr:
|
||||
|
159
src/ir.cpp
159
src/ir.cpp
@ -339,10 +339,10 @@ static void destroy_instruction(IrInstruction *inst) {
|
||||
return destroy(reinterpret_cast<IrInstructionSliceType *>(inst), name);
|
||||
case IrInstructionIdAnyFrameType:
|
||||
return destroy(reinterpret_cast<IrInstructionAnyFrameType *>(inst), name);
|
||||
case IrInstructionIdGlobalAsm:
|
||||
return destroy(reinterpret_cast<IrInstructionGlobalAsm *>(inst), name);
|
||||
case IrInstructionIdAsm:
|
||||
return destroy(reinterpret_cast<IrInstructionAsm *>(inst), name);
|
||||
case IrInstructionIdAsmSrc:
|
||||
return destroy(reinterpret_cast<IrInstructionAsmSrc *>(inst), name);
|
||||
case IrInstructionIdAsmGen:
|
||||
return destroy(reinterpret_cast<IrInstructionAsmGen *>(inst), name);
|
||||
case IrInstructionIdSizeOf:
|
||||
return destroy(reinterpret_cast<IrInstructionSizeOf *>(inst), name);
|
||||
case IrInstructionIdTestNonNull:
|
||||
@ -1028,12 +1028,12 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSliceType *) {
|
||||
return IrInstructionIdSliceType;
|
||||
}
|
||||
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionGlobalAsm *) {
|
||||
return IrInstructionIdGlobalAsm;
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionAsmSrc *) {
|
||||
return IrInstructionIdAsmSrc;
|
||||
}
|
||||
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionAsm *) {
|
||||
return IrInstructionIdAsm;
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionAsmGen *) {
|
||||
return IrInstructionIdAsmGen;
|
||||
}
|
||||
|
||||
static constexpr IrInstructionId ir_instruction_id(IrInstructionSizeOf *) {
|
||||
@ -2268,18 +2268,39 @@ static IrInstruction *ir_build_slice_type(IrBuilder *irb, Scope *scope, AstNode
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_global_asm(IrBuilder *irb, Scope *scope, AstNode *source_node, Buf *asm_code) {
|
||||
IrInstructionGlobalAsm *instruction = ir_build_instruction<IrInstructionGlobalAsm>(irb, scope, source_node);
|
||||
instruction->asm_code = asm_code;
|
||||
static IrInstruction *ir_build_asm_src(IrBuilder *irb, Scope *scope, AstNode *source_node,
|
||||
IrInstruction *asm_template, IrInstruction **input_list, IrInstruction **output_types,
|
||||
ZigVar **output_vars, size_t return_count, bool has_side_effects, bool is_global)
|
||||
{
|
||||
IrInstructionAsmSrc *instruction = ir_build_instruction<IrInstructionAsmSrc>(irb, scope, source_node);
|
||||
instruction->asm_template = asm_template;
|
||||
instruction->input_list = input_list;
|
||||
instruction->output_types = output_types;
|
||||
instruction->output_vars = output_vars;
|
||||
instruction->return_count = return_count;
|
||||
instruction->has_side_effects = has_side_effects;
|
||||
instruction->is_global = is_global;
|
||||
|
||||
assert(source_node->type == NodeTypeAsmExpr);
|
||||
for (size_t i = 0; i < source_node->data.asm_expr.output_list.length; i += 1) {
|
||||
IrInstruction *output_type = output_types[i];
|
||||
if (output_type) ir_ref_instruction(output_type, irb->current_basic_block);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < source_node->data.asm_expr.input_list.length; i += 1) {
|
||||
IrInstruction *input_value = input_list[i];
|
||||
ir_ref_instruction(input_value, irb->current_basic_block);
|
||||
}
|
||||
|
||||
return &instruction->base;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_build_asm(IrBuilder *irb, Scope *scope, AstNode *source_node,
|
||||
static IrInstruction *ir_build_asm_gen(IrAnalyze *ira, Scope *scope, AstNode *source_node,
|
||||
Buf *asm_template, AsmToken *token_list, size_t token_list_len,
|
||||
IrInstruction **input_list, IrInstruction **output_types, ZigVar **output_vars, size_t return_count,
|
||||
bool has_side_effects)
|
||||
{
|
||||
IrInstructionAsm *instruction = ir_build_instruction<IrInstructionAsm>(irb, scope, source_node);
|
||||
IrInstructionAsmGen *instruction = ir_build_instruction<IrInstructionAsmGen>(&ira->new_irb, scope, source_node);
|
||||
instruction->asm_template = asm_template;
|
||||
instruction->token_list = token_list;
|
||||
instruction->token_list_len = token_list_len;
|
||||
@ -2292,12 +2313,12 @@ static IrInstruction *ir_build_asm(IrBuilder *irb, Scope *scope, AstNode *source
|
||||
assert(source_node->type == NodeTypeAsmExpr);
|
||||
for (size_t i = 0; i < source_node->data.asm_expr.output_list.length; i += 1) {
|
||||
IrInstruction *output_type = output_types[i];
|
||||
if (output_type) ir_ref_instruction(output_type, irb->current_basic_block);
|
||||
if (output_type) ir_ref_instruction(output_type, ira->new_irb.current_basic_block);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < source_node->data.asm_expr.input_list.length; i += 1) {
|
||||
IrInstruction *input_value = input_list[i];
|
||||
ir_ref_instruction(input_value, irb->current_basic_block);
|
||||
ir_ref_instruction(input_value, ira->new_irb.current_basic_block);
|
||||
}
|
||||
|
||||
return &instruction->base;
|
||||
@ -7494,7 +7515,7 @@ static IrInstruction *ir_gen_undefined_literal(IrBuilder *irb, Scope *scope, Ast
|
||||
return ir_build_const_undefined(irb, scope, node);
|
||||
}
|
||||
|
||||
static Error parse_asm_template(IrBuilder *irb, AstNode *source_node, Buf *asm_template,
|
||||
static Error parse_asm_template(IrAnalyze *ira, AstNode *source_node, Buf *asm_template,
|
||||
ZigList<AsmToken> *tok_list)
|
||||
{
|
||||
// TODO Connect the errors in this function back up to the actual source location
|
||||
@ -7542,7 +7563,7 @@ static Error parse_asm_template(IrBuilder *irb, AstNode *source_node, Buf *asm_t
|
||||
cur_tok->end = i;
|
||||
state = StateStart;
|
||||
} else {
|
||||
add_node_error(irb->codegen, source_node,
|
||||
add_node_error(ira->codegen, source_node,
|
||||
buf_create_from_str("expected a '%' or '['"));
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
@ -7565,7 +7586,7 @@ static Error parse_asm_template(IrBuilder *irb, AstNode *source_node, Buf *asm_t
|
||||
{
|
||||
// do nothing
|
||||
} else {
|
||||
add_node_error(irb->codegen, source_node,
|
||||
add_node_error(ira->codegen, source_node,
|
||||
buf_sprintf("invalid substitution character: '%c'", c));
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
}
|
||||
@ -7578,7 +7599,7 @@ static Error parse_asm_template(IrBuilder *irb, AstNode *source_node, Buf *asm_t
|
||||
break;
|
||||
case StatePercent:
|
||||
case StateVar:
|
||||
add_node_error(irb->codegen, source_node, buf_sprintf("unexpected end of assembly template"));
|
||||
add_node_error(ira->codegen, source_node, buf_sprintf("unexpected end of assembly template"));
|
||||
return ErrorSemanticAnalyzeFail;
|
||||
case StateTemplate:
|
||||
cur_tok->end = buf_len(asm_template);
|
||||
@ -7607,14 +7628,16 @@ static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok, Buf *src_
|
||||
}
|
||||
|
||||
static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *node) {
|
||||
Error err;
|
||||
assert(node->type == NodeTypeAsmExpr);
|
||||
AstNodeAsmExpr *asm_expr = &node->data.asm_expr;
|
||||
|
||||
IrInstruction *asm_template = ir_gen_node(irb, asm_expr->asm_template, scope);
|
||||
if (asm_template == irb->codegen->invalid_instruction)
|
||||
return irb->codegen->invalid_instruction;
|
||||
|
||||
bool is_volatile = asm_expr->volatile_token != nullptr;
|
||||
bool in_fn_scope = (scope_fn_entry(scope) != nullptr);
|
||||
|
||||
Buf *template_buf = &asm_expr->asm_template->data.str_lit.str;
|
||||
|
||||
if (!in_fn_scope) {
|
||||
if (is_volatile) {
|
||||
add_token_error(irb->codegen, node->owner, asm_expr->volatile_token,
|
||||
@ -7630,12 +7653,8 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod
|
||||
return irb->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
return ir_build_global_asm(irb, scope, node, template_buf);
|
||||
}
|
||||
|
||||
ZigList<AsmToken> tok_list = {};
|
||||
if ((err = parse_asm_template(irb, node, template_buf, &tok_list))) {
|
||||
return irb->codegen->invalid_instruction;
|
||||
return ir_build_asm_src(irb, scope, node, asm_template, nullptr, nullptr,
|
||||
nullptr, 0, is_volatile, true);
|
||||
}
|
||||
|
||||
IrInstruction **input_list = allocate<IrInstruction *>(asm_expr->input_list.length);
|
||||
@ -7693,24 +7712,8 @@ static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, Scope *scope, AstNode *nod
|
||||
input_list[i] = input_value;
|
||||
}
|
||||
|
||||
for (size_t token_i = 0; token_i < tok_list.length; token_i += 1) {
|
||||
AsmToken asm_token = tok_list.at(token_i);
|
||||
if (asm_token.id == AsmTokenIdVar) {
|
||||
size_t index = find_asm_index(irb->codegen, node, &asm_token, template_buf);
|
||||
if (index == SIZE_MAX) {
|
||||
const char *ptr = buf_ptr(template_buf) + asm_token.start + 2;
|
||||
uint32_t len = asm_token.end - asm_token.start - 2;
|
||||
|
||||
add_node_error(irb->codegen, node,
|
||||
buf_sprintf("could not find '%.*s' in the inputs or outputs",
|
||||
len, ptr));
|
||||
return irb->codegen->invalid_instruction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ir_build_asm(irb, scope, node, template_buf, tok_list.items, tok_list.length,
|
||||
input_list, output_types, output_vars, return_count, is_volatile);
|
||||
return ir_build_asm_src(irb, scope, node, asm_template, input_list, output_types,
|
||||
output_vars, return_count, is_volatile, false);
|
||||
}
|
||||
|
||||
static IrInstruction *ir_gen_if_optional_expr(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval,
|
||||
@ -20150,21 +20153,49 @@ static IrInstruction *ir_analyze_instruction_slice_type(IrAnalyze *ira,
|
||||
return result;
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_instruction_global_asm(IrAnalyze *ira, IrInstructionGlobalAsm *instruction) {
|
||||
buf_append_char(&ira->codegen->global_asm, '\n');
|
||||
buf_append_buf(&ira->codegen->global_asm, instruction->asm_code);
|
||||
static IrInstruction *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionAsmSrc *asm_instruction) {
|
||||
Error err;
|
||||
|
||||
return ir_const_void(ira, &instruction->base);
|
||||
}
|
||||
|
||||
static IrInstruction *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionAsm *asm_instruction) {
|
||||
assert(asm_instruction->base.source_node->type == NodeTypeAsmExpr);
|
||||
|
||||
AstNode *node = asm_instruction->base.source_node;
|
||||
AstNodeAsmExpr *asm_expr = &asm_instruction->base.source_node->data.asm_expr;
|
||||
|
||||
Buf *template_buf = ir_resolve_str(ira, asm_instruction->asm_template->child);
|
||||
if (template_buf == nullptr)
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
if (asm_instruction->is_global) {
|
||||
buf_append_char(&ira->codegen->global_asm, '\n');
|
||||
buf_append_buf(&ira->codegen->global_asm, template_buf);
|
||||
|
||||
return ir_const_void(ira, &asm_instruction->base);
|
||||
}
|
||||
|
||||
if (!ir_emit_global_runtime_side_effect(ira, &asm_instruction->base))
|
||||
return ira->codegen->invalid_instruction;
|
||||
|
||||
ZigList<AsmToken> tok_list = {};
|
||||
if ((err = parse_asm_template(ira, node, template_buf, &tok_list))) {
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
|
||||
for (size_t token_i = 0; token_i < tok_list.length; token_i += 1) {
|
||||
AsmToken asm_token = tok_list.at(token_i);
|
||||
if (asm_token.id == AsmTokenIdVar) {
|
||||
size_t index = find_asm_index(ira->codegen, node, &asm_token, template_buf);
|
||||
if (index == SIZE_MAX) {
|
||||
const char *ptr = buf_ptr(template_buf) + asm_token.start + 2;
|
||||
uint32_t len = asm_token.end - asm_token.start - 2;
|
||||
|
||||
add_node_error(ira->codegen, node,
|
||||
buf_sprintf("could not find '%.*s' in the inputs or outputs",
|
||||
len, ptr));
|
||||
return ira->codegen->invalid_instruction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO validate the output types and variable types
|
||||
|
||||
IrInstruction **input_list = allocate<IrInstruction *>(asm_expr->input_list.length);
|
||||
@ -20197,9 +20228,9 @@ static IrInstruction *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionAs
|
||||
input_list[i] = input_value;
|
||||
}
|
||||
|
||||
IrInstruction *result = ir_build_asm(&ira->new_irb,
|
||||
IrInstruction *result = ir_build_asm_gen(ira,
|
||||
asm_instruction->base.scope, asm_instruction->base.source_node,
|
||||
asm_instruction->asm_template, asm_instruction->token_list, asm_instruction->token_list_len,
|
||||
template_buf, tok_list.items, tok_list.length,
|
||||
input_list, output_types, asm_instruction->output_vars, asm_instruction->return_count,
|
||||
asm_instruction->has_side_effects);
|
||||
result->value->type = return_type;
|
||||
@ -27722,6 +27753,7 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
|
||||
case IrInstructionIdSplatGen:
|
||||
case IrInstructionIdVectorExtractElem:
|
||||
case IrInstructionIdVectorStoreElem:
|
||||
case IrInstructionIdAsmGen:
|
||||
zig_unreachable();
|
||||
|
||||
case IrInstructionIdReturn:
|
||||
@ -27768,10 +27800,8 @@ static IrInstruction *ir_analyze_instruction_base(IrAnalyze *ira, IrInstruction
|
||||
return ir_analyze_instruction_any_frame_type(ira, (IrInstructionAnyFrameType *)instruction);
|
||||
case IrInstructionIdSliceType:
|
||||
return ir_analyze_instruction_slice_type(ira, (IrInstructionSliceType *)instruction);
|
||||
case IrInstructionIdGlobalAsm:
|
||||
return ir_analyze_instruction_global_asm(ira, (IrInstructionGlobalAsm *)instruction);
|
||||
case IrInstructionIdAsm:
|
||||
return ir_analyze_instruction_asm(ira, (IrInstructionAsm *)instruction);
|
||||
case IrInstructionIdAsmSrc:
|
||||
return ir_analyze_instruction_asm(ira, (IrInstructionAsmSrc *)instruction);
|
||||
case IrInstructionIdArrayType:
|
||||
return ir_analyze_instruction_array_type(ira, (IrInstructionArrayType *)instruction);
|
||||
case IrInstructionIdSizeOf:
|
||||
@ -28183,7 +28213,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
|
||||
case IrInstructionIdAssertZero:
|
||||
case IrInstructionIdAssertNonNull:
|
||||
case IrInstructionIdResizeSlice:
|
||||
case IrInstructionIdGlobalAsm:
|
||||
case IrInstructionIdUndeclaredIdent:
|
||||
case IrInstructionIdEndExpr:
|
||||
case IrInstructionIdPtrOfArrayToSlice:
|
||||
@ -28303,9 +28332,15 @@ bool ir_has_side_effects(IrInstruction *instruction) {
|
||||
case IrInstructionIdVectorExtractElem:
|
||||
return false;
|
||||
|
||||
case IrInstructionIdAsm:
|
||||
case IrInstructionIdAsmSrc:
|
||||
{
|
||||
IrInstructionAsm *asm_instruction = (IrInstructionAsm *)instruction;
|
||||
IrInstructionAsmSrc *asm_instruction = (IrInstructionAsmSrc *)instruction;
|
||||
return asm_instruction->has_side_effects;
|
||||
}
|
||||
|
||||
case IrInstructionIdAsmGen:
|
||||
{
|
||||
IrInstructionAsmGen *asm_instruction = (IrInstructionAsmGen *)instruction;
|
||||
return asm_instruction->has_side_effects;
|
||||
}
|
||||
case IrInstructionIdUnwrapErrPayload:
|
||||
|
@ -124,10 +124,10 @@ const char* ir_instruction_type_str(IrInstructionId id) {
|
||||
return "AnyFrameType";
|
||||
case IrInstructionIdSliceType:
|
||||
return "SliceType";
|
||||
case IrInstructionIdGlobalAsm:
|
||||
return "GlobalAsm";
|
||||
case IrInstructionIdAsm:
|
||||
return "Asm";
|
||||
case IrInstructionIdAsmSrc:
|
||||
return "AsmSrc";
|
||||
case IrInstructionIdAsmGen:
|
||||
return "AsmGen";
|
||||
case IrInstructionIdSizeOf:
|
||||
return "SizeOf";
|
||||
case IrInstructionIdTestNonNull:
|
||||
@ -888,11 +888,50 @@ static void ir_print_any_frame_type(IrPrint *irp, IrInstructionAnyFrameType *ins
|
||||
}
|
||||
}
|
||||
|
||||
static void ir_print_global_asm(IrPrint *irp, IrInstructionGlobalAsm *instruction) {
|
||||
fprintf(irp->f, "asm(\"%s\")", buf_ptr(instruction->asm_code));
|
||||
static void ir_print_asm_src(IrPrint *irp, IrInstructionAsmSrc *instruction) {
|
||||
assert(instruction->base.source_node->type == NodeTypeAsmExpr);
|
||||
AstNodeAsmExpr *asm_expr = &instruction->base.source_node->data.asm_expr;
|
||||
const char *volatile_kw = instruction->has_side_effects ? " volatile" : "";
|
||||
fprintf(irp->f, "asm%s (", volatile_kw);
|
||||
ir_print_other_instruction(irp, instruction->asm_template);
|
||||
|
||||
for (size_t i = 0; i < asm_expr->output_list.length; i += 1) {
|
||||
AsmOutput *asm_output = asm_expr->output_list.at(i);
|
||||
if (i != 0) fprintf(irp->f, ", ");
|
||||
|
||||
fprintf(irp->f, "[%s] \"%s\" (",
|
||||
buf_ptr(asm_output->asm_symbolic_name),
|
||||
buf_ptr(asm_output->constraint));
|
||||
if (asm_output->return_type) {
|
||||
fprintf(irp->f, "-> ");
|
||||
ir_print_other_instruction(irp, instruction->output_types[i]);
|
||||
} else {
|
||||
fprintf(irp->f, "%s", buf_ptr(asm_output->variable_name));
|
||||
}
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
fprintf(irp->f, " : ");
|
||||
for (size_t i = 0; i < asm_expr->input_list.length; i += 1) {
|
||||
AsmInput *asm_input = asm_expr->input_list.at(i);
|
||||
|
||||
if (i != 0) fprintf(irp->f, ", ");
|
||||
fprintf(irp->f, "[%s] \"%s\" (",
|
||||
buf_ptr(asm_input->asm_symbolic_name),
|
||||
buf_ptr(asm_input->constraint));
|
||||
ir_print_other_instruction(irp, instruction->input_list[i]);
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
fprintf(irp->f, " : ");
|
||||
for (size_t i = 0; i < asm_expr->clobber_list.length; i += 1) {
|
||||
Buf *reg_name = asm_expr->clobber_list.at(i);
|
||||
if (i != 0) fprintf(irp->f, ", ");
|
||||
fprintf(irp->f, "\"%s\"", buf_ptr(reg_name));
|
||||
}
|
||||
fprintf(irp->f, ")");
|
||||
}
|
||||
|
||||
static void ir_print_asm(IrPrint *irp, IrInstructionAsm *instruction) {
|
||||
static void ir_print_asm_gen(IrPrint *irp, IrInstructionAsmGen *instruction) {
|
||||
assert(instruction->base.source_node->type == NodeTypeAsmExpr);
|
||||
AstNodeAsmExpr *asm_expr = &instruction->base.source_node->data.asm_expr;
|
||||
const char *volatile_kw = instruction->has_side_effects ? " volatile" : "";
|
||||
@ -2121,11 +2160,11 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction, bool
|
||||
case IrInstructionIdAnyFrameType:
|
||||
ir_print_any_frame_type(irp, (IrInstructionAnyFrameType *)instruction);
|
||||
break;
|
||||
case IrInstructionIdGlobalAsm:
|
||||
ir_print_global_asm(irp, (IrInstructionGlobalAsm *)instruction);
|
||||
case IrInstructionIdAsmSrc:
|
||||
ir_print_asm_src(irp, (IrInstructionAsmSrc *)instruction);
|
||||
break;
|
||||
case IrInstructionIdAsm:
|
||||
ir_print_asm(irp, (IrInstructionAsm *)instruction);
|
||||
case IrInstructionIdAsmGen:
|
||||
ir_print_asm_gen(irp, (IrInstructionAsmGen *)instruction);
|
||||
break;
|
||||
case IrInstructionIdSizeOf:
|
||||
ir_print_size_of(irp, (IrInstructionSizeOf *)instruction);
|
||||
|
@ -1891,7 +1891,7 @@ static AstNode *ast_parse_asm_expr(ParseContext *pc) {
|
||||
|
||||
Token *volatile_token = eat_token_if(pc, TokenIdKeywordVolatile);
|
||||
expect_token(pc, TokenIdLParen);
|
||||
Token *asm_template = expect_token(pc, TokenIdStringLiteral);
|
||||
AstNode *asm_template = ast_expect(pc, ast_parse_expr);
|
||||
AstNode *res = ast_parse_asm_output(pc);
|
||||
if (res == nullptr)
|
||||
res = ast_create_node_no_line_info(pc, NodeTypeAsmExpr);
|
||||
|
Loading…
Reference in New Issue
Block a user