diff --git a/src/all_types.hpp b/src/all_types.hpp index c92ab364c5..d3d1a907d1 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1460,6 +1460,8 @@ struct CodeGen { ConstExprValue const_void_val; ConstExprValue panic_msg_vals[PanicMsgIdCount]; + + Buf global_asm; }; enum VarLinkage { diff --git a/src/codegen.cpp b/src/codegen.cpp index 5e803795f1..83b7e01614 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -73,6 +73,8 @@ CodeGen *codegen_create(Buf *root_source_dir, const ZigTarget *target) { g->is_test_build = false; g->want_h_file = true; + buf_resize(&g->global_asm, 0); + // reserve index 0 to indicate no error g->error_decls.append(nullptr); @@ -3725,6 +3727,10 @@ static void do_code_gen(CodeGen *g) { } assert(!g->errors.length); + if (buf_len(&g->global_asm) != 0) { + LLVMSetModuleInlineAsm(g->module, buf_ptr(&g->global_asm)); + } + ZigLLVMDIBuilderFinalize(g->dbuilder); if (g->verbose) { diff --git a/src/ir.cpp b/src/ir.cpp index 4f3f756d49..6f5f5fbbd2 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -9896,13 +9896,30 @@ static TypeTableEntry *ir_analyze_instruction_slice_type(IrAnalyze *ira, static TypeTableEntry *ir_analyze_instruction_asm(IrAnalyze *ira, IrInstructionAsm *asm_instruction) { assert(asm_instruction->base.source_node->type == NodeTypeAsmExpr); + AstNodeAsmExpr *asm_expr = &asm_instruction->base.source_node->data.asm_expr; + + bool global_scope = (scope_fn_entry(asm_instruction->base.scope) == nullptr); + if (global_scope) { + if (asm_expr->output_list.length != 0 || asm_expr->input_list.length != 0 || + asm_expr->clobber_list.length != 0) + { + ir_add_error(ira, &asm_instruction->base, + buf_sprintf("global assembly cannot have inputs, outputs, or clobbers")); + return ira->codegen->builtin_types.entry_invalid; + } + + buf_append_char(&ira->codegen->global_asm, '\n'); + buf_append_buf(&ira->codegen->global_asm, asm_expr->asm_template); + + ir_build_const_from(ira, &asm_instruction->base); + return ira->codegen->builtin_types.entry_void; + } + if (!ir_emit_global_runtime_side_effect(ira, &asm_instruction->base)) return ira->codegen->builtin_types.entry_invalid; // TODO validate the output types and variable types - AstNodeAsmExpr *asm_expr = &asm_instruction->base.source_node->data.asm_expr; - IrInstruction **input_list = allocate(asm_expr->input_list.length); IrInstruction **output_types = allocate(asm_expr->output_list.length); diff --git a/test/cases/asm.zig b/test/cases/asm.zig new file mode 100644 index 0000000000..ea7dc47ef1 --- /dev/null +++ b/test/cases/asm.zig @@ -0,0 +1,23 @@ +const assert = @import("std").debug.assert; + +comptime { + if (@compileVar("arch") == Arch.x86_64) { + asm volatile ( + \\.globl aoeu; + \\.type aoeu, @function; + \\.set aoeu, derp; + ); + } +} + +test "module level assembly" { + if (@compileVar("arch") == Arch.x86_64) { + assert(aoeu() == 1234); + } +} + +extern fn aoeu() -> i32; + +export fn derp() -> i32 { + return 1234; +} diff --git a/test/run_tests.cpp b/test/run_tests.cpp index 9b7ef38391..c5ff6dcd8c 100644 --- a/test/run_tests.cpp +++ b/test/run_tests.cpp @@ -1834,6 +1834,20 @@ fn foo(e: error) -> u2 { } export fn entry() -> usize { @sizeOf(@typeOf(foo)) } )SOURCE", 1, ".tmp_source.zig:5:14: error: too many error values to fit in 'u2'"); + + add_compile_fail_case("asm at compile time", R"SOURCE( +comptime { + doSomeAsm(); +} + +fn doSomeAsm() { + asm volatile ( + \\.globl aoeu; + \\.type aoeu, @function; + \\.set aoeu, derp; + ); +} + )SOURCE", 1, ".tmp_source.zig:7:5: error: unable to evaluate constant expression"); } ////////////////////////////////////////////////////////////////////////////// diff --git a/test/self_hosted.zig b/test/self_hosted.zig index 8968e08709..432e85114d 100644 --- a/test/self_hosted.zig +++ b/test/self_hosted.zig @@ -1,5 +1,6 @@ comptime { _ = @import("cases/array.zig"); + _ = @import("cases/asm.zig"); _ = @import("cases/atomics.zig"); _ = @import("cases/bool.zig"); _ = @import("cases/cast.zig");