diff --git a/src/all_types.hpp b/src/all_types.hpp index 627d5a8fd40ab3cf23744fea7328328fff4e2d36..a83ffa5402dd3eedfe5bbc3bff16ed5a3351ddcb 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -631,7 +631,6 @@ struct AstNodeAsmExpr { ZigList clobber_list; // populated by semantic analyzer - size_t return_count; Expr resolved_expr; }; @@ -1449,6 +1448,7 @@ enum IrInstructionId { IrInstructionIdSetFnTest, IrInstructionIdArrayType, IrInstructionIdSliceType, + IrInstructionIdAsm, }; struct IrInstruction { @@ -1716,6 +1716,16 @@ struct IrInstructionSliceType { IrInstruction *child_type; }; +struct IrInstructionAsm { + IrInstruction base; + + // Most information on inline assembly comes from the source node. + IrInstruction **input_list; + IrInstruction **output_types; + size_t return_count; + bool has_side_effects; +}; + enum LValPurpose { LValPurposeNone, LValPurposeAssign, diff --git a/src/ast_render.cpp b/src/ast_render.cpp index fbae957e5731762cd4855d8b52b32535408f41a3..6a24b4faad9a060f8aebf1933e74dc66203ba866 100644 --- a/src/ast_render.cpp +++ b/src/ast_render.cpp @@ -407,13 +407,19 @@ static void render_node(AstRender *ar, AstNode *node) { break; } case NodeTypeBlock: + if (node->data.block.statements.length == 0) { + fprintf(ar->f, "{}"); + break; + } fprintf(ar->f, "{\n"); ar->indent += ar->indent_size; for (size_t i = 0; i < node->data.block.statements.length; i += 1) { AstNode *statement = node->data.block.statements.at(i); print_indent(ar); render_node(ar, statement); - fprintf(ar->f, ";\n"); + if (i != node->data.block.statements.length - 1) + fprintf(ar->f, ";"); + fprintf(ar->f, "\n"); } ar->indent -= ar->indent_size; print_indent(ar); @@ -598,6 +604,60 @@ static void render_node(AstRender *ar, AstNode *node) { case NodeTypeVarLiteral: fprintf(ar->f, "var"); break; + case NodeTypeAsmExpr: + { + AstNodeAsmExpr *asm_expr = &node->data.asm_expr; + const char *volatile_str = asm_expr->is_volatile ? " volatile" : ""; + fprintf(ar->f, "asm%s (\"%s\"\n", volatile_str, buf_ptr(asm_expr->asm_template)); + print_indent(ar); + fprintf(ar->f, ": "); + 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(ar->f, ",\n"); + print_indent(ar); + } + + fprintf(ar->f, "[%s] \"%s\" (", + buf_ptr(asm_output->asm_symbolic_name), + buf_ptr(asm_output->constraint)); + if (asm_output->return_type) { + fprintf(ar->f, "-> "); + render_node(ar, asm_output->return_type); + } else { + fprintf(ar->f, "%s", buf_ptr(asm_output->variable_name)); + } + fprintf(ar->f, ")"); + } + fprintf(ar->f, "\n"); + print_indent(ar); + fprintf(ar->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(ar->f, ",\n"); + print_indent(ar); + } + + fprintf(ar->f, "[%s] \"%s\" (", + buf_ptr(asm_input->asm_symbolic_name), + buf_ptr(asm_input->constraint)); + render_node(ar, asm_input->expr); + fprintf(ar->f, ")"); + } + fprintf(ar->f, "\n"); + print_indent(ar); + fprintf(ar->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(ar->f, ", "); + fprintf(ar->f, "\"%s\"", buf_ptr(reg_name)); + } + fprintf(ar->f, ")"); + break; + } case NodeTypeFnDecl: case NodeTypeParamDecl: case NodeTypeErrorValueDecl: @@ -621,7 +681,6 @@ static void render_node(AstRender *ar, AstNode *node) { case NodeTypeGoto: case NodeTypeBreak: case NodeTypeContinue: - case NodeTypeAsmExpr: zig_panic("TODO more ast rendering"); } } diff --git a/src/codegen.cpp b/src/codegen.cpp index 22e9720abb0e303330758cf1d8ca3d08b2e03e74..8fe41917542ee038647d642e319f71bb8421ab3f 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -1537,6 +1537,136 @@ static LLVMValueRef ir_render_struct_field_ptr(CodeGen *g, IrExecutable *executa return LLVMBuildStructGEP(g->builder, struct_ptr, field->gen_index, ""); } +static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstructionAsm *instruction) { + zig_panic("TODO render asm"); +} +//static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok) { +// const char *ptr = buf_ptr(node->data.asm_expr.asm_template) + tok->start + 2; +// size_t len = tok->end - tok->start - 2; +// size_t result = 0; +// for (size_t i = 0; i < node->data.asm_expr.output_list.length; i += 1, result += 1) { +// AsmOutput *asm_output = node->data.asm_expr.output_list.at(i); +// if (buf_eql_mem(asm_output->asm_symbolic_name, ptr, len)) { +// return result; +// } +// } +// for (size_t i = 0; i < node->data.asm_expr.input_list.length; i += 1, result += 1) { +// AsmInput *asm_input = node->data.asm_expr.input_list.at(i); +// if (buf_eql_mem(asm_input->asm_symbolic_name, ptr, len)) { +// return result; +// } +// } +// return SIZE_MAX; +//} +// +//static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) { +// assert(node->type == NodeTypeAsmExpr); +// +// AstNodeAsmExpr *asm_expr = &node->data.asm_expr; +// +// Buf *src_template = asm_expr->asm_template; +// +// Buf llvm_template = BUF_INIT; +// buf_resize(&llvm_template, 0); +// +// for (size_t token_i = 0; token_i < asm_expr->token_list.length; token_i += 1) { +// AsmToken *asm_token = &asm_expr->token_list.at(token_i); +// switch (asm_token->id) { +// case AsmTokenIdTemplate: +// for (size_t offset = asm_token->start; offset < asm_token->end; offset += 1) { +// uint8_t c = *((uint8_t*)(buf_ptr(src_template) + offset)); +// if (c == '$') { +// buf_append_str(&llvm_template, "$$"); +// } else { +// buf_append_char(&llvm_template, c); +// } +// } +// break; +// case AsmTokenIdPercent: +// buf_append_char(&llvm_template, '%'); +// break; +// case AsmTokenIdVar: +// size_t index = find_asm_index(g, node, asm_token); +// assert(index < SIZE_MAX); +// buf_appendf(&llvm_template, "$%zu", index); +// break; +// } +// } +// +// Buf constraint_buf = BUF_INIT; +// buf_resize(&constraint_buf, 0); +// +// assert(asm_expr->return_count == 0 || asm_expr->return_count == 1); +// +// size_t total_constraint_count = asm_expr->output_list.length + +// asm_expr->input_list.length + +// asm_expr->clobber_list.length; +// size_t input_and_output_count = asm_expr->output_list.length + +// asm_expr->input_list.length - +// asm_expr->return_count; +// size_t total_index = 0; +// size_t param_index = 0; +// LLVMTypeRef *param_types = allocate(input_and_output_count); +// LLVMValueRef *param_values = allocate(input_and_output_count); +// for (size_t i = 0; i < asm_expr->output_list.length; i += 1, total_index += 1) { +// AsmOutput *asm_output = asm_expr->output_list.at(i); +// bool is_return = (asm_output->return_type != nullptr); +// assert(*buf_ptr(asm_output->constraint) == '='); +// if (is_return) { +// buf_appendf(&constraint_buf, "=%s", buf_ptr(asm_output->constraint) + 1); +// } else { +// buf_appendf(&constraint_buf, "=*%s", buf_ptr(asm_output->constraint) + 1); +// } +// if (total_index + 1 < total_constraint_count) { +// buf_append_char(&constraint_buf, ','); +// } +// +// if (!is_return) { +// VariableTableEntry *variable = asm_output->variable; +// assert(variable); +// param_types[param_index] = LLVMTypeOf(variable->value_ref); +// param_values[param_index] = variable->value_ref; +// param_index += 1; +// } +// } +// for (size_t i = 0; i < asm_expr->input_list.length; i += 1, total_index += 1, param_index += 1) { +// AsmInput *asm_input = asm_expr->input_list.at(i); +// buf_append_buf(&constraint_buf, asm_input->constraint); +// if (total_index + 1 < total_constraint_count) { +// buf_append_char(&constraint_buf, ','); +// } +// +// TypeTableEntry *expr_type = get_expr_type(asm_input->expr); +// param_types[param_index] = expr_type->type_ref; +// param_values[param_index] = gen_expr(g, asm_input->expr); +// } +// for (size_t i = 0; i < asm_expr->clobber_list.length; i += 1, total_index += 1) { +// Buf *clobber_buf = asm_expr->clobber_list.at(i); +// buf_appendf(&constraint_buf, "~{%s}", buf_ptr(clobber_buf)); +// if (total_index + 1 < total_constraint_count) { +// buf_append_char(&constraint_buf, ','); +// } +// } +// +// LLVMTypeRef ret_type; +// if (asm_expr->return_count == 0) { +// ret_type = LLVMVoidType(); +// } else { +// ret_type = get_expr_type(node)->type_ref; +// } +// LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, input_and_output_count, false); +// +// bool is_volatile = asm_expr->is_volatile || (asm_expr->output_list.length == 0); +// LLVMValueRef asm_fn = LLVMConstInlineAsm(function_type, buf_ptr(&llvm_template), +// buf_ptr(&constraint_buf), is_volatile, false); +// +// set_debug_source_node(g, node); +// return LLVMBuildCall(g->builder, asm_fn, param_values, input_and_output_count, ""); +//} +// + + + static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, IrInstruction *instruction) { set_debug_source_node(g, instruction->source_node); @@ -1579,6 +1709,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_call(g, executable, (IrInstructionCall *)instruction); case IrInstructionIdStructFieldPtr: return ir_render_struct_field_ptr(g, executable, (IrInstructionStructFieldPtr *)instruction); + case IrInstructionIdAsm: + return ir_render_asm(g, executable, (IrInstructionAsm *)instruction); case IrInstructionIdSwitchBr: case IrInstructionIdPhi: case IrInstructionIdContainerInitList: diff --git a/src/ir.cpp b/src/ir.cpp index 3ecad348fdcd2f9e03ac9cf07850816baf1cfed1..d552d7998939a744916fb11104e41742ee7b546f 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -197,6 +197,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionSliceType *) { return IrInstructionIdSliceType; } +static constexpr IrInstructionId ir_instruction_id(IrInstructionAsm *) { + return IrInstructionIdAsm; +} + template static T *ir_create_instruction(IrExecutable *exec, AstNode *source_node) { T *special_instruction = allocate(1); @@ -796,6 +800,38 @@ static IrInstruction *ir_build_slice_type(IrBuilder *irb, AstNode *source_node, return &instruction->base; } +static IrInstruction *ir_build_asm(IrBuilder *irb, AstNode *source_node, IrInstruction **input_list, + IrInstruction **output_types, size_t return_count, bool has_side_effects) +{ + IrInstructionAsm *instruction = ir_build_instruction(irb, source_node); + instruction->input_list = input_list; + instruction->output_types = output_types; + instruction->return_count = return_count; + instruction->has_side_effects = has_side_effects; + + 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); + } + + 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); + } + + return &instruction->base; +} + +static IrInstruction *ir_build_asm_from(IrBuilder *irb, IrInstruction *old_instruction, IrInstruction **input_list, + IrInstruction **output_types, size_t return_count, bool has_side_effects) +{ + IrInstruction *new_instruction = ir_build_asm(irb, old_instruction->source_node, input_list, output_types, + return_count, has_side_effects); + ir_link_new_instruction(new_instruction, old_instruction); + return new_instruction; +} + static void ir_gen_defers_for_block(IrBuilder *irb, BlockContext *inner_block, BlockContext *outer_block, bool gen_error_defers, bool gen_maybe_defers) { @@ -1683,6 +1719,56 @@ static IrInstruction *ir_gen_undefined_literal(IrBuilder *irb, AstNode *node) { return ir_build_const_undefined(irb, node); } +static IrInstruction *ir_gen_asm_expr(IrBuilder *irb, AstNode *node) { + assert(node->type == NodeTypeAsmExpr); + + IrInstruction **input_list = allocate(node->data.asm_expr.input_list.length); + IrInstruction **output_types = allocate(node->data.asm_expr.output_list.length); + size_t return_count = 0; + bool is_volatile = node->data.asm_expr.is_volatile; + if (!is_volatile && node->data.asm_expr.output_list.length == 0) { + add_node_error(irb->codegen, node, + buf_sprintf("assembly expression with no output must be marked volatile")); + return irb->codegen->invalid_instruction; + } + for (size_t i = 0; i < node->data.asm_expr.output_list.length; i += 1) { + AsmOutput *asm_output = node->data.asm_expr.output_list.at(i); + if (asm_output->return_type) { + return_count += 1; + + IrInstruction *return_type = ir_gen_node(irb, asm_output->return_type, node->block_context); + if (return_type == irb->codegen->invalid_instruction) + return irb->codegen->invalid_instruction; + if (return_count > 1) { + add_node_error(irb->codegen, node, + buf_sprintf("inline assembly allows up to one output value")); + return irb->codegen->invalid_instruction; + } + output_types[i] = return_type; + } else { + Buf *variable_name = asm_output->variable_name; + VariableTableEntry *var = find_variable(irb->codegen, node->block_context, variable_name); + if (var) { + asm_output->variable = var; + } else { + add_node_error(irb->codegen, node, + buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name))); + return irb->codegen->invalid_instruction; + } + } + } + for (size_t i = 0; i < node->data.asm_expr.input_list.length; i += 1) { + AsmInput *asm_input = node->data.asm_expr.input_list.at(i); + IrInstruction *input_value = ir_gen_node(irb, asm_input->expr, node->block_context); + if (input_value == irb->codegen->invalid_instruction) + return irb->codegen->invalid_instruction; + + input_list[i] = input_value; + } + + return ir_build_asm(irb, node, input_list, output_types, return_count, is_volatile); +} + static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockContext *block_context, LValPurpose lval) { @@ -1728,11 +1814,12 @@ static IrInstruction *ir_gen_node_extra(IrBuilder *irb, AstNode *node, BlockCont return ir_gen_string_literal(irb, node); case NodeTypeUndefinedLiteral: return ir_gen_undefined_literal(irb, node); + case NodeTypeAsmExpr: + return ir_gen_asm_expr(irb, node); case NodeTypeUnwrapErrorExpr: case NodeTypeDefer: case NodeTypeSliceExpr: case NodeTypeIfVarExpr: - case NodeTypeAsmExpr: case NodeTypeGoto: case NodeTypeBreak: case NodeTypeContinue: @@ -3865,6 +3952,30 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira, zig_unreachable(); } +static TypeTableEntry *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionAsm *asm_instruction) { + assert(asm_instruction->base.source_node->type == NodeTypeAsmExpr); + mark_impure_fn(ira->codegen, asm_instruction->base.source_node->block_context, + asm_instruction->base.source_node); + + // TODO validate the output types and variable types + + AstNodeAsmExpr *asm_expr = &asm_instruction->base.source_node->data.asm_expr; + + TypeTableEntry *return_type = ira->codegen->builtin_types.entry_void; + for (size_t i = 0; i < asm_expr->output_list.length; i += 1) { + AsmOutput *asm_output = asm_expr->output_list.at(i); + if (asm_output->return_type) { + return_type = ir_resolve_type(ira, asm_instruction->output_types[i]); + if (return_type->id == TypeTableEntryIdInvalid) + return ira->codegen->builtin_types.entry_invalid; + } + } + + ir_build_asm_from(&ira->new_irb, &asm_instruction->base, asm_instruction->input_list, + asm_instruction->output_types, asm_instruction->return_count, asm_instruction->has_side_effects); + return return_type; +} + static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) { switch (instruction->id) { case IrInstructionIdInvalid: @@ -3911,6 +4022,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_set_fn_test(ira, (IrInstructionSetFnTest *)instruction); case IrInstructionIdSliceType: return ir_analyze_instruction_slice_type(ira, (IrInstructionSliceType *)instruction); + case IrInstructionIdAsm: + return ir_analyze_instruction_asm(ira, (IrInstructionAsm *)instruction); case IrInstructionIdSwitchBr: case IrInstructionIdCast: case IrInstructionIdContainerInitList: @@ -4020,6 +4133,11 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdArrayType: case IrInstructionIdSliceType: return false; + case IrInstructionIdAsm: + { + IrInstructionAsm *asm_instruction = (IrInstructionAsm *)instruction; + return asm_instruction->has_side_effects; + } } zig_unreachable(); } @@ -7135,44 +7253,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) { // return return_type; //} // -//static TypeTableEntry *analyze_asm_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, -// TypeTableEntry *expected_type, AstNode *node) -//{ -// mark_impure_fn(g, context, node); -// -// node->data.asm_expr.return_count = 0; -// TypeTableEntry *return_type = g->builtin_types.entry_void; -// for (size_t i = 0; i < node->data.asm_expr.output_list.length; i += 1) { -// AsmOutput *asm_output = node->data.asm_expr.output_list.at(i); -// if (asm_output->return_type) { -// node->data.asm_expr.return_count += 1; -// return_type = analyze_type_expr(g, import, context, asm_output->return_type); -// if (node->data.asm_expr.return_count > 1) { -// add_node_error(g, node, -// buf_sprintf("inline assembly allows up to one output value")); -// break; -// } -// } else { -// Buf *variable_name = asm_output->variable_name; -// VariableTableEntry *var = find_variable(g, context, variable_name); -// if (var) { -// asm_output->variable = var; -// return var->type; -// } else { -// add_node_error(g, node, -// buf_sprintf("use of undeclared identifier '%s'", buf_ptr(variable_name))); -// return g->builtin_types.entry_invalid; -// } -// } -// } -// for (size_t i = 0; i < node->data.asm_expr.input_list.length; i += 1) { -// AsmInput *asm_input = node->data.asm_expr.input_list.at(i); -// analyze_expression(g, import, context, nullptr, asm_input->expr); -// } -// -// return return_type; -//} -// //static TypeTableEntry *analyze_error_literal_expr(CodeGen *g, ImportTableEntry *import, // BlockContext *context, AstNode *node, Buf *err_name) //{ @@ -7274,49 +7354,6 @@ IrInstruction *ir_exec_const_result(IrExecutable *exec) { // return var->type; //} // -//static TypeTableEntry *analyze_null_literal_expr(CodeGen *g, ImportTableEntry *import, -// BlockContext *block_context, TypeTableEntry *expected_type, AstNode *node) -//{ -// assert(node->type == NodeTypeNullLiteral); -// -// ConstExprValue *const_val = &get_resolved_expr(node)->const_val; -// const_val->ok = true; -// -// return g->builtin_types.entry_null; -//} -// -//static TypeTableEntry *analyze_undefined_literal_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, -// TypeTableEntry *expected_type, AstNode *node) -//{ -// assert(node->type == NodeTypeUndefinedLiteral); -// -// Expr *expr = get_resolved_expr(node); -// ConstExprValue *const_val = &expr->const_val; -// -// const_val->ok = true; -// const_val->special = ConstValSpecialUndef; -// -// return expected_type ? expected_type : g->builtin_types.entry_undef; -//} -// -//static TypeTableEntry *analyze_zeroes_literal_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, -// TypeTableEntry *expected_type, AstNode *node) -//{ -// Expr *expr = get_resolved_expr(node); -// ConstExprValue *const_val = &expr->const_val; -// -// const_val->ok = true; -// const_val->special = ConstValSpecialZeroes; -// -// return expected_type ? expected_type : g->builtin_types.entry_undef; -//} -// -//static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry *import, -// BlockContext *block_context, TypeTableEntry *expected_type, AstNode *node) -//{ -// return resolve_expr_const_val_as_bignum(g, node, expected_type, node->data.number_literal.bignum, false); -//} -// //static TypeTableEntry *analyze_fn_proto_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context, // TypeTableEntry *expected_type, AstNode *node) //{ @@ -8656,111 +8693,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no // } //} // -//static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) { -// assert(node->type == NodeTypeAsmExpr); -// -// AstNodeAsmExpr *asm_expr = &node->data.asm_expr; -// -// Buf *src_template = asm_expr->asm_template; -// -// Buf llvm_template = BUF_INIT; -// buf_resize(&llvm_template, 0); -// -// for (size_t token_i = 0; token_i < asm_expr->token_list.length; token_i += 1) { -// AsmToken *asm_token = &asm_expr->token_list.at(token_i); -// switch (asm_token->id) { -// case AsmTokenIdTemplate: -// for (size_t offset = asm_token->start; offset < asm_token->end; offset += 1) { -// uint8_t c = *((uint8_t*)(buf_ptr(src_template) + offset)); -// if (c == '$') { -// buf_append_str(&llvm_template, "$$"); -// } else { -// buf_append_char(&llvm_template, c); -// } -// } -// break; -// case AsmTokenIdPercent: -// buf_append_char(&llvm_template, '%'); -// break; -// case AsmTokenIdVar: -// size_t index = find_asm_index(g, node, asm_token); -// assert(index < SIZE_MAX); -// buf_appendf(&llvm_template, "$%zu", index); -// break; -// } -// } -// -// Buf constraint_buf = BUF_INIT; -// buf_resize(&constraint_buf, 0); -// -// assert(asm_expr->return_count == 0 || asm_expr->return_count == 1); -// -// size_t total_constraint_count = asm_expr->output_list.length + -// asm_expr->input_list.length + -// asm_expr->clobber_list.length; -// size_t input_and_output_count = asm_expr->output_list.length + -// asm_expr->input_list.length - -// asm_expr->return_count; -// size_t total_index = 0; -// size_t param_index = 0; -// LLVMTypeRef *param_types = allocate(input_and_output_count); -// LLVMValueRef *param_values = allocate(input_and_output_count); -// for (size_t i = 0; i < asm_expr->output_list.length; i += 1, total_index += 1) { -// AsmOutput *asm_output = asm_expr->output_list.at(i); -// bool is_return = (asm_output->return_type != nullptr); -// assert(*buf_ptr(asm_output->constraint) == '='); -// if (is_return) { -// buf_appendf(&constraint_buf, "=%s", buf_ptr(asm_output->constraint) + 1); -// } else { -// buf_appendf(&constraint_buf, "=*%s", buf_ptr(asm_output->constraint) + 1); -// } -// if (total_index + 1 < total_constraint_count) { -// buf_append_char(&constraint_buf, ','); -// } -// -// if (!is_return) { -// VariableTableEntry *variable = asm_output->variable; -// assert(variable); -// param_types[param_index] = LLVMTypeOf(variable->value_ref); -// param_values[param_index] = variable->value_ref; -// param_index += 1; -// } -// } -// for (size_t i = 0; i < asm_expr->input_list.length; i += 1, total_index += 1, param_index += 1) { -// AsmInput *asm_input = asm_expr->input_list.at(i); -// buf_append_buf(&constraint_buf, asm_input->constraint); -// if (total_index + 1 < total_constraint_count) { -// buf_append_char(&constraint_buf, ','); -// } -// -// TypeTableEntry *expr_type = get_expr_type(asm_input->expr); -// param_types[param_index] = expr_type->type_ref; -// param_values[param_index] = gen_expr(g, asm_input->expr); -// } -// for (size_t i = 0; i < asm_expr->clobber_list.length; i += 1, total_index += 1) { -// Buf *clobber_buf = asm_expr->clobber_list.at(i); -// buf_appendf(&constraint_buf, "~{%s}", buf_ptr(clobber_buf)); -// if (total_index + 1 < total_constraint_count) { -// buf_append_char(&constraint_buf, ','); -// } -// } -// -// LLVMTypeRef ret_type; -// if (asm_expr->return_count == 0) { -// ret_type = LLVMVoidType(); -// } else { -// ret_type = get_expr_type(node)->type_ref; -// } -// LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, input_and_output_count, false); -// -// bool is_volatile = asm_expr->is_volatile || (asm_expr->output_list.length == 0); -// LLVMValueRef asm_fn = LLVMConstInlineAsm(function_type, buf_ptr(&llvm_template), -// buf_ptr(&constraint_buf), is_volatile, false); -// -// set_debug_source_node(g, node); -// return LLVMBuildCall(g->builder, asm_fn, param_values, input_and_output_count, ""); -//} -// //static LLVMValueRef gen_container_init_expr(CodeGen *g, AstNode *node) { // assert(node->type == NodeTypeContainerInitExpr); // @@ -9404,35 +9336,6 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no // return result; //} // -//static size_t find_asm_index(CodeGen *g, AstNode *node, AsmToken *tok) { -// const char *ptr = buf_ptr(node->data.asm_expr.asm_template) + tok->start + 2; -// size_t len = tok->end - tok->start - 2; -// size_t result = 0; -// for (size_t i = 0; i < node->data.asm_expr.output_list.length; i += 1, result += 1) { -// AsmOutput *asm_output = node->data.asm_expr.output_list.at(i); -// if (buf_eql_mem(asm_output->asm_symbolic_name, ptr, len)) { -// return result; -// } -// } -// for (size_t i = 0; i < node->data.asm_expr.input_list.length; i += 1, result += 1) { -// AsmInput *asm_input = node->data.asm_expr.input_list.at(i); -// if (buf_eql_mem(asm_input->asm_symbolic_name, ptr, len)) { -// return result; -// } -// } -// return SIZE_MAX; -//} -// -//static LLVMValueRef gen_symbol(CodeGen *g, AstNode *node) { -// assert(node->type == NodeTypeSymbol); -// VariableTableEntry *variable = get_resolved_expr(node)->variable; -// if (variable) { -// return gen_variable(g, node, variable); -// } -// -// zig_unreachable(); -//} -// //static LLVMValueRef gen_label(CodeGen *g, AstNode *node) { // assert(node->type == NodeTypeLabel); // @@ -9447,13 +9350,3 @@ static void analyze_goto_pass2(CodeGen *g, ImportTableEntry *import, AstNode *no // LLVMPositionBuilderAtEnd(g->builder, basic_block); // return nullptr; //} -// -//static LLVMValueRef gen_variable(CodeGen *g, AstNode *source_node, VariableTableEntry *variable) { -// if (!type_has_bits(variable->type)) { -// return nullptr; -// } else { -// assert(variable->value_ref); -// return get_handle_value(g, variable->value_ref, variable->type); -// } -//} -// diff --git a/src/ir_print.cpp b/src/ir_print.cpp index 1690bf92e3c25a4c2e7b591dc3c00068c387e3fc..02a3942782b8dddcd29ddd4be51a6b8f2dbb48bb 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -420,6 +420,48 @@ static void ir_print_slice_type(IrPrint *irp, IrInstructionSliceType *instructio ir_print_other_instruction(irp, instruction->child_type); } +static void ir_print_asm(IrPrint *irp, IrInstructionAsm *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 (\"%s\") : ", volatile_kw, buf_ptr(asm_expr->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_instruction(IrPrint *irp, IrInstruction *instruction) { ir_print_prefix(irp, instruction); switch (instruction->id) { @@ -503,6 +545,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdSliceType: ir_print_slice_type(irp, (IrInstructionSliceType *)instruction); break; + case IrInstructionIdAsm: + ir_print_asm(irp, (IrInstructionAsm *)instruction); + break; case IrInstructionIdSwitchBr: zig_panic("TODO print more IR instructions"); }