diff --git a/src/compiler/ast.c b/src/compiler/ast.c index a88c96cd7..409a28917 100644 --- a/src/compiler/ast.c +++ b/src/compiler/ast.c @@ -329,7 +329,7 @@ int decl_count_elements(Decl *structlike) return elements; } -bool ast_is_compile_time(Ast *ast, ConstantEvalKind eval_kind) +bool ast_is_compile_time(Ast *ast) { switch (ast->ast_kind) { @@ -338,15 +338,15 @@ bool ast_is_compile_time(Ast *ast, ConstantEvalKind eval_kind) case AST_RETURN_STMT: case AST_BLOCK_EXIT_STMT: if (!ast->return_stmt.expr) return true; - return expr_is_constant_eval(ast->return_stmt.expr, eval_kind); + return expr_is_runtime_const(ast->return_stmt.expr); case AST_EXPR_STMT: - return expr_is_const(ast->expr_stmt); + return expr_is_runtime_const(ast->expr_stmt); case AST_COMPOUND_STMT: { AstId current = ast->compound_stmt.first_stmt; while (current) { - if (!ast_is_compile_time(ast_next(¤t), eval_kind)) return false; + if (!ast_is_compile_time(ast_next(¤t))) return false; } return true; } @@ -360,6 +360,31 @@ bool decl_is_externally_visible(Decl *decl) return decl->is_external_visible || decl->visibility == VISIBLE_PUBLIC || decl->is_export; } +bool decl_is_global(Decl *ident) +{ + switch (ident->var.kind) + { + case VARDECL_LOCAL: + return ident->var.is_static; + case VARDECL_CONST: + case VARDECL_GLOBAL: + return true; + case VARDECL_PARAM: + case VARDECL_MEMBER: + case VARDECL_BITMEMBER: + case VARDECL_PARAM_REF: + case VARDECL_PARAM_EXPR: + case VARDECL_UNWRAPPED: + case VARDECL_ERASE: + case VARDECL_REWRAPPED: + case VARDECL_PARAM_CT: + case VARDECL_PARAM_CT_TYPE: + case VARDECL_LOCAL_CT: + case VARDECL_LOCAL_CT_TYPE: + return false; + } +} + bool decl_is_local(Decl *decl) { return !decl->is_external_visible && decl->visibility != VISIBLE_PUBLIC && !decl->is_export; diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 6e132e1cb..16dd61220 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -146,6 +146,8 @@ typedef struct const char *ptr; ArraySize len; } bytes; + Expr *expr_ref; + Decl *global_ref; Decl *enum_err_val; Type *typeid; ConstInitializer *initializer; @@ -1931,7 +1933,7 @@ INLINE bool no_stdlib(void) bool ast_is_not_empty(Ast *ast); -bool ast_is_compile_time(Ast *ast, ConstantEvalKind eval_kind); +bool ast_is_compile_time(Ast *ast); bool ast_supports_continue(Ast *stmt); INLINE void ast_append(AstId **succ, Ast *next); INLINE void ast_prepend(AstId *first, Ast *ast); @@ -2147,6 +2149,7 @@ bool decl_needs_prefix(Decl *decl); AlignSize decl_find_member_offset(Decl *decl, Decl *member); bool decl_is_externally_visible(Decl *decl); bool decl_is_local(Decl *decl); +bool decl_is_global(Decl *decl); void scratch_buffer_set_extern_decl_name(Decl *decl, bool clear); // --- Expression functions @@ -2158,7 +2161,7 @@ Expr *expr_new_const_bool(SourceSpan span, Type *type, bool value); Expr *expr_new_const_typeid(SourceSpan span, Type *type); bool expr_is_simple(Expr *expr, bool to_float); bool expr_is_pure(Expr *expr); -bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind); +bool expr_is_runtime_const(Expr *expr); Expr *expr_generate_decl(Decl *decl, Expr *assign); void expr_insert_addr(Expr *original); void expr_rewrite_insert_deref(Expr *original); @@ -2176,7 +2179,7 @@ INLINE bool exprid_is_pure(ExprId expr_id); INLINE Type *exprtype(ExprId expr_id); INLINE void expr_replace(Expr *expr, Expr *replacement); INLINE bool expr_poison(Expr *expr); -INLINE bool exprid_is_constant_eval(ExprId expr, ConstantEvalKind eval_kind); +INLINE bool exprid_is_runtime_const(ExprId expr); INLINE bool expr_is_init_list(Expr *expr); INLINE bool expr_is_neg(Expr *expr); INLINE bool expr_is_mult(Expr *expr); @@ -2198,6 +2201,7 @@ INLINE void expr_rewrite_const_untyped_list(Expr *expr, Expr **elements); void expr_rewrite_to_builtin_access(Expr *expr, Expr *parent, BuiltinAccessKind kind, Type *type); void expr_rewrite_to_string(Expr *expr_to_rewrite, const char *string); +void expr_rewrite_to_const_ref(Expr *expr_to_rewrite, Decl *decl); void expr_rewrite_to_const_zero(Expr *expr, Type *type); bool expr_rewrite_to_const_initializer_index(Type *list_type, ConstInitializer *list, Expr *result, unsigned index, bool from_back); @@ -3166,9 +3170,9 @@ INLINE bool expr_is_init_list(Expr *expr) return kind == EXPR_DESIGNATED_INITIALIZER_LIST || kind == EXPR_INITIALIZER_LIST; } -INLINE bool exprid_is_constant_eval(ExprId expr, ConstantEvalKind eval_kind) +INLINE bool exprid_is_runtime_const(ExprId expr) { - return expr ? expr_is_constant_eval(exprptr(expr), eval_kind) : true; + return expr ? expr_is_runtime_const(exprptr(expr)) : true; } INLINE bool expr_poison(Expr *expr) { expr->expr_kind = EXPR_POISONED; expr->resolve_status = RESOLVE_DONE; return false; } @@ -3177,6 +3181,8 @@ static inline void expr_list_set_span(Expr **expr, SourceSpan loc); static inline void exprid_set_span(ExprId expr_id, SourceSpan loc); static inline void expr_set_span(Expr *expr, SourceSpan loc); +bool const_init_local_init_may_be_global(ConstInitializer *init); + static inline void const_init_set_span(ConstInitializer *init, SourceSpan loc) { RETRY: @@ -3645,6 +3651,7 @@ INLINE unsigned arg_bits_max(AsmArgBits bits, unsigned limit) return 0; } + INLINE bool expr_is_const(Expr *expr) { return expr->expr_kind == EXPR_CONST; diff --git a/src/compiler/copying.c b/src/compiler/copying.c index 09d13ef3f..8a8efe979 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -271,6 +271,9 @@ INLINE Expr *copy_const_expr(CopyStruct *c, Expr *expr) case CONST_INTEGER: case CONST_BOOL: break; + case CONST_REF: + fixup_decl(c, &expr->const_expr.global_ref); + break; case CONST_ENUM: case CONST_ERR: fixup_decl(c, &expr->const_expr.enum_err_val); diff --git a/src/compiler/enums.h b/src/compiler/enums.h index bbeb25cbd..45087d8ec 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -591,13 +591,6 @@ typedef enum COND_TYPE_EVALTYPE_VALUE, } CondType; -typedef enum -{ - CONSTANT_EVAL_NO_SIDE_EFFECTS, - CONSTANT_EVAL_GLOBAL_INIT, - CONSTANT_EVAL_LOCAL_INIT, - CONSTANT_EVAL_CONSTANT_VALUE, -} ConstantEvalKind; typedef enum { @@ -623,6 +616,7 @@ typedef enum CONST_TYPEID, CONST_INITIALIZER, CONST_UNTYPED_LIST, + CONST_REF, CONST_MEMBER, } ConstKind; diff --git a/src/compiler/expr.c b/src/compiler/expr.c index c4df28b97..fe65067e7 100644 --- a/src/compiler/expr.c +++ b/src/compiler/expr.c @@ -4,10 +4,9 @@ #include "compiler_internal.h" -static inline bool expr_binary_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind); -static inline bool expr_cast_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind); -static inline bool expr_list_is_constant_eval(Expr **exprs, ConstantEvalKind eval_kind); -static inline bool expr_unary_addr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind); +static inline bool expr_cast_is_runtime_const(Expr *expr); +static inline bool expr_list_is_constant_eval(Expr **exprs); +static inline bool expr_unary_addr_is_constant_eval(Expr *expr); static inline ConstInitializer *initializer_for_index(ConstInitializer *initializer, ArraySize index, bool from_back); Expr *expr_negate_expr(Expr *expr) @@ -135,19 +134,8 @@ bool expr_may_addr(Expr *expr) UNREACHABLE } -static inline bool expr_binary_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) -{ - if (expr->binary_expr.operator >= BINARYOP_ASSIGN) return false; - // Pointer add is already handled. - if (eval_kind == CONSTANT_EVAL_GLOBAL_INIT) return false; - Expr *left = exprptr(expr->binary_expr.left); - Expr *right = exprptr(expr->binary_expr.right); - if (!expr_is_constant_eval(left, eval_kind)) return false; - if (!expr_is_constant_eval(right, eval_kind)) return false; - return true; -} -bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) +bool expr_is_runtime_const(Expr *expr) { assert(expr->resolve_status == RESOLVE_DONE); RETRY: @@ -156,49 +144,20 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) case EXPR_OTHER_CONTEXT: expr = expr->expr_other_context.inner; goto RETRY; - case EXPR_SWIZZLE: - return false; case EXPR_POINTER_OFFSET: - return exprid_is_constant_eval(expr->pointer_offset_expr.ptr, eval_kind) && exprid_is_constant_eval(expr->pointer_offset_expr.offset, eval_kind); + return exprid_is_runtime_const(expr->pointer_offset_expr.ptr) && exprid_is_runtime_const( + expr->pointer_offset_expr.offset); + case EXPR_SWIZZLE: case EXPR_RETVAL: - return false; case EXPR_BUILTIN: case EXPR_CT_EVAL: case EXPR_VASPLAT: case EXPR_BENCHMARK_HOOK: case EXPR_TEST_HOOK: - return false; - case EXPR_BITACCESS: - case EXPR_ACCESS: - expr = expr->access_expr.parent; - goto RETRY; case EXPR_ANYSWITCH: - return false; case EXPR_BITASSIGN: - return false; case EXPR_TAGOF: - return true; - case EXPR_BUILTIN_ACCESS: - switch (expr->builtin_access_expr.kind) - { - case ACCESS_ENUMNAME: - case ACCESS_FAULTNAME: - case ACCESS_LEN: - case ACCESS_PTR: - case ACCESS_FAULTORDINAL: - break; - case ACCESS_TYPEOFANYFAULT: - case ACCESS_TYPEOFANY: - if (eval_kind != CONSTANT_EVAL_NO_SIDE_EFFECTS) return false; - break; - } - return exprid_is_constant_eval(expr->builtin_access_expr.inner, eval_kind); case EXPR_BINARY: - return expr_binary_is_constant_eval(expr, eval_kind); - case EXPR_CAST: - return expr_cast_is_constant_eval(expr, eval_kind); - case EXPR_CONST: - return true; case EXPR_OPERATOR_CHARS: case EXPR_STRINGIFY: case EXPR_CT_AND_OR: @@ -209,13 +168,6 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) case EXPR_CT_IS_CONST: case EXPR_LAMBDA: case EXPR_EMBED: - return true; - case EXPR_COND: - return expr_list_is_constant_eval(expr->cond_expr, eval_kind); - case EXPR_DESIGNATOR: - expr = expr->designator_expr.value; - if (!expr) return true; - goto RETRY; case EXPR_EXPR_BLOCK: case EXPR_DECL: case EXPR_CALL: @@ -230,7 +182,34 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) case EXPR_MACRO_BLOCK: case EXPR_RETHROW: case EXPR_MEMBER_GET: + case EXPR_BITACCESS: + case EXPR_COND: return false; + case EXPR_ACCESS: + expr = expr->access_expr.parent; + goto RETRY; + case EXPR_BUILTIN_ACCESS: + switch (expr->builtin_access_expr.kind) + { + case ACCESS_ENUMNAME: + case ACCESS_FAULTNAME: + case ACCESS_LEN: + case ACCESS_PTR: + case ACCESS_FAULTORDINAL: + break; + case ACCESS_TYPEOFANYFAULT: + case ACCESS_TYPEOFANY: + break; + } + return exprid_is_runtime_const(expr->builtin_access_expr.inner); + case EXPR_CAST: + return expr_cast_is_runtime_const(expr); + case EXPR_CONST: + return true; + case EXPR_DESIGNATOR: + expr = expr->designator_expr.value; + if (!expr) return true; + goto RETRY; case EXPR_IDENTIFIER: { Decl *ident = expr->identifier_expr.decl; @@ -251,7 +230,7 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) } } case EXPR_EXPRESSION_LIST: - return expr_list_is_constant_eval(expr->expression_list, eval_kind); + return expr_list_is_constant_eval(expr->expression_list); case EXPR_TYPEID_INFO: expr = exprptr(expr->typeid_info_expr.parent); goto RETRY; @@ -262,18 +241,18 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) expr = expr->default_arg_expr.inner; goto RETRY; case EXPR_INITIALIZER_LIST: - return expr_list_is_constant_eval(expr->initializer_list, eval_kind); + return expr_list_is_constant_eval(expr->initializer_list); case EXPR_DESIGNATED_INITIALIZER_LIST: - return expr_list_is_constant_eval(expr->designated_init_list, eval_kind); + return expr_list_is_constant_eval(expr->designated_init_list); case EXPR_SLICE: - if (!exprid_is_constant_eval(expr->slice_expr.expr, eval_kind)) return false; + if (!exprid_is_runtime_const(expr->slice_expr.expr)) return false; return expr->slice_expr.range.range_type == RANGE_CONST_RANGE; case EXPR_SUBSCRIPT: - if (!exprid_is_constant_eval(expr->subscript_expr.index.expr, eval_kind)) return false; + if (!exprid_is_runtime_const(expr->subscript_expr.index.expr)) return false; expr = exprptr(expr->subscript_expr.expr); goto RETRY; case EXPR_SUBSCRIPT_ADDR: - if (!exprid_is_constant_eval(expr->subscript_expr.index.expr, eval_kind)) return false; + if (!exprid_is_runtime_const(expr->subscript_expr.index.expr)) return false; expr = exprptr(expr->subscript_expr.expr); if (expr->expr_kind == EXPR_IDENTIFIER) { @@ -295,13 +274,13 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) } goto RETRY; case EXPR_TERNARY: - assert(!exprid_is_constant_eval(expr->ternary_expr.cond, eval_kind)); + assert(!exprid_is_runtime_const(expr->ternary_expr.cond)); return false; case EXPR_FORCE_UNWRAP: case EXPR_LAST_FAULT: return false; case EXPR_TYPEID: - return eval_kind != CONSTANT_EVAL_CONSTANT_VALUE; + return true; case EXPR_UNARY: switch (expr->unary_expr.operator) { @@ -309,9 +288,8 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) case UNARYOP_ERROR: return false; case UNARYOP_ADDR: - return expr_unary_addr_is_constant_eval(expr, eval_kind); + return expr_unary_addr_is_constant_eval(expr); case UNARYOP_TADDR: - if (eval_kind == CONSTANT_EVAL_CONSTANT_VALUE || eval_kind == CONSTANT_EVAL_LOCAL_INIT) return false; expr = expr->unary_expr.expr; goto RETRY; case UNARYOP_PLUS: @@ -347,7 +325,7 @@ bool expr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) UNREACHABLE } -static inline bool expr_cast_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) +static inline bool expr_cast_is_runtime_const(Expr *expr) { switch (expr->cast_expr.kind) { @@ -375,8 +353,7 @@ static inline bool expr_cast_is_constant_eval(Expr *expr, ConstantEvalKind eval_ case CAST_ARRVEC: case CAST_BOOLVECINT: case CAST_INTINT: - if (eval_kind != CONSTANT_EVAL_NO_SIDE_EFFECTS) return false; - return exprid_is_constant_eval(expr->cast_expr.expr, eval_kind); + return exprid_is_runtime_const(expr->cast_expr.expr); case CAST_INTPTR: case CAST_PTRPTR: case CAST_APTSA: @@ -388,56 +365,50 @@ static inline bool expr_cast_is_constant_eval(Expr *expr, ConstantEvalKind eval_ case CAST_IDPTR: case CAST_IDBOOL: case CAST_EXPVEC: - return exprid_is_constant_eval(expr->cast_expr.expr, eval_kind); + return exprid_is_runtime_const(expr->cast_expr.expr); case CAST_PTRANY: - if (eval_kind == CONSTANT_EVAL_LOCAL_INIT || eval_kind == CONSTANT_EVAL_CONSTANT_VALUE) return false; - return exprid_is_constant_eval(expr->cast_expr.expr, eval_kind); + return exprid_is_runtime_const(expr->cast_expr.expr); case CAST_ERINT: case CAST_PTRINT: case CAST_IDINT: case CAST_INTARRBS: case CAST_BSINTARR: case CAST_SLARR: - if (eval_kind == CONSTANT_EVAL_CONSTANT_VALUE) return false; - return exprid_is_constant_eval(expr->cast_expr.expr, eval_kind); + return exprid_is_runtime_const(expr->cast_expr.expr); } UNREACHABLE } -static inline bool expr_list_is_constant_eval(Expr **exprs, ConstantEvalKind eval_kind) +static inline bool expr_list_is_constant_eval(Expr **exprs) { FOREACH(Expr *, expr, exprs) { - if (!expr_is_constant_eval(expr, eval_kind)) return false; + if (!expr_is_runtime_const(expr)) return false; } return true; } -static inline bool expr_unary_addr_is_constant_eval(Expr *expr, ConstantEvalKind eval_kind) +static inline bool expr_unary_addr_is_constant_eval(Expr *expr) { // An address is never a constant value. - if (eval_kind == CONSTANT_EVAL_CONSTANT_VALUE) return false; Expr *inner = expr->unary_expr.expr; - if (eval_kind == CONSTANT_EVAL_GLOBAL_INIT && IS_OPTIONAL(inner)) return false; + if (IS_OPTIONAL(inner)) return false; switch (inner->expr_kind) { case EXPR_ACCESS: - return expr_is_constant_eval(inner, eval_kind); + return expr_is_runtime_const(inner); case EXPR_CONST: case EXPR_INITIALIZER_LIST: case EXPR_DESIGNATED_INITIALIZER_LIST: // We can't create temporaries as const locally or making them into compile time constants. - if (eval_kind == CONSTANT_EVAL_LOCAL_INIT) return false; - return expr_is_constant_eval(inner, eval_kind); + return expr_is_runtime_const(inner); case EXPR_IDENTIFIER: { // The address of an identifier is side effect free. - if (eval_kind == CONSTANT_EVAL_NO_SIDE_EFFECTS) return true; Decl *decl = inner->identifier_expr.decl; if (decl->decl_kind == DECL_FUNC) return true; if (decl->decl_kind != DECL_VAR) return false; - assert(eval_kind == CONSTANT_EVAL_LOCAL_INIT || eval_kind == CONSTANT_EVAL_GLOBAL_INIT); switch (decl->var.kind) { case VARDECL_CONST: @@ -943,6 +914,15 @@ void expr_rewrite_insert_deref(Expr *original) } } +void expr_rewrite_to_const_ref(Expr *expr_to_rewrite, Decl *decl) +{ + expr_to_rewrite->const_expr = (ExprConst) { + .global_ref = decl, + .const_kind = CONST_REF + }; + expr_to_rewrite->expr_kind = EXPR_CONST; +} + void expr_rewrite_to_string(Expr *expr_to_rewrite, const char *string) { expr_to_rewrite->expr_kind = EXPR_CONST; diff --git a/src/compiler/headers.c b/src/compiler/headers.c index 41715436a..c8c37c3b0 100644 --- a/src/compiler/headers.c +++ b/src/compiler/headers.c @@ -631,6 +631,9 @@ static void header_gen_global_var(HeaderContext *c, Decl *decl, bool fn_globals, case CONST_BOOL: PRINTF("%s\n", init->const_expr.b ? "true" : "false"); return; + case CONST_REF: + PRINTF("&%s\n", decl_get_extname(init->const_expr.global_ref)); + return; case CONST_POINTER: if (!init->const_expr.ptr) { diff --git a/src/compiler/llvm_codegen.c b/src/compiler/llvm_codegen.c index d261f51f8..4eb4282c2 100644 --- a/src/compiler/llvm_codegen.c +++ b/src/compiler/llvm_codegen.c @@ -365,7 +365,7 @@ LLVMValueRef llvm_emit_const_initializer(GenContext *c, ConstInitializer *const_ LLVMTypeRef expected_type = llvm_get_type(c, const_init->init_struct[i]->type); LLVMValueRef element = llvm_emit_const_initializer(c, const_init->init_struct[i]); LLVMTypeRef element_type = LLVMTypeOf(element); - assert(LLVMIsConstant(element)); + //assert(LLVMIsConstant(element)); if (expected_type != element_type) { was_modified = true; diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index 633c6ffd7..c4764d772 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -1739,8 +1739,11 @@ static void llvm_emit_const_init_ref(GenContext *c, BEValue *ref, ConstInitializ // In case of small const initializers, or full arrays - use copy. if (const_init->kind == CONST_INIT_ARRAY_FULL || type_size(const_init->type) <= 32) { - llvm_emit_initialize_reference_temporary_const(c, ref, const_init); - return; + if (const_init_local_init_may_be_global(const_init)) + { + llvm_emit_initialize_reference_temporary_const(c, ref, const_init); + return; + } } // Make sure we have an address. @@ -2562,6 +2565,13 @@ static inline void llvm_emit_deref(GenContext *c, BEValue *value, Expr *inner, T if (safe_mode_enabled()) { LLVMValueRef check = LLVMBuildICmp(c->builder, LLVMIntEQ, value->value, llvm_get_zero(c, inner->type), "checknull"); + assert(!LLVMIsPoison(check)); + if (llvm_is_const(check)) + { + LLVMDumpValue(check); + printf("-- %lld value\n", LLVMConstIntGetSExtValue(check)); + + } scratch_buffer_clear(); scratch_buffer_append("Dereference of null pointer, '"); span_to_scratch(inner->span); @@ -4945,6 +4955,13 @@ static void llvm_emit_const_expr(GenContext *c, BEValue *be_value, Expr *expr) bool is_bytes = false; switch (expr->const_expr.const_kind) { + case CONST_REF: + { + Decl *decl = expr->const_expr.global_ref; + LLVMValueRef backend_ref = llvm_get_ref(c, decl); + llvm_value_set(be_value, backend_ref, expr->type); + return; + } case CONST_INTEGER: { LLVMValueRef value; @@ -7054,11 +7071,6 @@ static void llmv_emit_test_hook(GenContext *c, BEValue *value, Expr *expr) llvm_value_set_address_abi_aligned(value, get_global, expr->type); } -static void llvm_emit_lambda(GenContext *c, BEValue *value, Expr *expr) -{ - Decl *decl = expr->lambda_expr; - llvm_value_set(value, llvm_get_ref(c, decl), expr->type); -} static void llvm_emit_swizzle(GenContext *c, BEValue *value, Expr *expr) { @@ -7117,6 +7129,7 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr) switch (expr->expr_kind) { case NON_RUNTIME_EXPR: + case EXPR_LAMBDA: case EXPR_COND: case EXPR_ASM: case EXPR_VASPLAT: @@ -7131,9 +7144,6 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr) case EXPR_DEFAULT_ARG: llvm_emit_default_arg(c, value, expr); return; - case EXPR_LAMBDA: - llvm_emit_lambda(c, value, expr); - return; case EXPR_SWIZZLE: llvm_emit_swizzle(c, value, expr); return; diff --git a/src/compiler/llvm_codegen_internal.h b/src/compiler/llvm_codegen_internal.h index b67c2aad1..1f33f15bc 100644 --- a/src/compiler/llvm_codegen_internal.h +++ b/src/compiler/llvm_codegen_internal.h @@ -82,6 +82,7 @@ typedef struct OptionalCatch_ typedef struct GenContext_ { bool shared_context; + bool in_init_ref; LLVMModuleRef module; LLVMBuilderRef global_builder; LLVMTargetMachineRef machine; diff --git a/src/compiler/llvm_codegen_stmt.c b/src/compiler/llvm_codegen_stmt.c index 1f6f6f072..c6f64d3e0 100644 --- a/src/compiler/llvm_codegen_stmt.c +++ b/src/compiler/llvm_codegen_stmt.c @@ -1563,7 +1563,7 @@ void llvm_emit_panic(GenContext *c, const char *message, SourceSpan loc, const c void llvm_emit_panic_if_true(GenContext *c, BEValue *value, const char *panic_name, SourceSpan loc, const char *fmt, BEValue *value_1, BEValue *value_2) { - if (llvm_is_const(value->value)) + if (LLVMIsAConstantInt(value->value)) { assert(!LLVMConstIntGetZExtValue(value->value) && "Unexpected bounds check failed."); return; diff --git a/src/compiler/number.c b/src/compiler/number.c index da333dbd4..892c91a10 100644 --- a/src/compiler/number.c +++ b/src/compiler/number.c @@ -137,6 +137,10 @@ bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp case CONST_INTEGER: assert(right->const_kind != CONST_ENUM); return int_comp(left->ixx, right->ixx, op); + case CONST_REF: + assert(right->const_kind == CONST_POINTER || right->const_kind == CONST_REF); + if (right->const_kind == CONST_POINTER) return false; + return decl_flatten(right->global_ref) == decl_flatten(left->global_ref); case CONST_FLOAT: return compare_fps(left->fxx.f, right->fxx.f, op); case CONST_POINTER: @@ -278,6 +282,7 @@ bool expr_const_will_overflow(const ExprConst *expr, TypeKind kind) case CONST_INITIALIZER: case CONST_UNTYPED_LIST: case CONST_MEMBER: + case CONST_REF: UNREACHABLE; } UNREACHABLE; @@ -302,6 +307,8 @@ const char *expr_const_to_error_string(const ExprConst *expr) return str_printf("\"%*.s\"", expr->bytes.len, expr->bytes.ptr); case CONST_BYTES: return ""; + case CONST_REF: + return expr->global_ref->name; case CONST_ENUM: case CONST_ERR: return expr->enum_err_val->name; diff --git a/src/compiler/sema_casts.c b/src/compiler/sema_casts.c index ce2f20b1e..b5029895b 100644 --- a/src/compiler/sema_casts.c +++ b/src/compiler/sema_casts.c @@ -1903,10 +1903,13 @@ static void cast_float_to_bool(SemaContext *context, Expr *expr, Type *type) */ static void cast_ptr_to_int(SemaContext *context, Expr *expr, Type *type) { - if (insert_runtime_cast_unless_const(expr, CAST_PTRINT, type)) return; - - // Revisit this to support pointers > 64 bits. - expr_rewrite_const_int(expr, type, expr->const_expr.ptr); + if (sema_cast_const(expr) && expr_is_const_pointer(expr)) + { + // Revisit this to support pointers > 64 bits. + expr_rewrite_const_int(expr, type, expr->const_expr.ptr); + return; + } + insert_runtime_cast(expr, CAST_PTRINT, type); } /** @@ -1917,12 +1920,19 @@ static void cast_ptr_to_bool(SemaContext *context, Expr *expr, Type *type) if (insert_runtime_cast_unless_const(expr, CAST_PTRBOOL, type)) return; // It may be a pointer - if (expr->const_expr.const_kind == CONST_POINTER) + switch (expr->const_expr.const_kind) { - expr_rewrite_const_bool(expr, type, expr->const_expr.ptr != 0); - return; + case CONST_POINTER: + expr_rewrite_const_bool(expr, type, expr->const_expr.ptr != 0); + return; + case CONST_REF: + expr_rewrite_const_bool(expr, type, true); + return; + default: + break; } + // Or it's a string, in which case it is always true. assert(expr->const_expr.const_kind == CONST_STRING); expr_rewrite_const_bool(expr, type, true); diff --git a/src/compiler/sema_const.c b/src/compiler/sema_const.c index 942d226ee..b5e829b18 100644 --- a/src/compiler/sema_const.c +++ b/src/compiler/sema_const.c @@ -73,7 +73,7 @@ ArrayIndex sema_len_from_const(Expr *expr) case CONST_POINTER: case CONST_TYPEID: case CONST_MEMBER: - return -1; + case CONST_REF: case CONST_BYTES: case CONST_STRING: return expr->const_expr.bytes.len; @@ -208,6 +208,7 @@ static bool sema_concat_bytes_and_other(SemaContext *context, Expr *expr, Expr * case CONST_POINTER: case CONST_TYPEID: case CONST_MEMBER: + case CONST_REF: RETURN_SEMA_ERROR(expr, "Concatenating %s with %s is not possible at compile time.", type_quoted_error_string(left->type), type_to_error_string(right->type)); case CONST_BYTES: @@ -258,6 +259,7 @@ static bool sema_append_concat_const_bytes(SemaContext *context, Expr *expr, Exp return true; } +// TODO there is also another const_len... look at that. static inline ArraySize sema_get_const_len(SemaContext *context, Expr *expr) { switch (expr->const_expr.const_kind) @@ -269,6 +271,7 @@ static inline ArraySize sema_get_const_len(SemaContext *context, Expr *expr) case CONST_ERR: case CONST_POINTER: case CONST_TYPEID: + case CONST_REF: return 1; case CONST_BYTES: case CONST_STRING: @@ -369,6 +372,7 @@ bool sema_expr_analyse_ct_concat(SemaContext *context, Expr *concat_expr, Expr * case CONST_ENUM: case CONST_ERR: case CONST_TYPEID: + case CONST_REF: RETURN_SEMA_ERROR(left, "Only bytes, strings and list-like constants can be concatenated."); case CONST_BYTES: case CONST_STRING: @@ -421,6 +425,7 @@ bool sema_expr_analyse_ct_concat(SemaContext *context, Expr *concat_expr, Expr * case CONST_POINTER: case CONST_TYPEID: case CONST_MEMBER: + case CONST_REF: return sema_expr_const_append(context, concat_expr, left, right); case CONST_BYTES: case CONST_STRING: diff --git a/src/compiler/sema_decls.c b/src/compiler/sema_decls.c index 3ee960958..8c2d5869c 100644 --- a/src/compiler/sema_decls.c +++ b/src/compiler/sema_decls.c @@ -1560,7 +1560,7 @@ static inline bool sema_analyse_enum(SemaContext *context, Decl *decl, bool *era Expr *arg = args[j]; if (!sema_analyse_expr_rhs(context, associated_values[j]->type, arg, false, NULL, false)) return false; - if (!expr_is_constant_eval(arg, CONSTANT_EVAL_GLOBAL_INIT)) + if (!expr_is_runtime_const(arg)) { SEMA_ERROR(arg, "Expected a constant expression as parameter."); return false; @@ -2479,7 +2479,7 @@ static bool sema_analyse_attribute(SemaContext *context, ResolvedAttrData *attr_ if (!sema_analyse_expr(context, string)) return false; if (!sema_cast_const(string) || !expr_is_const_string(string)) RETURN_SEMA_ERROR(string, "Expected a constant string here, usage is: '@tag(name, value)'."); if (!sema_analyse_expr(context, val)) return false; - if (!sema_cast_const(val) || !expr_is_const(val)) RETURN_SEMA_ERROR(val, "Expected a constant value here, usage is: '@tag(name, value)'."); + if (!sema_cast_const(val)) RETURN_SEMA_ERROR(val, "Expected a constant value here, usage is: '@tag(name, value)'."); const char *name = string->const_expr.bytes.ptr; FOREACH_IDX(i, Attr *, tag, attr_data->tags) { @@ -3678,7 +3678,7 @@ bool sema_analyse_var_decl_ct(SemaContext *context, Decl *decl) if (!sema_analyse_expr_rhs(context, decl->type, init, false, NULL, false)) goto FAIL; // Check that it is constant. - if (!expr_is_constant_eval(init, CONSTANT_EVAL_CONSTANT_VALUE)) + if (!expr_is_runtime_const(init)) { SEMA_ERROR(init, "Expected a constant expression assigned to %s.", decl->name); goto FAIL; @@ -3690,7 +3690,7 @@ bool sema_analyse_var_decl_ct(SemaContext *context, Decl *decl) { if (!sema_analyse_expr(context, init)) goto FAIL; // Check it is constant. - if (!expr_is_constant_eval(init, CONSTANT_EVAL_CONSTANT_VALUE)) + if (!sema_cast_const(init)) { SEMA_ERROR(init, "Expected a constant expression assigned to %s.", decl->name); goto FAIL; @@ -3798,7 +3798,7 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local) { if (!sema_analyse_expr(context, init_expr)) return decl_poison(decl); if (global_level_var || !type_is_abi_aggregate(init_expr->type)) sema_cast_const(init_expr); - if (global_level_var && !expr_is_constant_eval(init_expr, CONSTANT_EVAL_GLOBAL_INIT)) + if (global_level_var && !expr_is_runtime_const(init_expr)) { SEMA_ERROR(init_expr, "This expression cannot be evaluated at compile time."); return decl_poison(decl); @@ -3901,10 +3901,10 @@ bool sema_analyse_var_decl(SemaContext *context, Decl *decl, bool local) Expr *init_expr = decl->var.init_expr; // 2. Check const-ness - if (global_level_var && !expr_is_constant_eval(init_expr, CONSTANT_EVAL_GLOBAL_INIT)) + if (global_level_var && !expr_is_runtime_const(init_expr)) { SEMA_ERROR(init_expr, "The expression must be a constant value."); - expr_is_constant_eval(init_expr, CONSTANT_EVAL_GLOBAL_INIT); + expr_is_runtime_const(init_expr); return decl_poison(decl); } if (global_level_var || !type_is_abi_aggregate(init_expr->type)) sema_cast_const(init_expr); diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index d90353413..db24e5d3c 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -211,6 +211,7 @@ static inline bool sema_constant_fold_ops(Expr *expr) return true; case CONST_INITIALIZER: case CONST_UNTYPED_LIST: + case CONST_REF: return false; } UNREACHABLE @@ -803,13 +804,14 @@ static inline bool sema_cast_ident_rvalue(SemaContext *context, Expr *expr) { case VARDECL_CONST: if (decl->is_extern) return true; - if (!expr_is_constant_eval(decl->var.init_expr, CONSTANT_EVAL_NO_SIDE_EFFECTS)) - { - UNREACHABLE - } if (type_is_abi_aggregate(decl->type)) return true; expr_replace(expr, copy_expr_single(decl->var.init_expr)); - return sema_analyse_expr(context, expr); + if (!sema_analyse_expr(context, expr)) return false; + if (!sema_cast_const(expr) && !expr_is_runtime_const(expr)) + { + RETURN_SEMA_ERROR(decl->var.init_expr, "The expression must be constant."); + } + return true; case VARDECL_PARAM_EXPR: UNREACHABLE case VARDECL_PARAM_CT_TYPE: @@ -856,7 +858,7 @@ static inline bool sema_expr_analyse_ternary(SemaContext *context, Expr *expr) SEMA_ERROR(cond, "Cannot convert expression to boolean."); return false; } - if (expr_is_constant_eval(cond, CONSTANT_EVAL_CONSTANT_VALUE)) + if (expr_is_const(cond)) { Expr *copy = copy_expr_single(cond); cast_no_check(context, copy, type_bool, false); @@ -1016,7 +1018,7 @@ static inline bool sema_expr_analyse_identifier(SemaContext *context, Type *to, { Expr *copy = copy_expr_single(decl->var.init_expr); if (!sema_analyse_expr(context, copy)) return false; - if (!expr_is_constant_eval(copy, false)) + if (!expr_is_runtime_const(copy)) { SEMA_ERROR(expr, "Constant value did not evaluate to a constant."); return false; @@ -1334,7 +1336,7 @@ static bool sema_analyse_parameter(SemaContext *context, Expr *arg, Decl *param, SEMA_NOTE(definition, "The definition is here."); return false; } - if (!expr_is_constant_eval(arg, CONSTANT_EVAL_CONSTANT_VALUE)) + if (!sema_cast_const(arg) && !expr_is_runtime_const(arg)) { RETURN_SEMA_FUNC_ERROR(definition, arg, "A compile time parameter must always be a constant, did you mistake it for a normal paramter?"); } @@ -1786,8 +1788,7 @@ static inline bool sema_call_check_contract_param_match(SemaContext *context, De { if (param->var.not_null && expr_is_const_pointer(expr) && !expr->const_expr.ptr) { - SEMA_ERROR(expr, "You may not pass null to a '&' parameter."); - return false; + RETURN_SEMA_ERROR(expr, "You may not pass null to a '&' parameter."); } if (expr->expr_kind == EXPR_UNARY && expr->unary_expr.expr->expr_kind == EXPR_IDENTIFIER) { @@ -2299,7 +2300,7 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s Ast *ret = macro_context.returns[0]; Expr *result = ret ? ret->return_stmt.expr : NULL; if (!result) goto NOT_CT; - if (!expr_is_constant_eval(result, CONSTANT_EVAL_GLOBAL_INIT)) goto NOT_CT; + if (!expr_is_runtime_const(result)) goto NOT_CT; bool only_ct_params = true; FOREACH(Decl *, param, params) { @@ -2315,7 +2316,7 @@ bool sema_expr_analyse_macro_call(SemaContext *context, Expr *call_expr, Expr *s goto NOT_CT; } } - if (ast_is_compile_time(body, CONSTANT_EVAL_GLOBAL_INIT)) + if (ast_is_compile_time(body)) { expr_replace(call_expr, result); goto EXIT; @@ -2336,7 +2337,7 @@ EXIT: context->active_scope = old_scope; if (is_no_return) context->active_scope.jump_end = true; sema_context_destroy(¯o_context); - if (is_always_const && !expr_is_const(call_expr)) + if (is_always_const && !expr_is_runtime_const(call_expr)) { SEMA_ERROR(call_expr, "The macro failed to fold to a constant value, despite being '@const'."); SEMA_NOTE(decl, "The macro was declared here."); @@ -2996,7 +2997,7 @@ static inline bool sema_expr_analyse_subscript(SemaContext *context, Expr *expr, if (sema_cast_const(index)) { ASSERT_SPAN(index, expr_is_const_int(index)); - sema_expr_flatten_const_ident(current_expr); + sema_cast_const(current_expr); bool is_const_initializer = expr_is_const_initializer(current_expr); if (is_const_initializer || expr_is_const_string(current_expr) || expr_is_const_bytes(current_expr)) { @@ -3056,7 +3057,7 @@ static inline bool sema_expr_analyse_pointer_offset(SemaContext *context, Expr * bool is_optional = IS_OPTIONAL(pointer) || IS_OPTIONAL(offset); // 4. Possibly constant fold - if (!vec_len && sema_cast_const(pointer) && sema_cast_const(offset)) + if (!vec_len && sema_cast_const(pointer) && expr_is_const_pointer(pointer) && sema_cast_const(offset)) { ASSERT_SPAN(expr, !is_optional); Int mul = { .i.low = type_size(type_flatten(pointer->type)->pointer), .type = offset->const_expr.ixx.type }; @@ -4518,50 +4519,6 @@ static inline bool sema_analyse_maybe_dead_expr(SemaContext *context, Expr *expr context->active_scope.is_dead = false; return success; } -static bool sema_expr_flatten_assign(Expr *expr) -{ - ASSERT_SPAN(expr, expr->resolve_status == RESOLVE_DONE); - switch (expr->expr_kind) - { - case EXPR_ACCESS: - case EXPR_BITACCESS: - { - Expr *parent = expr->access_expr.parent; - Type *flat = type_flatten(parent->type); - switch (flat->type_kind) - { - case TYPE_UNION: - case TYPE_UNTYPED_LIST: - case TYPE_BITSTRUCT: - case TYPE_STRUCT: - break; - default: - return false; - } - if (!sema_expr_flatten_assign(expr->access_expr.parent)) return false; - if (!sema_expr_fold_to_member(expr, expr->access_expr.parent, expr->access_expr.ref)) return false; - return true; - } - case EXPR_SLICE: - return false; - case EXPR_SUBSCRIPT: - { - if (!expr_is_const(exprptr(expr->subscript_expr.index.expr))) return false; - Expr *parent = exprptr(expr->subscript_expr.expr); - Type *flat_type = type_flatten(parent->type); - if (!type_is_any_arraylike(flat_type) || flat_type->type_kind == TYPE_UNTYPED_LIST) return false; - if (!sema_expr_flatten_assign(parent)) return false; - return sema_expr_fold_to_index(expr, parent, expr->subscript_expr.index); - } - case EXPR_IDENTIFIER: - sema_expr_flatten_const_ident(expr); - return expr_is_const(expr); - case EXPR_CONST: - return true; - default: - return false; - } -} static inline void sema_expr_flatten_const_ident(Expr *expr) { @@ -5734,7 +5691,8 @@ static bool sema_expr_analyse_sub(SemaContext *context, Expr *expr, Expr *left, return false; } - if (!right_is_pointer_vector && !left_is_pointer_vector && expr_both_const(left, right) && sema_constant_fold_ops(left)) + if (!right_is_pointer_vector && !left_is_pointer_vector + && expr_both_const(left, right) && sema_constant_fold_ops(left) && sema_constant_fold_ops(right)) { expr_rewrite_const_int(expr, type_isz, (left->const_expr.ptr - right->const_expr.ptr) / type_size(left_type->pointer)); @@ -6522,11 +6480,25 @@ static inline bool sema_expr_analyse_deref(SemaContext *context, Expr *expr, boo RETURN_SEMA_ERROR(inner, "A 'void*' cannot be dereferenced, you need to first cast it to a concrete type."); } - // 3. This could be a constant, in which case it is a null which is an error. + // 3. This could be a constant, in which case we can inline any *&foo to "foo" + // and check for null. if (sema_cast_const(inner)) { - if (failed_ref) goto ON_FAILED; - RETURN_SEMA_ERROR(inner, "Dereferencing null is not allowed, did you do it by mistake?"); + switch (inner->const_expr.const_kind) + { + case CONST_POINTER: + if (!inner->const_expr.ptr) + { + if (failed_ref) goto ON_FAILED; + RETURN_SEMA_ERROR(inner, "Dereferencing null is not allowed, did you do it by mistake?"); + } + break; + case CONST_REF: + expr_replace(expr, expr_variable(inner->const_expr.global_ref)); + break; + default: + UNREACHABLE + } } // 4. Now the type might not be a pointer because of a typedef, @@ -6535,7 +6507,6 @@ static inline bool sema_expr_analyse_deref(SemaContext *context, Expr *expr, boo // 5. And... set the type. expr->type = type_add_optional(deref_type->pointer, IS_OPTIONAL(inner)); - return true; ON_FAILED: *failed_ref = true; @@ -6647,6 +6618,24 @@ static const char *sema_addr_check_may_take(Expr *inner) return "To take the address of a temporary value, use '&&' instead of '&'."; } +static bool sema_expr_recursive_const_address(SemaContext *context, Expr *expr) +{ + RETRY: + switch (expr->expr_kind) + { + case EXPR_ACCESS: + expr = expr->access_expr.parent; + goto RETRY; + case EXPR_SUBSCRIPT: + if (!sema_cast_const(exprptr(expr->subscript_expr.index.expr))) return false; + expr = exprptr(expr->subscript_expr.expr); + goto RETRY; + case EXPR_IDENTIFIER: + return decl_is_global(expr->identifier_expr.decl); + default: + return false; + } +} /** * Analyse &a * @return true if analysis succeeds. @@ -6710,7 +6699,15 @@ static inline bool sema_expr_analyse_addr(SemaContext *context, Expr *expr, bool return true; } expr->type = type_get_ptr_recurse(inner->type); - + if (inner->expr_kind == EXPR_IDENTIFIER) + { + Decl *ident = inner->identifier_expr.decl; + if (decl_is_global(ident)) + { + expr_rewrite_to_const_ref(expr, ident); + return true; + } + } return true; } @@ -6887,17 +6884,10 @@ static inline bool sema_expr_analyse_ct_incdec(SemaContext *context, Expr *expr, Decl *var = inner->ct_ident_expr.decl; Expr *start_value = var->var.init_expr; - ASSERT_SPAN(expr, expr_is_const(start_value)); - - switch (start_value->const_expr.const_kind) + if (!expr_is_const_int(start_value)) { - case CONST_INTEGER: - break; - default: - SEMA_ERROR(expr, "The compile time variable '%s' does not hold an integer.", var->name); - return false; + RETURN_SEMA_ERROR(expr, "The compile time variable '%s' does not hold an integer.", var->name); } - Expr *end_value = expr_copy(start_value); // Make the change. @@ -8067,11 +8057,10 @@ INLINE bool lambda_parameter_match(Decl **ct_lambda_params, Decl *candidate) break; case VARDECL_LOCAL_CT: case VARDECL_PARAM_CT: - assert(expr_is_const(ct_param->var.init_expr)); - assert(expr_is_const(param->var.init_expr)); + if (!expr_is_const(ct_param->var.init_expr)) return false; + if (!expr_is_const(param->var.init_expr)) return false; if (!expr_const_compare(&ct_param->var.init_expr->const_expr, - ¶m->var.init_expr->const_expr, BINARYOP_EQ)) - return false; + ¶m->var.init_expr->const_expr, BINARYOP_EQ)) return false; break; default: UNREACHABLE @@ -8245,7 +8234,7 @@ static inline bool sema_expr_analyse_lambda(SemaContext *context, Type *target_t if (decl_cached) { expr->type = type_get_func_ptr(decl_cached->type); - expr->lambda_expr = decl_cached; + expr_rewrite_to_const_ref(expr, decl_cached); return true; } } @@ -8345,6 +8334,7 @@ static inline bool sema_expr_analyse_lambda(SemaContext *context, Type *target_t vec_add(original->func_decl.generated_lambda, decl); } decl->resolve_status = RESOLVE_DONE; + expr_rewrite_to_const_ref(expr, decl); return true; FAIL_NO_INFER: SEMA_ERROR(expr, "Inferred lambda expressions cannot be used unless the type can be determined."); @@ -8375,7 +8365,7 @@ static inline bool sema_expr_analyse_ct_is_const(SemaContext *context, Expr *exp ASSERT_SPAN(expr, expr->resolve_status == RESOLVE_RUNNING); Expr *inner = expr->inner_expr; if (!sema_analyse_expr(context, inner)) return false; - expr_rewrite_const_bool(expr, type_bool, expr_is_constant_eval(inner, CONSTANT_EVAL_CONSTANT_VALUE)); + expr_rewrite_const_bool(expr, type_bool, sema_cast_const(inner)); return true; } @@ -8633,7 +8623,7 @@ static inline bool sema_expr_analyse_ct_arg(SemaContext *context, Type *infer_ty ASSIGN_EXPR_OR_RET(Expr *arg_expr, sema_expr_analyse_ct_arg_index(context, exprptr(expr->ct_arg_expr.arg), NULL), false); arg_expr = copy_expr_single(arg_expr); if (!sema_analyse_inferred_expr(context, infer_type, arg_expr)) return false; - if (!expr_is_constant_eval(arg_expr, CONSTANT_EVAL_CONSTANT_VALUE)) + if (!sema_cast_const(arg_expr)) { RETURN_SEMA_ERROR(arg_expr, "This argument needs to be a compile time constant."); } @@ -8879,7 +8869,7 @@ static inline bool sema_expr_analyse_retval(SemaContext *context, Expr *expr) } } ASSERT_SPAN(expr, return_value); - if (expr_is_constant_eval(return_value, CONSTANT_EVAL_GLOBAL_INIT)) + if (expr_is_runtime_const(return_value)) { expr_replace(expr, copy_expr_single(return_value)); } @@ -9364,7 +9354,48 @@ bool sema_analyse_expr(SemaContext *context, Expr *expr) bool sema_cast_const(Expr *expr) { - return sema_expr_flatten_assign(expr); + ASSERT_SPAN(expr, expr->resolve_status == RESOLVE_DONE); + switch (expr->expr_kind) + { + case EXPR_ACCESS: + case EXPR_BITACCESS: + { + Expr *parent = expr->access_expr.parent; + Type *flat = type_flatten(parent->type); + switch (flat->type_kind) + { + case TYPE_UNION: + case TYPE_UNTYPED_LIST: + case TYPE_BITSTRUCT: + case TYPE_STRUCT: + break; + default: + return false; + } + if (!sema_cast_const(expr->access_expr.parent)) return false; + if (!sema_expr_fold_to_member(expr, expr->access_expr.parent, expr->access_expr.ref)) return false; + return true; + } + case EXPR_SLICE: + return false; + case EXPR_SUBSCRIPT: + { + if (!expr_is_const(exprptr(expr->subscript_expr.index.expr))) return false; + Expr *parent = exprptr(expr->subscript_expr.expr); + Type *flat_type = type_flatten(parent->type); + if (!type_is_any_arraylike(flat_type) || flat_type->type_kind == TYPE_UNTYPED_LIST) return false; + if (!sema_cast_const(parent)) return false; + return sema_expr_fold_to_index(expr, parent, expr->subscript_expr.index); + } + case EXPR_IDENTIFIER: + sema_expr_flatten_const_ident(expr); + return expr_is_const(expr); + case EXPR_CONST: + return true; + default: + return false; + } + UNREACHABLE } static inline int64_t expr_get_index_max(Expr *expr) diff --git a/src/compiler/sema_initializers.c b/src/compiler/sema_initializers.c index 5545fb486..0b6d2506f 100644 --- a/src/compiler/sema_initializers.c +++ b/src/compiler/sema_initializers.c @@ -41,14 +41,47 @@ static inline void sema_update_const_initializer_with_designator( DesignatorElement **curr, DesignatorElement **end, Expr *value); -static inline ConstantEvalKind env_eval_type(SemaContext *context); - - -static inline ConstantEvalKind env_eval_type(SemaContext *context) +bool const_init_local_init_may_be_global_inner(ConstInitializer *init, bool top) { - if (context->call_env.kind == CALL_ENV_FUNCTION) return CONSTANT_EVAL_LOCAL_INIT; - return CONSTANT_EVAL_GLOBAL_INIT; + ConstInitializer **list; + unsigned len; + switch (init->kind) + { + case CONST_INIT_ZERO: + return top; + case CONST_INIT_STRUCT: + list = init->init_struct; + len = vec_size(type_flatten(init->type)->decl->strukt.members); + break; + case CONST_INIT_UNION: + return const_init_local_init_may_be_global_inner(init->init_union.element, false); + case CONST_INIT_VALUE: + if (!expr_is_const(init->init_value)) return false; + if (top && expr_is_const_pointer(init->init_value) && !init->init_value->const_expr.ptr) return false; + return true; + case CONST_INIT_ARRAY: + list = init->init_array.elements; + len = vec_size(list); + break; + case CONST_INIT_ARRAY_FULL: + list = init->init_array_full; + len = vec_size(list); + break; + case CONST_INIT_ARRAY_VALUE: + return const_init_local_init_may_be_global_inner(init->init_array_value.element, false); + } + for (unsigned i = 0; i < len; i++) + { + ConstInitializer *subinit = list[i]; + if (!const_init_local_init_may_be_global_inner(subinit, false)) return false; + } + return true; +} + +bool const_init_local_init_may_be_global(ConstInitializer *init) +{ + return const_init_local_init_may_be_global_inner(init, true); } static inline void sema_not_enough_elements_error(SemaContext *context, Expr *initializer, int element) @@ -172,7 +205,7 @@ static inline bool sema_expr_analyse_struct_plain_initializer(SemaContext *conte // 6. There's the case of too few values as well. Mark the last field as wrong. assert(elements_needed <= size); initializer->resolve_status = RESOLVE_DONE; - if (expr_is_constant_eval(initializer, env_eval_type(context))) + if (expr_is_runtime_const(initializer)) { bool is_union = type_flatten(initializer->type)->type_kind == TYPE_UNION; assert(!is_union || vec_size(elements) == 1); @@ -352,7 +385,7 @@ static inline bool sema_expr_analyse_array_plain_initializer(SemaContext *contex } initializer->resolve_status = RESOLVE_DONE; - if (expr_is_constant_eval(initializer, env_eval_type(context))) + if (expr_is_runtime_const(initializer)) { ConstInitializer *const_init = CALLOCS(ConstInitializer); const_init->kind = CONST_INIT_ARRAY_FULL; @@ -451,7 +484,7 @@ static bool sema_expr_analyse_designated_initializer(SemaContext *context, Type } initializer->type = type_add_optional(type, optional); initializer->resolve_status = RESOLVE_DONE; - if (expr_is_constant_eval(initializer, env_eval_type(context))) + if (expr_is_runtime_const(initializer)) { ConstInitializer *const_init = MALLOCS(ConstInitializer); sema_create_const_initializer_from_designated_init(const_init, initializer); diff --git a/src/compiler/sema_liveness.c b/src/compiler/sema_liveness.c index 3c8322663..7eed0dc61 100644 --- a/src/compiler/sema_liveness.c +++ b/src/compiler/sema_liveness.c @@ -345,11 +345,29 @@ RETRY: return; } case EXPR_CONST: - if (expr->const_expr.const_kind != CONST_INITIALIZER) return; + switch (expr->const_expr.const_kind) { - sema_trace_const_initializer_liveness(expr->const_expr.initializer); + case CONST_FLOAT: + case CONST_INTEGER: + case CONST_BOOL: + case CONST_BYTES: + case CONST_STRING: + case CONST_POINTER: + case CONST_TYPEID: + case CONST_UNTYPED_LIST: + case CONST_MEMBER: + return; + case CONST_ENUM: + case CONST_ERR: + sema_trace_decl_liveness(expr->const_expr.enum_err_val); + return; + case CONST_REF: + sema_trace_decl_liveness(expr->const_expr.global_ref); + return; + case CONST_INITIALIZER: + sema_trace_const_initializer_liveness(expr->const_expr.initializer); + return; } - return; case EXPR_COMPOUND_LITERAL: sema_trace_expr_liveness(expr->expr_compound_literal.initializer); return; @@ -376,8 +394,7 @@ RETRY: return; } case EXPR_LAMBDA: - sema_trace_decl_liveness(expr->lambda_expr); - return; + UNREACHABLE case EXPR_MACRO_BLOCK: { FOREACH(Decl *, val, expr->macro_block.params) sema_trace_decl_liveness(val); diff --git a/src/compiler/sema_passes.c b/src/compiler/sema_passes.c index d4de59afa..1242f40ce 100644 --- a/src/compiler/sema_passes.c +++ b/src/compiler/sema_passes.c @@ -198,6 +198,9 @@ static bool exec_arg_append_to_scratch(Expr *arg) case CONST_BOOL: scratch_buffer_append(arg->const_expr.b ? "true" : "false"); return true; + case CONST_REF: + scratch_buffer_append(arg->const_expr.global_ref->name); + return true; case CONST_ENUM: case CONST_ERR: scratch_buffer_append(arg->const_expr.enum_err_val->name); diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index 2cb7bea31..25f051a0d 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -2815,6 +2815,9 @@ bool sema_analyse_ct_echo_stmt(SemaContext *context, Ast *statement) case CONST_BOOL: puts(message->const_expr.b ? "true" : "false"); break; + case CONST_REF: + puts(message->const_expr.global_ref->name); + break; case CONST_ENUM: case CONST_ERR: puts(message->const_expr.enum_err_val->name); diff --git a/test/test_suite/bitstruct/bitstruct_in_subarray.c3t b/test/test_suite/bitstruct/bitstruct_in_subarray.c3t index 3e37bba93..bb264a6a2 100644 --- a/test/test_suite/bitstruct/bitstruct_in_subarray.c3t +++ b/test/test_suite/bitstruct/bitstruct_in_subarray.c3t @@ -17,7 +17,7 @@ define i64 @test.main() #0 { entry: %xx = alloca %"char[]", align 8 %literal = alloca [1 x i8], align 1 - call void @llvm.memcpy.p0.p0.i32(ptr align 1 %literal, ptr align 1 @.__const, i32 1, i1 false) + store i8 2, ptr %literal, align 1 %0 = insertvalue %"char[]" undef, ptr %literal, 0 %1 = insertvalue %"char[]" %0, i64 1, 1 store %"char[]" %1, ptr %xx, align 8 diff --git a/test/test_suite/bitstruct/bitstruct_initializer.c3t b/test/test_suite/bitstruct/bitstruct_initializer.c3t index 666004788..fa136861f 100644 --- a/test/test_suite/bitstruct/bitstruct_initializer.c3t +++ b/test/test_suite/bitstruct/bitstruct_initializer.c3t @@ -56,34 +56,34 @@ entry: %b = alloca [8 x i8], align 1 %varargslots = alloca [3 x %any], align 16 %taddr = alloca i32, align 4 - %taddr30 = alloca i32, align 4 - %taddr34 = alloca i8, align 1 + %taddr32 = alloca i32, align 4 + %taddr36 = alloca i8, align 1 %retparam = alloca i64, align 8 - %varargslots36 = alloca [3 x %any], align 16 - %taddr39 = alloca i32, align 4 - %taddr43 = alloca i32, align 4 - %taddr48 = alloca i8, align 1 - %retparam50 = alloca i64, align 8 - %varargslots51 = alloca [3 x %any], align 16 - %taddr62 = alloca i32, align 4 - %taddr74 = alloca i32, align 4 - %taddr78 = alloca i8, align 1 - %retparam80 = alloca i64, align 8 - %varargslots111 = alloca [3 x %any], align 16 - %taddr113 = alloca i32, align 4 - %taddr116 = alloca i32, align 4 - %taddr120 = alloca i8, align 1 - %retparam122 = alloca i64, align 8 - %varargslots123 = alloca [3 x %any], align 16 - %taddr126 = alloca i32, align 4 - %taddr130 = alloca i32, align 4 - %taddr135 = alloca i8, align 1 - %retparam137 = alloca i64, align 8 - %varargslots138 = alloca [3 x %any], align 16 - %taddr149 = alloca i32, align 4 - %taddr161 = alloca i32, align 4 - %taddr165 = alloca i8, align 1 - %retparam167 = alloca i64, align 8 + %varargslots38 = alloca [3 x %any], align 16 + %taddr41 = alloca i32, align 4 + %taddr45 = alloca i32, align 4 + %taddr50 = alloca i8, align 1 + %retparam52 = alloca i64, align 8 + %varargslots53 = alloca [3 x %any], align 16 + %taddr64 = alloca i32, align 4 + %taddr76 = alloca i32, align 4 + %taddr80 = alloca i8, align 1 + %retparam82 = alloca i64, align 8 + %varargslots113 = alloca [3 x %any], align 16 + %taddr115 = alloca i32, align 4 + %taddr118 = alloca i32, align 4 + %taddr122 = alloca i8, align 1 + %retparam124 = alloca i64, align 8 + %varargslots125 = alloca [3 x %any], align 16 + %taddr128 = alloca i32, align 4 + %taddr132 = alloca i32, align 4 + %taddr137 = alloca i8, align 1 + %retparam139 = alloca i64, align 8 + %varargslots140 = alloca [3 x %any], align 16 + %taddr151 = alloca i32, align 4 + %taddr163 = alloca i32, align 4 + %taddr167 = alloca i8, align 1 + %retparam169 = alloca i64, align 8 store i64 0, ptr %x, align 8 %zext = zext i32 %0 to i64 %1 = and i64 %zext, 4294967295 @@ -95,351 +95,355 @@ entry: %4 = and i64 %1, 9223372036854775807 %5 = or i64 %4, %3 store i64 %5, ptr %x, align 8 - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %y, ptr align 8 @.__const, i32 16, i1 false) - call void @llvm.memcpy.p0.p0.i32(ptr align 8 %d, ptr align 8 @.__const.1, i32 16, i1 false) + store i32 0, ptr %y, align 8 + %ptradd = getelementptr inbounds i8, ptr %y, i64 8 + store i64 42949672992, ptr %ptradd, align 8 + store i32 0, ptr %d, align 8 + %ptradd2 = getelementptr inbounds i8, ptr %d, i64 8 + store i64 -9223371989610135529, ptr %ptradd2, align 8 store i8 0, ptr %b, align 1 - %ptradd = getelementptr inbounds i8, ptr %b, i64 1 - store i8 0, ptr %ptradd, align 1 - %ptradd2 = getelementptr inbounds i8, ptr %b, i64 2 - store i8 0, ptr %ptradd2, align 1 - %ptradd3 = getelementptr inbounds i8, ptr %b, i64 3 + %ptradd3 = getelementptr inbounds i8, ptr %b, i64 1 store i8 0, ptr %ptradd3, align 1 - %ptradd4 = getelementptr inbounds i8, ptr %b, i64 4 + %ptradd4 = getelementptr inbounds i8, ptr %b, i64 2 store i8 0, ptr %ptradd4, align 1 - %ptradd5 = getelementptr inbounds i8, ptr %b, i64 5 + %ptradd5 = getelementptr inbounds i8, ptr %b, i64 3 store i8 0, ptr %ptradd5, align 1 - %ptradd6 = getelementptr inbounds i8, ptr %b, i64 6 + %ptradd6 = getelementptr inbounds i8, ptr %b, i64 4 store i8 0, ptr %ptradd6, align 1 - %ptradd7 = getelementptr inbounds i8, ptr %b, i64 7 + %ptradd7 = getelementptr inbounds i8, ptr %b, i64 5 store i8 0, ptr %ptradd7, align 1 - store i8 0, ptr %b, align 1 - %ptradd8 = getelementptr inbounds i8, ptr %b, i64 1 + %ptradd8 = getelementptr inbounds i8, ptr %b, i64 6 store i8 0, ptr %ptradd8, align 1 - %ptradd9 = getelementptr inbounds i8, ptr %b, i64 2 + %ptradd9 = getelementptr inbounds i8, ptr %b, i64 7 store i8 0, ptr %ptradd9, align 1 - %ptradd10 = getelementptr inbounds i8, ptr %b, i64 3 + store i8 0, ptr %b, align 1 + %ptradd10 = getelementptr inbounds i8, ptr %b, i64 1 store i8 0, ptr %ptradd10, align 1 - %ptradd11 = getelementptr inbounds i8, ptr %b, i64 4 + %ptradd11 = getelementptr inbounds i8, ptr %b, i64 2 store i8 0, ptr %ptradd11, align 1 - %ptradd12 = getelementptr inbounds i8, ptr %b, i64 5 + %ptradd12 = getelementptr inbounds i8, ptr %b, i64 3 store i8 0, ptr %ptradd12, align 1 - %ptradd13 = getelementptr inbounds i8, ptr %b, i64 6 + %ptradd13 = getelementptr inbounds i8, ptr %b, i64 4 store i8 0, ptr %ptradd13, align 1 - %ptradd14 = getelementptr inbounds i8, ptr %b, i64 7 + %ptradd14 = getelementptr inbounds i8, ptr %b, i64 5 store i8 0, ptr %ptradd14, align 1 + %ptradd15 = getelementptr inbounds i8, ptr %b, i64 6 + store i8 0, ptr %ptradd15, align 1 + %ptradd16 = getelementptr inbounds i8, ptr %b, i64 7 + store i8 0, ptr %ptradd16, align 1 %trunc = trunc i32 %0 to i8 store i8 %trunc, ptr %b, align 1 %lshrl = lshr i32 %0, 8 - %ptradd15 = getelementptr inbounds i8, ptr %b, i64 1 - %trunc16 = trunc i32 %lshrl to i8 - store i8 %trunc16, ptr %ptradd15, align 1 - %lshrl17 = lshr i32 %lshrl, 8 - %ptradd18 = getelementptr inbounds i8, ptr %b, i64 2 - %trunc19 = trunc i32 %lshrl17 to i8 - store i8 %trunc19, ptr %ptradd18, align 1 - %lshrl20 = lshr i32 %lshrl17, 8 - %ptradd21 = getelementptr inbounds i8, ptr %b, i64 3 - %trunc22 = trunc i32 %lshrl20 to i8 - store i8 %trunc22, ptr %ptradd21, align 1 - %lshrl23 = lshr i32 %lshrl20, 8 - %lt24 = icmp slt i32 %0, 100 - %6 = zext i1 %lt24 to i8 - %shl25 = shl i8 %6, 7 - %ptradd26 = getelementptr inbounds i8, ptr %b, i64 7 - %7 = load i8, ptr %ptradd26, align 1 + %ptradd17 = getelementptr inbounds i8, ptr %b, i64 1 + %trunc18 = trunc i32 %lshrl to i8 + store i8 %trunc18, ptr %ptradd17, align 1 + %lshrl19 = lshr i32 %lshrl, 8 + %ptradd20 = getelementptr inbounds i8, ptr %b, i64 2 + %trunc21 = trunc i32 %lshrl19 to i8 + store i8 %trunc21, ptr %ptradd20, align 1 + %lshrl22 = lshr i32 %lshrl19, 8 + %ptradd23 = getelementptr inbounds i8, ptr %b, i64 3 + %trunc24 = trunc i32 %lshrl22 to i8 + store i8 %trunc24, ptr %ptradd23, align 1 + %lshrl25 = lshr i32 %lshrl22, 8 + %lt26 = icmp slt i32 %0, 100 + %6 = zext i1 %lt26 to i8 + %shl27 = shl i8 %6, 7 + %ptradd28 = getelementptr inbounds i8, ptr %b, i64 7 + %7 = load i8, ptr %ptradd28, align 1 %8 = and i8 %7, 127 - %9 = or i8 %8, %shl25 - store i8 %9, ptr %ptradd26, align 1 + %9 = or i8 %8, %shl27 + store i8 %9, ptr %ptradd28, align 1 %10 = load i64, ptr %x, align 8 %11 = and i64 4294967295, %10 - %trunc27 = trunc i64 %11 to i32 - store i32 %trunc27, ptr %taddr, align 4 + %trunc29 = trunc i64 %11 to i32 + store i32 %trunc29, ptr %taddr, align 4 %12 = insertvalue %any undef, ptr %taddr, 0 %13 = insertvalue %any %12, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 store %any %13, ptr %varargslots, align 16 %14 = load i64, ptr %x, align 8 - %lshrl28 = lshr i64 %14, 32 - %15 = and i64 2147483647, %lshrl28 - %trunc29 = trunc i64 %15 to i32 - store i32 %trunc29, ptr %taddr30, align 4 - %16 = insertvalue %any undef, ptr %taddr30, 0 + %lshrl30 = lshr i64 %14, 32 + %15 = and i64 2147483647, %lshrl30 + %trunc31 = trunc i64 %15 to i32 + store i32 %trunc31, ptr %taddr32, align 4 + %16 = insertvalue %any undef, ptr %taddr32, 0 %17 = insertvalue %any %16, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 - %ptradd31 = getelementptr inbounds i8, ptr %varargslots, i64 16 - store %any %17, ptr %ptradd31, align 16 + %ptradd33 = getelementptr inbounds i8, ptr %varargslots, i64 16 + store %any %17, ptr %ptradd33, align 16 %18 = load i64, ptr %x, align 8 - %lshrl32 = lshr i64 %18, 63 - %19 = and i64 1, %lshrl32 - %trunc33 = trunc i64 %19 to i8 - store i8 %trunc33, ptr %taddr34, align 1 - %20 = insertvalue %any undef, ptr %taddr34, 0 + %lshrl34 = lshr i64 %18, 63 + %19 = and i64 1, %lshrl34 + %trunc35 = trunc i64 %19 to i8 + store i8 %trunc35, ptr %taddr36, align 1 + %20 = insertvalue %any undef, ptr %taddr36, 0 %21 = insertvalue %any %20, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %ptradd35 = getelementptr inbounds i8, ptr %varargslots, i64 32 - store %any %21, ptr %ptradd35, align 16 + %ptradd37 = getelementptr inbounds i8, ptr %varargslots, i64 32 + store %any %21, ptr %ptradd37, align 16 %22 = call i64 @std.io.printfn(ptr %retparam, ptr @.str, i64 8, ptr %varargslots, i64 3) - %ptradd37 = getelementptr inbounds i8, ptr %y, i64 8 - %23 = load i64, ptr %ptradd37, align 8 + %ptradd39 = getelementptr inbounds i8, ptr %y, i64 8 + %23 = load i64, ptr %ptradd39, align 8 %24 = and i64 4294967295, %23 - %trunc38 = trunc i64 %24 to i32 - store i32 %trunc38, ptr %taddr39, align 4 - %25 = insertvalue %any undef, ptr %taddr39, 0 + %trunc40 = trunc i64 %24 to i32 + store i32 %trunc40, ptr %taddr41, align 4 + %25 = insertvalue %any undef, ptr %taddr41, 0 %26 = insertvalue %any %25, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 - store %any %26, ptr %varargslots36, align 16 - %ptradd40 = getelementptr inbounds i8, ptr %y, i64 8 - %27 = load i64, ptr %ptradd40, align 8 - %lshrl41 = lshr i64 %27, 32 - %28 = and i64 2147483647, %lshrl41 - %trunc42 = trunc i64 %28 to i32 - store i32 %trunc42, ptr %taddr43, align 4 - %29 = insertvalue %any undef, ptr %taddr43, 0 + store %any %26, ptr %varargslots38, align 16 + %ptradd42 = getelementptr inbounds i8, ptr %y, i64 8 + %27 = load i64, ptr %ptradd42, align 8 + %lshrl43 = lshr i64 %27, 32 + %28 = and i64 2147483647, %lshrl43 + %trunc44 = trunc i64 %28 to i32 + store i32 %trunc44, ptr %taddr45, align 4 + %29 = insertvalue %any undef, ptr %taddr45, 0 %30 = insertvalue %any %29, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 - %ptradd44 = getelementptr inbounds i8, ptr %varargslots36, i64 16 - store %any %30, ptr %ptradd44, align 16 - %ptradd45 = getelementptr inbounds i8, ptr %y, i64 8 - %31 = load i64, ptr %ptradd45, align 8 - %lshrl46 = lshr i64 %31, 63 - %32 = and i64 1, %lshrl46 - %trunc47 = trunc i64 %32 to i8 - store i8 %trunc47, ptr %taddr48, align 1 - %33 = insertvalue %any undef, ptr %taddr48, 0 + %ptradd46 = getelementptr inbounds i8, ptr %varargslots38, i64 16 + store %any %30, ptr %ptradd46, align 16 + %ptradd47 = getelementptr inbounds i8, ptr %y, i64 8 + %31 = load i64, ptr %ptradd47, align 8 + %lshrl48 = lshr i64 %31, 63 + %32 = and i64 1, %lshrl48 + %trunc49 = trunc i64 %32 to i8 + store i8 %trunc49, ptr %taddr50, align 1 + %33 = insertvalue %any undef, ptr %taddr50, 0 %34 = insertvalue %any %33, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %ptradd49 = getelementptr inbounds i8, ptr %varargslots36, i64 32 - store %any %34, ptr %ptradd49, align 16 - %35 = call i64 @std.io.printfn(ptr %retparam50, ptr @.str.2, i64 8, ptr %varargslots36, i64 3) + %ptradd51 = getelementptr inbounds i8, ptr %varargslots38, i64 32 + store %any %34, ptr %ptradd51, align 16 + %35 = call i64 @std.io.printfn(ptr %retparam52, ptr @.str.1, i64 8, ptr %varargslots38, i64 3) %36 = load i8, ptr %b, align 1 - %zext52 = zext i8 %36 to i32 - %ptradd53 = getelementptr inbounds i8, ptr %b, i64 1 - %37 = load i8, ptr %ptradd53, align 1 - %zext54 = zext i8 %37 to i32 - %shl55 = shl i32 %zext54, 8 - %38 = or i32 %shl55, %zext52 - %ptradd56 = getelementptr inbounds i8, ptr %b, i64 2 - %39 = load i8, ptr %ptradd56, align 1 - %zext57 = zext i8 %39 to i32 - %shl58 = shl i32 %zext57, 16 - %40 = or i32 %shl58, %38 - %ptradd59 = getelementptr inbounds i8, ptr %b, i64 3 - %41 = load i8, ptr %ptradd59, align 1 - %zext60 = zext i8 %41 to i32 - %shl61 = shl i32 %zext60, 24 - %42 = or i32 %shl61, %40 - store i32 %42, ptr %taddr62, align 4 - %43 = insertvalue %any undef, ptr %taddr62, 0 + %zext54 = zext i8 %36 to i32 + %ptradd55 = getelementptr inbounds i8, ptr %b, i64 1 + %37 = load i8, ptr %ptradd55, align 1 + %zext56 = zext i8 %37 to i32 + %shl57 = shl i32 %zext56, 8 + %38 = or i32 %shl57, %zext54 + %ptradd58 = getelementptr inbounds i8, ptr %b, i64 2 + %39 = load i8, ptr %ptradd58, align 1 + %zext59 = zext i8 %39 to i32 + %shl60 = shl i32 %zext59, 16 + %40 = or i32 %shl60, %38 + %ptradd61 = getelementptr inbounds i8, ptr %b, i64 3 + %41 = load i8, ptr %ptradd61, align 1 + %zext62 = zext i8 %41 to i32 + %shl63 = shl i32 %zext62, 24 + %42 = or i32 %shl63, %40 + store i32 %42, ptr %taddr64, align 4 + %43 = insertvalue %any undef, ptr %taddr64, 0 %44 = insertvalue %any %43, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 - store %any %44, ptr %varargslots51, align 16 - %ptradd63 = getelementptr inbounds i8, ptr %b, i64 4 - %45 = load i8, ptr %ptradd63, align 1 - %zext64 = zext i8 %45 to i32 - %ptradd65 = getelementptr inbounds i8, ptr %b, i64 5 - %46 = load i8, ptr %ptradd65, align 1 - %zext66 = zext i8 %46 to i32 - %shl67 = shl i32 %zext66, 8 - %47 = or i32 %shl67, %zext64 - %ptradd68 = getelementptr inbounds i8, ptr %b, i64 6 - %48 = load i8, ptr %ptradd68, align 1 - %zext69 = zext i8 %48 to i32 - %shl70 = shl i32 %zext69, 16 - %49 = or i32 %shl70, %47 - %ptradd71 = getelementptr inbounds i8, ptr %b, i64 7 - %50 = load i8, ptr %ptradd71, align 1 - %zext72 = zext i8 %50 to i32 - %shl73 = shl i32 %zext72, 24 - %51 = or i32 %shl73, %49 + store %any %44, ptr %varargslots53, align 16 + %ptradd65 = getelementptr inbounds i8, ptr %b, i64 4 + %45 = load i8, ptr %ptradd65, align 1 + %zext66 = zext i8 %45 to i32 + %ptradd67 = getelementptr inbounds i8, ptr %b, i64 5 + %46 = load i8, ptr %ptradd67, align 1 + %zext68 = zext i8 %46 to i32 + %shl69 = shl i32 %zext68, 8 + %47 = or i32 %shl69, %zext66 + %ptradd70 = getelementptr inbounds i8, ptr %b, i64 6 + %48 = load i8, ptr %ptradd70, align 1 + %zext71 = zext i8 %48 to i32 + %shl72 = shl i32 %zext71, 16 + %49 = or i32 %shl72, %47 + %ptradd73 = getelementptr inbounds i8, ptr %b, i64 7 + %50 = load i8, ptr %ptradd73, align 1 + %zext74 = zext i8 %50 to i32 + %shl75 = shl i32 %zext74, 24 + %51 = or i32 %shl75, %49 %52 = and i32 2147483647, %51 - store i32 %52, ptr %taddr74, align 4 - %53 = insertvalue %any undef, ptr %taddr74, 0 + store i32 %52, ptr %taddr76, align 4 + %53 = insertvalue %any undef, ptr %taddr76, 0 %54 = insertvalue %any %53, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 - %ptradd75 = getelementptr inbounds i8, ptr %varargslots51, i64 16 - store %any %54, ptr %ptradd75, align 16 - %ptradd76 = getelementptr inbounds i8, ptr %b, i64 7 - %55 = load i8, ptr %ptradd76, align 1 - %lshrl77 = lshr i8 %55, 7 - %56 = trunc i8 %lshrl77 to i1 + %ptradd77 = getelementptr inbounds i8, ptr %varargslots53, i64 16 + store %any %54, ptr %ptradd77, align 16 + %ptradd78 = getelementptr inbounds i8, ptr %b, i64 7 + %55 = load i8, ptr %ptradd78, align 1 + %lshrl79 = lshr i8 %55, 7 + %56 = trunc i8 %lshrl79 to i1 %57 = zext i1 %56 to i8 - store i8 %57, ptr %taddr78, align 1 - %58 = insertvalue %any undef, ptr %taddr78, 0 + store i8 %57, ptr %taddr80, align 1 + %58 = insertvalue %any undef, ptr %taddr80, 0 %59 = insertvalue %any %58, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %ptradd79 = getelementptr inbounds i8, ptr %varargslots51, i64 32 - store %any %59, ptr %ptradd79, align 16 - %60 = call i64 @std.io.printfn(ptr %retparam80, ptr @.str.3, i64 8, ptr %varargslots51, i64 3) + %ptradd81 = getelementptr inbounds i8, ptr %varargslots53, i64 32 + store %any %59, ptr %ptradd81, align 16 + %60 = call i64 @std.io.printfn(ptr %retparam82, ptr @.str.2, i64 8, ptr %varargslots53, i64 3) %add = add i32 %0, 1 - %zext81 = zext i32 %add to i64 - %61 = and i64 %zext81, 4294967295 + %zext83 = zext i32 %add to i64 + %61 = and i64 %zext83, 4294967295 %62 = and i64 %61, -9223372032559808513 %63 = or i64 %62, 4294967296 %gt = icmp sgt i32 %0, 100 %64 = zext i1 %gt to i8 - %zext82 = zext i8 %64 to i64 - %shl83 = shl i64 %zext82, 63 - %65 = and i64 %shl83, -9223372036854775808 + %zext84 = zext i8 %64 to i64 + %shl85 = shl i64 %zext84, 63 + %65 = and i64 %shl85, -9223372036854775808 %66 = and i64 %63, 9223372036854775807 %67 = or i64 %66, %65 store i64 %67, ptr %x, align 8 - %ptradd84 = getelementptr inbounds i8, ptr %y, i64 8 - store i64 -9223371989610135519, ptr %ptradd84, align 8 + %ptradd86 = getelementptr inbounds i8, ptr %y, i64 8 + store i64 -9223371989610135519, ptr %ptradd86, align 8 store i8 0, ptr %b, align 1 - %ptradd85 = getelementptr inbounds i8, ptr %b, i64 1 - store i8 0, ptr %ptradd85, align 1 - %ptradd86 = getelementptr inbounds i8, ptr %b, i64 2 - store i8 0, ptr %ptradd86, align 1 - %ptradd87 = getelementptr inbounds i8, ptr %b, i64 3 + %ptradd87 = getelementptr inbounds i8, ptr %b, i64 1 store i8 0, ptr %ptradd87, align 1 - %ptradd88 = getelementptr inbounds i8, ptr %b, i64 4 + %ptradd88 = getelementptr inbounds i8, ptr %b, i64 2 store i8 0, ptr %ptradd88, align 1 - %ptradd89 = getelementptr inbounds i8, ptr %b, i64 5 + %ptradd89 = getelementptr inbounds i8, ptr %b, i64 3 store i8 0, ptr %ptradd89, align 1 - %ptradd90 = getelementptr inbounds i8, ptr %b, i64 6 + %ptradd90 = getelementptr inbounds i8, ptr %b, i64 4 store i8 0, ptr %ptradd90, align 1 - %ptradd91 = getelementptr inbounds i8, ptr %b, i64 7 + %ptradd91 = getelementptr inbounds i8, ptr %b, i64 5 store i8 0, ptr %ptradd91, align 1 - %add92 = add i32 %0, 1 - %trunc93 = trunc i32 %add92 to i8 - store i8 %trunc93, ptr %b, align 1 - %lshrl94 = lshr i32 %add92, 8 - %ptradd95 = getelementptr inbounds i8, ptr %b, i64 1 - %trunc96 = trunc i32 %lshrl94 to i8 - store i8 %trunc96, ptr %ptradd95, align 1 - %lshrl97 = lshr i32 %lshrl94, 8 - %ptradd98 = getelementptr inbounds i8, ptr %b, i64 2 - %trunc99 = trunc i32 %lshrl97 to i8 - store i8 %trunc99, ptr %ptradd98, align 1 - %lshrl100 = lshr i32 %lshrl97, 8 - %ptradd101 = getelementptr inbounds i8, ptr %b, i64 3 - %trunc102 = trunc i32 %lshrl100 to i8 - store i8 %trunc102, ptr %ptradd101, align 1 - %lshrl103 = lshr i32 %lshrl100, 8 - %ptradd104 = getelementptr inbounds i8, ptr %b, i64 4 - store i8 1, ptr %ptradd104, align 1 - %ptradd105 = getelementptr inbounds i8, ptr %b, i64 5 - store i8 0, ptr %ptradd105, align 1 - %ptradd106 = getelementptr inbounds i8, ptr %b, i64 6 - store i8 0, ptr %ptradd106, align 1 - %ptradd107 = getelementptr inbounds i8, ptr %b, i64 7 - %68 = load i8, ptr %ptradd107, align 1 + %ptradd92 = getelementptr inbounds i8, ptr %b, i64 6 + store i8 0, ptr %ptradd92, align 1 + %ptradd93 = getelementptr inbounds i8, ptr %b, i64 7 + store i8 0, ptr %ptradd93, align 1 + %add94 = add i32 %0, 1 + %trunc95 = trunc i32 %add94 to i8 + store i8 %trunc95, ptr %b, align 1 + %lshrl96 = lshr i32 %add94, 8 + %ptradd97 = getelementptr inbounds i8, ptr %b, i64 1 + %trunc98 = trunc i32 %lshrl96 to i8 + store i8 %trunc98, ptr %ptradd97, align 1 + %lshrl99 = lshr i32 %lshrl96, 8 + %ptradd100 = getelementptr inbounds i8, ptr %b, i64 2 + %trunc101 = trunc i32 %lshrl99 to i8 + store i8 %trunc101, ptr %ptradd100, align 1 + %lshrl102 = lshr i32 %lshrl99, 8 + %ptradd103 = getelementptr inbounds i8, ptr %b, i64 3 + %trunc104 = trunc i32 %lshrl102 to i8 + store i8 %trunc104, ptr %ptradd103, align 1 + %lshrl105 = lshr i32 %lshrl102, 8 + %ptradd106 = getelementptr inbounds i8, ptr %b, i64 4 + store i8 1, ptr %ptradd106, align 1 + %ptradd107 = getelementptr inbounds i8, ptr %b, i64 5 + store i8 0, ptr %ptradd107, align 1 + %ptradd108 = getelementptr inbounds i8, ptr %b, i64 6 + store i8 0, ptr %ptradd108, align 1 + %ptradd109 = getelementptr inbounds i8, ptr %b, i64 7 + %68 = load i8, ptr %ptradd109, align 1 %69 = and i8 %68, -128 - store i8 %69, ptr %ptradd107, align 1 - %gt108 = icmp sgt i32 %0, 100 - %70 = zext i1 %gt108 to i8 - %shl109 = shl i8 %70, 7 - %ptradd110 = getelementptr inbounds i8, ptr %b, i64 7 - %71 = load i8, ptr %ptradd110, align 1 + store i8 %69, ptr %ptradd109, align 1 + %gt110 = icmp sgt i32 %0, 100 + %70 = zext i1 %gt110 to i8 + %shl111 = shl i8 %70, 7 + %ptradd112 = getelementptr inbounds i8, ptr %b, i64 7 + %71 = load i8, ptr %ptradd112, align 1 %72 = and i8 %71, 127 - %73 = or i8 %72, %shl109 - store i8 %73, ptr %ptradd110, align 1 + %73 = or i8 %72, %shl111 + store i8 %73, ptr %ptradd112, align 1 %74 = load i64, ptr %x, align 8 %75 = and i64 4294967295, %74 - %trunc112 = trunc i64 %75 to i32 - store i32 %trunc112, ptr %taddr113, align 4 - %76 = insertvalue %any undef, ptr %taddr113, 0 + %trunc114 = trunc i64 %75 to i32 + store i32 %trunc114, ptr %taddr115, align 4 + %76 = insertvalue %any undef, ptr %taddr115, 0 %77 = insertvalue %any %76, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 - store %any %77, ptr %varargslots111, align 16 + store %any %77, ptr %varargslots113, align 16 %78 = load i64, ptr %x, align 8 - %lshrl114 = lshr i64 %78, 32 - %79 = and i64 2147483647, %lshrl114 - %trunc115 = trunc i64 %79 to i32 - store i32 %trunc115, ptr %taddr116, align 4 - %80 = insertvalue %any undef, ptr %taddr116, 0 + %lshrl116 = lshr i64 %78, 32 + %79 = and i64 2147483647, %lshrl116 + %trunc117 = trunc i64 %79 to i32 + store i32 %trunc117, ptr %taddr118, align 4 + %80 = insertvalue %any undef, ptr %taddr118, 0 %81 = insertvalue %any %80, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 - %ptradd117 = getelementptr inbounds i8, ptr %varargslots111, i64 16 - store %any %81, ptr %ptradd117, align 16 + %ptradd119 = getelementptr inbounds i8, ptr %varargslots113, i64 16 + store %any %81, ptr %ptradd119, align 16 %82 = load i64, ptr %x, align 8 - %lshrl118 = lshr i64 %82, 63 - %83 = and i64 1, %lshrl118 - %trunc119 = trunc i64 %83 to i8 - store i8 %trunc119, ptr %taddr120, align 1 - %84 = insertvalue %any undef, ptr %taddr120, 0 + %lshrl120 = lshr i64 %82, 63 + %83 = and i64 1, %lshrl120 + %trunc121 = trunc i64 %83 to i8 + store i8 %trunc121, ptr %taddr122, align 1 + %84 = insertvalue %any undef, ptr %taddr122, 0 %85 = insertvalue %any %84, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %ptradd121 = getelementptr inbounds i8, ptr %varargslots111, i64 32 - store %any %85, ptr %ptradd121, align 16 - %86 = call i64 @std.io.printfn(ptr %retparam122, ptr @.str.4, i64 8, ptr %varargslots111, i64 3) - %ptradd124 = getelementptr inbounds i8, ptr %y, i64 8 - %87 = load i64, ptr %ptradd124, align 8 + %ptradd123 = getelementptr inbounds i8, ptr %varargslots113, i64 32 + store %any %85, ptr %ptradd123, align 16 + %86 = call i64 @std.io.printfn(ptr %retparam124, ptr @.str.3, i64 8, ptr %varargslots113, i64 3) + %ptradd126 = getelementptr inbounds i8, ptr %y, i64 8 + %87 = load i64, ptr %ptradd126, align 8 %88 = and i64 4294967295, %87 - %trunc125 = trunc i64 %88 to i32 - store i32 %trunc125, ptr %taddr126, align 4 - %89 = insertvalue %any undef, ptr %taddr126, 0 + %trunc127 = trunc i64 %88 to i32 + store i32 %trunc127, ptr %taddr128, align 4 + %89 = insertvalue %any undef, ptr %taddr128, 0 %90 = insertvalue %any %89, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 - store %any %90, ptr %varargslots123, align 16 - %ptradd127 = getelementptr inbounds i8, ptr %y, i64 8 - %91 = load i64, ptr %ptradd127, align 8 - %lshrl128 = lshr i64 %91, 32 - %92 = and i64 2147483647, %lshrl128 - %trunc129 = trunc i64 %92 to i32 - store i32 %trunc129, ptr %taddr130, align 4 - %93 = insertvalue %any undef, ptr %taddr130, 0 + store %any %90, ptr %varargslots125, align 16 + %ptradd129 = getelementptr inbounds i8, ptr %y, i64 8 + %91 = load i64, ptr %ptradd129, align 8 + %lshrl130 = lshr i64 %91, 32 + %92 = and i64 2147483647, %lshrl130 + %trunc131 = trunc i64 %92 to i32 + store i32 %trunc131, ptr %taddr132, align 4 + %93 = insertvalue %any undef, ptr %taddr132, 0 %94 = insertvalue %any %93, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 - %ptradd131 = getelementptr inbounds i8, ptr %varargslots123, i64 16 - store %any %94, ptr %ptradd131, align 16 - %ptradd132 = getelementptr inbounds i8, ptr %y, i64 8 - %95 = load i64, ptr %ptradd132, align 8 - %lshrl133 = lshr i64 %95, 63 - %96 = and i64 1, %lshrl133 - %trunc134 = trunc i64 %96 to i8 - store i8 %trunc134, ptr %taddr135, align 1 - %97 = insertvalue %any undef, ptr %taddr135, 0 + %ptradd133 = getelementptr inbounds i8, ptr %varargslots125, i64 16 + store %any %94, ptr %ptradd133, align 16 + %ptradd134 = getelementptr inbounds i8, ptr %y, i64 8 + %95 = load i64, ptr %ptradd134, align 8 + %lshrl135 = lshr i64 %95, 63 + %96 = and i64 1, %lshrl135 + %trunc136 = trunc i64 %96 to i8 + store i8 %trunc136, ptr %taddr137, align 1 + %97 = insertvalue %any undef, ptr %taddr137, 0 %98 = insertvalue %any %97, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %ptradd136 = getelementptr inbounds i8, ptr %varargslots123, i64 32 - store %any %98, ptr %ptradd136, align 16 - %99 = call i64 @std.io.printfn(ptr %retparam137, ptr @.str.5, i64 8, ptr %varargslots123, i64 3) + %ptradd138 = getelementptr inbounds i8, ptr %varargslots125, i64 32 + store %any %98, ptr %ptradd138, align 16 + %99 = call i64 @std.io.printfn(ptr %retparam139, ptr @.str.4, i64 8, ptr %varargslots125, i64 3) %100 = load i8, ptr %b, align 1 - %zext139 = zext i8 %100 to i32 - %ptradd140 = getelementptr inbounds i8, ptr %b, i64 1 - %101 = load i8, ptr %ptradd140, align 1 - %zext141 = zext i8 %101 to i32 - %shl142 = shl i32 %zext141, 8 - %102 = or i32 %shl142, %zext139 - %ptradd143 = getelementptr inbounds i8, ptr %b, i64 2 - %103 = load i8, ptr %ptradd143, align 1 - %zext144 = zext i8 %103 to i32 - %shl145 = shl i32 %zext144, 16 - %104 = or i32 %shl145, %102 - %ptradd146 = getelementptr inbounds i8, ptr %b, i64 3 - %105 = load i8, ptr %ptradd146, align 1 - %zext147 = zext i8 %105 to i32 - %shl148 = shl i32 %zext147, 24 - %106 = or i32 %shl148, %104 - store i32 %106, ptr %taddr149, align 4 - %107 = insertvalue %any undef, ptr %taddr149, 0 + %zext141 = zext i8 %100 to i32 + %ptradd142 = getelementptr inbounds i8, ptr %b, i64 1 + %101 = load i8, ptr %ptradd142, align 1 + %zext143 = zext i8 %101 to i32 + %shl144 = shl i32 %zext143, 8 + %102 = or i32 %shl144, %zext141 + %ptradd145 = getelementptr inbounds i8, ptr %b, i64 2 + %103 = load i8, ptr %ptradd145, align 1 + %zext146 = zext i8 %103 to i32 + %shl147 = shl i32 %zext146, 16 + %104 = or i32 %shl147, %102 + %ptradd148 = getelementptr inbounds i8, ptr %b, i64 3 + %105 = load i8, ptr %ptradd148, align 1 + %zext149 = zext i8 %105 to i32 + %shl150 = shl i32 %zext149, 24 + %106 = or i32 %shl150, %104 + store i32 %106, ptr %taddr151, align 4 + %107 = insertvalue %any undef, ptr %taddr151, 0 %108 = insertvalue %any %107, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 - store %any %108, ptr %varargslots138, align 16 - %ptradd150 = getelementptr inbounds i8, ptr %b, i64 4 - %109 = load i8, ptr %ptradd150, align 1 - %zext151 = zext i8 %109 to i32 - %ptradd152 = getelementptr inbounds i8, ptr %b, i64 5 - %110 = load i8, ptr %ptradd152, align 1 - %zext153 = zext i8 %110 to i32 - %shl154 = shl i32 %zext153, 8 - %111 = or i32 %shl154, %zext151 - %ptradd155 = getelementptr inbounds i8, ptr %b, i64 6 - %112 = load i8, ptr %ptradd155, align 1 - %zext156 = zext i8 %112 to i32 - %shl157 = shl i32 %zext156, 16 - %113 = or i32 %shl157, %111 - %ptradd158 = getelementptr inbounds i8, ptr %b, i64 7 - %114 = load i8, ptr %ptradd158, align 1 - %zext159 = zext i8 %114 to i32 - %shl160 = shl i32 %zext159, 24 - %115 = or i32 %shl160, %113 + store %any %108, ptr %varargslots140, align 16 + %ptradd152 = getelementptr inbounds i8, ptr %b, i64 4 + %109 = load i8, ptr %ptradd152, align 1 + %zext153 = zext i8 %109 to i32 + %ptradd154 = getelementptr inbounds i8, ptr %b, i64 5 + %110 = load i8, ptr %ptradd154, align 1 + %zext155 = zext i8 %110 to i32 + %shl156 = shl i32 %zext155, 8 + %111 = or i32 %shl156, %zext153 + %ptradd157 = getelementptr inbounds i8, ptr %b, i64 6 + %112 = load i8, ptr %ptradd157, align 1 + %zext158 = zext i8 %112 to i32 + %shl159 = shl i32 %zext158, 16 + %113 = or i32 %shl159, %111 + %ptradd160 = getelementptr inbounds i8, ptr %b, i64 7 + %114 = load i8, ptr %ptradd160, align 1 + %zext161 = zext i8 %114 to i32 + %shl162 = shl i32 %zext161, 24 + %115 = or i32 %shl162, %113 %116 = and i32 2147483647, %115 - store i32 %116, ptr %taddr161, align 4 - %117 = insertvalue %any undef, ptr %taddr161, 0 + store i32 %116, ptr %taddr163, align 4 + %117 = insertvalue %any undef, ptr %taddr163, 0 %118 = insertvalue %any %117, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 - %ptradd162 = getelementptr inbounds i8, ptr %varargslots138, i64 16 - store %any %118, ptr %ptradd162, align 16 - %ptradd163 = getelementptr inbounds i8, ptr %b, i64 7 - %119 = load i8, ptr %ptradd163, align 1 - %lshrl164 = lshr i8 %119, 7 - %120 = trunc i8 %lshrl164 to i1 + %ptradd164 = getelementptr inbounds i8, ptr %varargslots140, i64 16 + store %any %118, ptr %ptradd164, align 16 + %ptradd165 = getelementptr inbounds i8, ptr %b, i64 7 + %119 = load i8, ptr %ptradd165, align 1 + %lshrl166 = lshr i8 %119, 7 + %120 = trunc i8 %lshrl166 to i1 %121 = zext i1 %120 to i8 - store i8 %121, ptr %taddr165, align 1 - %122 = insertvalue %any undef, ptr %taddr165, 0 + store i8 %121, ptr %taddr167, align 1 + %122 = insertvalue %any undef, ptr %taddr167, 0 %123 = insertvalue %any %122, i64 ptrtoint (ptr @"$ct.bool" to i64), 1 - %ptradd166 = getelementptr inbounds i8, ptr %varargslots138, i64 32 - store %any %123, ptr %ptradd166, align 16 - %124 = call i64 @std.io.printfn(ptr %retparam167, ptr @.str.6, i64 8, ptr %varargslots138, i64 3) + %ptradd168 = getelementptr inbounds i8, ptr %varargslots140, i64 32 + store %any %123, ptr %ptradd168, align 16 + %124 = call i64 @std.io.printfn(ptr %retparam169, ptr @.str.5, i64 8, ptr %varargslots140, i64 3) ret void } -; Function Attrs: +; Function Attrs: nounwind uwtable define void @test.main() #0 { entry: call void @test.hello(i32 12) diff --git a/test/test_suite/pointers/const_ref.c3t b/test/test_suite/pointers/const_ref.c3t new file mode 100644 index 000000000..517502459 --- /dev/null +++ b/test/test_suite/pointers/const_ref.c3t @@ -0,0 +1,25 @@ +// #target: macos-x64 +module test; +const int[*] X = int[*] { 1, 2, 3 }; +int[*] y = int[*] { 1, 2, 3 }; + +fn int main() +{ + var $z = { &y, "hello" }; + (*$z[0])[1] = 4; + assert(y[1] == 4); + return 0; +} +/* #expect: test.ll + +@test.X = local_unnamed_addr constant [3 x i32] [i32 1, i32 2, i32 3], align 4 +@test.y = global [3 x i32] [i32 1, i32 2, i32 3], align 4 + +define i32 @main() #0 { +entry: + store i32 4, ptr getelementptr inbounds (i8, ptr @test.y, i64 4), align 4 + %0 = load i32, ptr getelementptr inbounds (i8, ptr @test.y, i64 4), align 4 + %eq = icmp eq i32 %0, 4 + call void @llvm.assume(i1 %eq) + ret i32 0 +} diff --git a/test/test_suite/pointers/pointer_index.c3t b/test/test_suite/pointers/pointer_index.c3t index 461a4061f..994021dfc 100644 --- a/test/test_suite/pointers/pointer_index.c3t +++ b/test/test_suite/pointers/pointer_index.c3t @@ -1,3 +1,4 @@ +// #target: macos-x64 module pointer_index; fn void test1(int* x)