Commit 0edc2b19fe
Changed files (6)
src/all_types.hpp
@@ -1460,6 +1460,8 @@ struct CodeGen {
ConstExprValue const_void_val;
ConstExprValue panic_msg_vals[PanicMsgIdCount];
+
+ Buf global_asm;
};
enum VarLinkage {
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) {
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<IrInstruction *>(asm_expr->input_list.length);
IrInstruction **output_types = allocate<IrInstruction *>(asm_expr->output_list.length);
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;
+}
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");
}
//////////////////////////////////////////////////////////////////////////////
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");