Commit 2edc6c1a3f
Changed files (5)
src/all_types.hpp
@@ -631,7 +631,6 @@ struct AstNodeAsmExpr {
ZigList<Buf*> 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,
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");
}
}
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<LLVMTypeRef>(input_and_output_count);
+// LLVMValueRef *param_values = allocate<LLVMValueRef>(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:
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<typename T>
static T *ir_create_instruction(IrExecutable *exec, AstNode *source_node) {
T *special_instruction = allocate<T>(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<IrInstructionAsm>(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<IrInstruction *>(node->data.asm_expr.input_list.length);
+ IrInstruction **output_types = allocate<IrInstruction *>(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<LLVMTypeRef>(input_and_output_count);
-// LLVMValueRef *param_values = allocate<LLVMValueRef>(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);
-// }
-//}
-//
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");
}