diff --git a/releasenotes.md b/releasenotes.md index efe1dd70a..9194b3b37 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -21,6 +21,7 @@ - Compiler hang with unaligned load-store pair. #2470 - `??` with void results on both sides cause a compiler crash #2472. - Stack object size limit error on a static object. #2476 +- Compiler segfault when modifying variable using an inline assembly block inside defer #2450. ### Stdlib changes - Added generic `InterfaceList` to store a list of values that implement a specific interface diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 278ae64dc..63bd1f0fc 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -1000,6 +1000,7 @@ typedef struct unsigned short index : 16; AsmOffsetType offset_type : 6; bool neg_offset : 1; + bool resolved : 1; union { struct { diff --git a/src/compiler/copying.c b/src/compiler/copying.c index c8a28feae..cf085cdf8 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -18,6 +18,7 @@ static Decl *copy_decl(CopyStruct *c, Decl *decl); static Decl **copy_decl_list(CopyStruct *c, Decl **decl_list); static Methods *copy_decl_methods(CopyStruct *c, Methods *methods); static TypeInfo *copy_type_info(CopyStruct *c, TypeInfo *source); +static void copy_expr_asm_arg(CopyStruct *c, ExprAsmArg *arg); static inline void copy_reg_ref(CopyStruct *c, void *original, void *result) { @@ -464,20 +465,8 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr) MACRO_COPY_EXPRID(expr->subscript_expr.index.expr); return expr; case EXPR_ASM: - switch (expr->expr_asm_arg.kind) - { - case ASM_ARG_REG: - case ASM_ARG_MEMADDR: - case ASM_ARG_REGVAR: - case ASM_ARG_INT: - case ASM_ARG_MEMVAR: - return expr; - case ASM_ARG_VALUE: - case ASM_ARG_ADDR: - MACRO_COPY_EXPRID(expr->expr_asm_arg.expr_id); - return expr; - } - UNREACHABLE + copy_expr_asm_arg(c, &expr->expr_asm_arg); + return expr; case EXPR_CT_ASSIGNABLE: MACRO_COPY_EXPRID(expr->assignable_expr.expr); MACRO_COPY_EXPRID(expr->assignable_expr.type); @@ -635,6 +624,41 @@ void doc_ast_copy(CopyStruct *c, AstContractStmt *doc) } } +static void copy_expr_asm_arg(CopyStruct *c, ExprAsmArg *arg) +{ + switch (arg->kind) + { + case ASM_ARG_MEMADDR: + case ASM_ARG_REGVAR: + case ASM_ARG_MEMVAR: + if (arg->resolved) fixup_decl(c, &arg->ident.ident_decl); + return; + case ASM_ARG_REG: + case ASM_ARG_INT: + return; + case ASM_ARG_ADDR: + MACRO_COPY_EXPRID(arg->base); + MACRO_COPY_EXPRID(arg->idx); + return; + case ASM_ARG_VALUE: + MACRO_COPY_EXPRID(arg->expr_id); + return; + } + UNREACHABLE_VOID +} +static ExprAsmArg **copy_expr_asm_arg_list(CopyStruct *c, ExprAsmArg **args) +{ + ExprAsmArg **new_args = NULL; + FOREACH(ExprAsmArg *, arg, args) + { + ExprAsmArg *new_arg = MALLOCS(ExprAsmArg); + *new_arg = *arg; + copy_expr_asm_arg(c, new_arg); + vec_add(new_args, new_arg); + } + return new_args; +} + Ast *ast_copy_deep(CopyStruct *c, Ast *source) { if (!source) return NULL; @@ -681,6 +705,9 @@ RETRY: *block = *ast->asm_block_stmt.block; ast->asm_block_stmt.block = block; MACRO_COPY_ASTID(block->asm_stmt); + MACRO_COPY_AST_LIST(block->labels); + block->input = copy_expr_asm_arg_list(c, block->input); + block->output_vars = copy_expr_asm_arg_list(c, block->output_vars); } break; case AST_ASM_STMT: diff --git a/src/compiler/sema_asm.c b/src/compiler/sema_asm.c index 46d64d0b3..5cc39eea5 100644 --- a/src/compiler/sema_asm.c +++ b/src/compiler/sema_asm.c @@ -528,6 +528,7 @@ static inline bool sema_check_asm_arg_value(SemaContext *context, AsmInlineBlock } static inline bool sema_check_asm_arg(SemaContext *context, AsmInlineBlock *block, AsmInstruction *instr, AsmArgType arg_type, Expr *expr) { + expr->expr_asm_arg.resolved = true; switch (expr->expr_asm_arg.kind) { case ASM_ARG_INT: diff --git a/src/compiler/sema_liveness.c b/src/compiler/sema_liveness.c index fea401856..075b806fe 100644 --- a/src/compiler/sema_liveness.c +++ b/src/compiler/sema_liveness.c @@ -68,28 +68,33 @@ static void sema_trace_stmt_chain_liveness(AstId astid) } REMINDER("Optimize to ignore after return"); } +static void sema_trace_expr_asm_arg(ExprAsmArg *arg) +{ + switch (arg->kind) + { + case ASM_ARG_ADDR: + sema_trace_exprid_liveness(arg->base); + sema_trace_exprid_liveness(arg->idx); + return; + case ASM_ARG_REG: + case ASM_ARG_INT: + return; + case ASM_ARG_MEMADDR: + case ASM_ARG_MEMVAR: + case ASM_ARG_REGVAR: + sema_trace_decl_liveness(arg->ident.ident_decl); + return; + case ASM_ARG_VALUE: + sema_trace_exprid_liveness(arg->expr_id); + return; + } + UNREACHABLE_VOID +} static void sema_trace_asm_arg_list(ExprAsmArg **list) { FOREACH(ExprAsmArg *, asm_arg, list) { - switch (asm_arg->kind) - { - case ASM_ARG_ADDR: - TODO - return; - case ASM_ARG_REG: - case ASM_ARG_INT: - continue; - case ASM_ARG_MEMADDR: - case ASM_ARG_MEMVAR: - case ASM_ARG_REGVAR: - sema_trace_decl_liveness(asm_arg->ident.ident_decl); - continue; - case ASM_ARG_VALUE: - sema_trace_exprid_liveness(asm_arg->expr_id); - continue; - } - UNREACHABLE_VOID + sema_trace_expr_asm_arg(asm_arg); } } @@ -287,20 +292,8 @@ RETRY: expr = expr->access_resolved_expr.parent; goto RETRY; case EXPR_ASM: - switch (expr->expr_asm_arg.kind) - { - case ASM_ARG_REG: - case ASM_ARG_MEMADDR: - case ASM_ARG_REGVAR: - case ASM_ARG_INT: - case ASM_ARG_MEMVAR: - return; - case ASM_ARG_VALUE: - case ASM_ARG_ADDR: - sema_trace_expr_liveness(exprptr(expr->expr_asm_arg.expr_id)); - return; - } - UNREACHABLE_VOID + sema_trace_expr_asm_arg(&expr->expr_asm_arg); + return; case EXPR_BINARY: case EXPR_BITASSIGN: sema_trace_expr_liveness(exprptr(expr->binary_expr.left)); diff --git a/test/test_suite/asm/asm_defer.c3t b/test/test_suite/asm/asm_defer.c3t new file mode 100644 index 000000000..a2deb4ba4 --- /dev/null +++ b/test/test_suite/asm/asm_defer.c3t @@ -0,0 +1,28 @@ +// #target: macos-x64 +module test; +fn int main(String[] args) +{ + defer + { + int x; + asm + { + movl [x], 1; + } + } + return 0; +} + +/* #expect: test.ll + +entry: + %args = alloca %"char[][]", align 8 + %x = alloca i32, align 4 + store ptr %0, ptr %args, align 8 + %ptradd = getelementptr inbounds i8, ptr %args, i64 8 + store i64 %1, ptr %ptradd, align 8 + store i32 0, ptr %x, align 4 + %2 = load i32, ptr %x, align 4 + call void asm sideeffect alignstack "movl $$1, ($0)\0A", "r,~{flags},~{dirflag},~{fspr}"(i32 %2) + ret i32 0 +} \ No newline at end of file