diff --git a/lib/std/io/formatter.c3 b/lib/std/io/formatter.c3 index 050c2dede..6b556c23a 100644 --- a/lib/std/io/formatter.c3 +++ b/lib/std/io/formatter.c3 @@ -19,7 +19,7 @@ alias FloatType = double; macro bool is_struct_with_default_print($Type) { - return $Type.kindof == STRUCT + return ($Type.kindof == STRUCT ||| $Type.kindof == BITSTRUCT) &&& !$defined($Type.to_format) &&& !$defined($Type.to_constant_string); } @@ -27,7 +27,7 @@ macro bool is_struct_with_default_print($Type) <* Introspect a struct and print it to a formatter - @require @typekind(value) == STRUCT : `This macro is only valid on macros` + @require @typekind(value) == STRUCT || @typekind(value) == BITSTRUCT : `This macro is only valid on macros` *> macro usz? struct_to_format(value, Formatter* f, bool $force_dump) { @@ -40,7 +40,7 @@ macro usz? struct_to_format(value, Formatter* f, bool $force_dump) $if $member.nameof != "": total += f.printf("%s: ", $member.nameof)!; $endif - $if ($force_dump &&& $member.typeid.kindof == STRUCT) ||| + $if ($force_dump &&& ($member.typeid.kindof == STRUCT || $member.typeid.kindof == BITSTRUCT)) ||| is_struct_with_default_print($member.typeid): total += struct_to_format($member.get(value), f, $force_dump)!; $else diff --git a/releasenotes.md b/releasenotes.md index 856aa1290..ab94dc777 100644 --- a/releasenotes.md +++ b/releasenotes.md @@ -28,6 +28,8 @@ - Add `@allow_deprecated` attribute to functions to selectively allow deprecated declarations #2223. - Improve error message on pointer diff #2239. - Compile-time comparison of constant vectors. #1575. +- $member.get supports bitstructs. +- $member.set for setting members without the *& trick. ### Fixes - `-2147483648`, MIN literals work correctly. @@ -76,6 +78,7 @@ - Add comparison with `==` for ZString types. - `is_array_or_slice_of_char` and `is_arrayptr_or_slice_of_char` are replaced by constant `@` variants. - `@pool` now has an optional `reserve` parameter, some minor changes to the temp_allocator API +- io::struct_to_format now supports bitstructs. ## 0.7.2 Change list diff --git a/src/compiler/c_codegen.c b/src/compiler/c_codegen.c index 22ee909ed..7b74c0588 100644 --- a/src/compiler/c_codegen.c +++ b/src/compiler/c_codegen.c @@ -467,6 +467,7 @@ static void c_emit_expr(GenContext *c, CValue *value, Expr *expr) case EXPR_MACRO_BODY_EXPANSION: break; case EXPR_MEMBER_GET: + case EXPR_MEMBER_SET: break; case EXPR_NAMED_ARGUMENT: break; diff --git a/src/compiler/compiler_internal.h b/src/compiler/compiler_internal.h index 6a4648a67..daf827379 100644 --- a/src/compiler/compiler_internal.h +++ b/src/compiler/compiler_internal.h @@ -3548,6 +3548,7 @@ static inline void expr_set_span(Expr *expr, SourceSpan loc) case EXPR_DEFAULT_ARG: case EXPR_TYPECALL: case EXPR_MEMBER_GET: + case EXPR_MEMBER_SET: case EXPR_RVALUE: case EXPR_CT_SUBSCRIPT: break; diff --git a/src/compiler/copying.c b/src/compiler/copying.c index 77c1e776f..78bf8338f 100644 --- a/src/compiler/copying.c +++ b/src/compiler/copying.c @@ -335,6 +335,7 @@ Expr *copy_expr(CopyStruct *c, Expr *source_expr) } return expr; case EXPR_MEMBER_GET: + case EXPR_MEMBER_SET: fixup_decl(c, &expr->member_get_expr); break; case EXPR_SWIZZLE: diff --git a/src/compiler/enums.h b/src/compiler/enums.h index 12ed1b7d0..de8956315 100644 --- a/src/compiler/enums.h +++ b/src/compiler/enums.h @@ -780,6 +780,7 @@ typedef enum EXPR_MAKE_ANY, EXPR_MAKE_SLICE, EXPR_MEMBER_GET, + EXPR_MEMBER_SET, EXPR_NAMED_ARGUMENT, EXPR_NOP, EXPR_OPERATOR_CHARS, @@ -1421,6 +1422,7 @@ typedef enum TYPE_PROPERTY_QNAMEOF, TYPE_PROPERTY_RETURNS, TYPE_PROPERTY_SIZEOF, + TYPE_PROPERTY_SET, TYPE_PROPERTY_TAGOF, TYPE_PROPERTY_HAS_TAGOF, TYPE_PROPERTY_VALUES, diff --git a/src/compiler/expr.c b/src/compiler/expr.c index 5af16fbbf..30c403ef7 100644 --- a/src/compiler/expr.c +++ b/src/compiler/expr.c @@ -65,6 +65,7 @@ const char *expr_kind_to_string(ExprKind kind) case EXPR_MAKE_ANY: return "make_any"; case EXPR_MAKE_SLICE: return "make_slice"; case EXPR_MEMBER_GET: return "member_get"; + case EXPR_MEMBER_SET: return "member_set"; case EXPR_NAMED_ARGUMENT: return "named_argument"; case EXPR_NOP: return "nop"; case EXPR_OPERATOR_CHARS: return "operator_chars"; @@ -223,6 +224,7 @@ bool expr_may_addr(Expr *expr) case EXPR_SUBSCRIPT: case EXPR_MEMBER_GET: return true; + case EXPR_MEMBER_SET: case EXPR_SLICE: case EXPR_BENCHMARK_HOOK: case EXPR_TEST_HOOK: @@ -328,6 +330,7 @@ bool expr_is_runtime_const(Expr *expr) case EXPR_MACRO_BLOCK: case EXPR_RETHROW: case EXPR_MEMBER_GET: + case EXPR_MEMBER_SET: case EXPR_BITACCESS: case EXPR_COND: case EXPR_PTR_ACCESS: @@ -828,6 +831,7 @@ bool expr_is_pure(Expr *expr) case EXPR_TYPEINFO: case EXPR_LAST_FAULT: case EXPR_MEMBER_GET: + case EXPR_MEMBER_SET: return true; case EXPR_TWO: return expr_is_pure(expr->two_expr.first) && expr_is_pure(expr->two_expr.last); diff --git a/src/compiler/llvm_codegen_expr.c b/src/compiler/llvm_codegen_expr.c index fee2794eb..5fd37d020 100644 --- a/src/compiler/llvm_codegen_expr.c +++ b/src/compiler/llvm_codegen_expr.c @@ -6983,6 +6983,7 @@ void llvm_emit_expr(GenContext *c, BEValue *value, Expr *expr) case EXPR_ASM: case EXPR_DESIGNATOR: case EXPR_MEMBER_GET: + case EXPR_MEMBER_SET: case EXPR_NAMED_ARGUMENT: case EXPR_BUILTIN: case EXPR_OPERATOR_CHARS: diff --git a/src/compiler/sema_expr.c b/src/compiler/sema_expr.c index 2084dbf8d..4eda1877f 100644 --- a/src/compiler/sema_expr.c +++ b/src/compiler/sema_expr.c @@ -631,6 +631,7 @@ static bool sema_binary_is_expr_lvalue(SemaContext *context, Expr *top_expr, Exp case EXPR_MAKE_ANY: case EXPR_MAKE_SLICE: case EXPR_MEMBER_GET: + case EXPR_MEMBER_SET: case EXPR_NAMED_ARGUMENT: case EXPR_NOP: case EXPR_OPERATOR_CHARS: @@ -694,6 +695,7 @@ static bool expr_may_ref(Expr *expr) case EXPR_DEFAULT_ARG: case EXPR_TYPECALL: case EXPR_MEMBER_GET: + case EXPR_MEMBER_SET: case EXPR_EXT_TRUNC: case EXPR_PTR_ACCESS: case EXPR_VECTOR_TO_ARRAY: @@ -3188,21 +3190,14 @@ INLINE bool sema_call_may_not_have_attributes(SemaContext *context, Expr *expr) return true; } -static inline bool sema_call_analyse_member_get(SemaContext *context, Expr *expr) +INLINE bool sema_analyse_member_get_set_common(SemaContext *context, Decl *decl, Expr *inner, bool *is_bitrstruct) { - if (vec_size(expr->call_expr.arguments) != 1) - { - RETURN_SEMA_ERROR(expr, "Expected a single argument to '.get'."); - } - if (!sema_call_may_not_have_attributes(context, expr)) return false; - Expr *get = exprptr(expr->call_expr.function); - Expr *inner = expr->call_expr.arguments[0]; if (!sema_analyse_expr(context, inner)) return false; - Decl *decl = get->member_get_expr; Type *type = type_flatten(inner->type); - if (type->type_kind != TYPE_STRUCT && type->type_kind != TYPE_UNION) + bool type_is_bitstruct = type->type_kind == TYPE_BITSTRUCT; + if (!type_is_bitstruct && type->type_kind != TYPE_STRUCT && type->type_kind != TYPE_UNION) { - RETURN_SEMA_ERROR(inner, "This value does not match the member."); + RETURN_SEMA_ERROR(inner, "The member does not belong to the type %s.", type_quoted_error_string(inner->type)); } Decl **members = type->decl->strukt.members; ArrayIndex index = -1; @@ -3216,9 +3211,47 @@ static inline bool sema_call_analyse_member_get(SemaContext *context, Expr *expr } if (index == -1) { - RETURN_SEMA_ERROR(inner, "This value does not match the member."); + RETURN_SEMA_ERROR(inner, "The member does not belong to the type %s.", type_quoted_error_string(inner->type)); } - expr->expr_kind = EXPR_ACCESS_RESOLVED; + *is_bitrstruct = type_is_bitstruct; + return true; +} + +static inline bool sema_call_analyse_member_set(SemaContext *context, Expr *expr) +{ + if (vec_size(expr->call_expr.arguments) != 2) + { + RETURN_SEMA_ERROR(expr, "Expected two arguments to '.set'."); + } + if (!sema_call_may_not_have_attributes(context, expr)) return false; + Expr *get = exprptr(expr->call_expr.function); + Decl *decl = get->member_get_expr; + Expr *inner = expr->call_expr.arguments[0]; + bool is_bitstruct; + if (!sema_analyse_member_get_set_common(context, decl, inner, &is_bitstruct)) return false; + Expr *arg = expr->call_expr.arguments[1]; + Expr *access = expr_new_expr(is_bitstruct ? EXPR_BITACCESS : EXPR_ACCESS_RESOLVED, expr); + access->access_resolved_expr = (ExprResolvedAccess) { .parent = inner, .ref = decl }; + access->type = decl->type; + access->resolve_status = RESOLVE_DONE; + expr->expr_kind = EXPR_BINARY; + expr->binary_expr = (ExprBinary) { .left = exprid(access), .right = exprid(arg), .operator = BINARYOP_ASSIGN }; + return sema_expr_analyse_binary(context, NULL, expr, NULL); +} + +static inline bool sema_call_analyse_member_get(SemaContext *context, Expr *expr) +{ + if (vec_size(expr->call_expr.arguments) != 1) + { + RETURN_SEMA_ERROR(expr, "Expected a single argument to '.get'."); + } + if (!sema_call_may_not_have_attributes(context, expr)) return false; + Expr *get = exprptr(expr->call_expr.function); + Decl *decl = get->member_get_expr; + Expr *inner = expr->call_expr.arguments[0]; + bool is_bitstruct; + if (!sema_analyse_member_get_set_common(context, decl, inner, &is_bitstruct)) return false; + expr->expr_kind = is_bitstruct ? EXPR_BITACCESS : EXPR_ACCESS_RESOLVED; expr->access_resolved_expr = (ExprResolvedAccess) { .parent = inner, .ref = decl }; expr->type = decl->type; return true; @@ -3228,19 +3261,17 @@ static inline bool sema_expr_analyse_call(SemaContext *context, Expr *expr, bool if (no_match_ref) *no_match_ref = true; Expr *func_expr = exprptr(expr->call_expr.function); if (!sema_analyse_expr_value(context, func_expr)) return false; - if (func_expr->expr_kind == EXPR_MACRO_BODY_EXPANSION) - { - return sema_call_analyse_body_expansion(context, expr); - } - if (func_expr->expr_kind == EXPR_MEMBER_GET) - { - return sema_call_analyse_member_get(context, expr); - } bool optional = func_expr->type && IS_OPTIONAL(func_expr); Decl *decl; Expr *struct_var = NULL; switch (func_expr->expr_kind) { + case EXPR_MACRO_BODY_EXPANSION: + return sema_call_analyse_body_expansion(context, expr); + case EXPR_MEMBER_GET: + return sema_call_analyse_member_get(context, expr); + case EXPR_MEMBER_SET: + return sema_call_analyse_member_set(context, expr); case EXPR_TYPECALL: return sema_expr_analyse_typecall(context, expr); case EXPR_BUILTIN: @@ -4548,6 +4579,11 @@ static inline bool sema_expr_analyse_member_access(SemaContext *context, Expr *e expr->expr_kind = EXPR_TYPECALL; expr->type_call_expr = (ExprTypeCall) { .type = decl, .property = type_property }; return true; + case TYPE_PROPERTY_SET: + expr->expr_kind = EXPR_MEMBER_SET; + expr->member_get_expr = decl; + expr->type = type_void; + return true; case TYPE_PROPERTY_GET: expr->expr_kind = EXPR_MEMBER_GET; expr->member_get_expr = decl; @@ -5082,6 +5118,7 @@ static bool sema_expr_rewrite_to_typeid_property(SemaContext *context, Expr *exp case TYPE_PROPERTY_EXTNAMEOF: case TYPE_PROPERTY_FROM_ORDINAL: case TYPE_PROPERTY_GET: + case TYPE_PROPERTY_SET: case TYPE_PROPERTY_HAS_TAGOF: case TYPE_PROPERTY_INF: case TYPE_PROPERTY_IS_EQ: @@ -5235,6 +5272,7 @@ static bool sema_type_property_is_valid_for_type(Type *original_type, TypeProper case TYPE_PROPERTY_NONE: return false; case TYPE_PROPERTY_GET: + case TYPE_PROPERTY_SET: return type == type_member; case TYPE_PROPERTY_INF: case TYPE_PROPERTY_NAN: @@ -5390,6 +5428,7 @@ static bool sema_expr_rewrite_to_type_property(SemaContext *context, Expr *expr, expr->resolve_status = RESOLVE_DONE; return true; case TYPE_PROPERTY_GET: + case TYPE_PROPERTY_SET: UNREACHABLE case TYPE_PROPERTY_MEMBERSOF: { @@ -10093,6 +10132,7 @@ static inline bool sema_expr_analyse_ct_defined(SemaContext *context, Expr *expr case EXPR_TYPEID_INFO: case EXPR_TYPECALL: case EXPR_MEMBER_GET: + case EXPR_MEMBER_SET: case EXPR_SPLAT: case EXPR_EXT_TRUNC: case EXPR_INT_TO_BOOL: @@ -10445,6 +10485,7 @@ static inline bool sema_analyse_expr_dispatch(SemaContext *context, Expr *expr, case EXPR_MACRO_BODY: case EXPR_MACRO_BODY_EXPANSION: case EXPR_MEMBER_GET: + case EXPR_MEMBER_SET: case EXPR_NAMED_ARGUMENT: case EXPR_NOP: case EXPR_OPERATOR_CHARS: @@ -10744,8 +10785,10 @@ static inline bool sema_cast_rvalue(SemaContext *context, Expr *expr, bool mutat if (!expr_ok(expr)) return false; switch (expr->expr_kind) { + case EXPR_MEMBER_SET: + RETURN_SEMA_ERROR(expr, "Expected two parameters to 'set', e.g. '$member.set(v, new_value)'."); case EXPR_MEMBER_GET: - RETURN_SEMA_ERROR(expr, "Expected a parameter to 'get', e.g. '$member.get(value)'."); + RETURN_SEMA_ERROR(expr, "Expected a parameter to 'get', e.g. '$member.get(v)'."); case EXPR_MACRO_BODY_EXPANSION: if (!expr->body_expansion_expr.first_stmt) { @@ -10993,6 +11036,7 @@ IDENT_CHECK:; case EXPR_MAKE_ANY: case EXPR_MAKE_SLICE: case EXPR_MEMBER_GET: + case EXPR_MEMBER_SET: case EXPR_NAMED_ARGUMENT: case EXPR_NOP: case EXPR_OPERATOR_CHARS: diff --git a/src/compiler/sema_liveness.c b/src/compiler/sema_liveness.c index 93cdc13c1..53da02c9d 100644 --- a/src/compiler/sema_liveness.c +++ b/src/compiler/sema_liveness.c @@ -260,6 +260,7 @@ RETRY: case EXPR_SUBSCRIPT_ASSIGN: case EXPR_OPERATOR_CHARS: case EXPR_MEMBER_GET: + case EXPR_MEMBER_SET: case EXPR_NAMED_ARGUMENT: case UNRESOLVED_EXPRS: UNREACHABLE diff --git a/src/compiler/sema_stmts.c b/src/compiler/sema_stmts.c index a31fa48e5..617da0b32 100644 --- a/src/compiler/sema_stmts.c +++ b/src/compiler/sema_stmts.c @@ -762,6 +762,7 @@ static inline bool sema_expr_valid_try_expression(Expr *expr) case EXPR_LAST_FAULT: case EXPR_TYPECALL: case EXPR_MEMBER_GET: + case EXPR_MEMBER_SET: case EXPR_SPLAT: case EXPR_MAKE_ANY: case EXPR_DISCARD: diff --git a/src/compiler/symtab.c b/src/compiler/symtab.c index 9603a0e06..a696a426b 100644 --- a/src/compiler/symtab.c +++ b/src/compiler/symtab.c @@ -184,6 +184,7 @@ void symtab_init(uint32_t capacity) type_property_list[TYPE_PROPERTY_PARENTOF] = KW_DEF("parentof"); type_property_list[TYPE_PROPERTY_QNAMEOF] = KW_DEF("qnameof"); type_property_list[TYPE_PROPERTY_RETURNS] = KW_DEF("returns"); + type_property_list[TYPE_PROPERTY_SET] = KW_DEF("set"); type_property_list[TYPE_PROPERTY_SIZEOF] = KW_DEF("sizeof"); type_property_list[TYPE_PROPERTY_TAGOF] = KW_DEF("tagof"); type_property_list[TYPE_PROPERTY_HAS_TAGOF] = KW_DEF("has_tagof"); diff --git a/test/test_suite/bitstruct/bitstruct_with_get_set.c3t b/test/test_suite/bitstruct/bitstruct_with_get_set.c3t new file mode 100644 index 000000000..3553550e9 --- /dev/null +++ b/test/test_suite/bitstruct/bitstruct_with_get_set.c3t @@ -0,0 +1,232 @@ +// #target: macos-x64 +module test; +import std; +bitstruct Foo (Printable) : long +{ + int a : 2..4; + uint b: 5..10; +} +fn usz? Foo.to_format(&self, Formatter *f) @dynamic => io::struct_to_format(*self, f, false); + +fn int main() +{ + Foo d = { 1, 11 }; + Foo.membersof[0].set(d, 3); + return 0; +} + +/* #expect: test.ll + +define i64 @test.Foo.to_format(ptr %0, ptr %1, ptr %2) #0 { +entry: + %reterr = alloca i64, align 8 + %value = alloca i64, align 8 + %total = alloca i64, align 8 + %error_var = alloca i64, align 8 + %retparam = alloca i64, align 8 + %error_var1 = alloca i64, align 8 + %varargslots = alloca [1 x %any], align 16 + %taddr = alloca %"char[]", align 8 + %retparam2 = alloca i64, align 8 + %error_var8 = alloca i64, align 8 + %varargslots9 = alloca [1 x %any], align 16 + %taddr10 = alloca i32, align 4 + %retparam11 = alloca i64, align 8 + %error_var18 = alloca i64, align 8 + %retparam19 = alloca i64, align 8 + %error_var26 = alloca i64, align 8 + %varargslots27 = alloca [1 x %any], align 16 + %taddr28 = alloca %"char[]", align 8 + %retparam29 = alloca i64, align 8 + %error_var36 = alloca i64, align 8 + %varargslots37 = alloca [1 x %any], align 16 + %taddr39 = alloca i32, align 4 + %retparam40 = alloca i64, align 8 + %retparam47 = alloca i64, align 8 + %3 = load i64, ptr %1, align 8 + store i64 %3, ptr %value, align 8 + %4 = call i64 @std.io.Formatter.print(ptr %retparam, ptr %2, ptr @.str, i64 2) + %not_err = icmp eq i64 %4, 0 + %5 = call i1 @llvm.expect.i1(i1 %not_err, i1 true) + br i1 %5, label %after_check, label %assign_optional + +assign_optional: ; preds = %entry + store i64 %4, ptr %error_var, align 8 + br label %guard_block + +after_check: ; preds = %entry + br label %noerr_block + +guard_block: ; preds = %assign_optional + %6 = load i64, ptr %error_var, align 8 + store i64 %6, ptr %reterr, align 8 + br label %err_retblock + +noerr_block: ; preds = %after_check + %7 = load i64, ptr %retparam, align 8 + store i64 %7, ptr %total, align 8 + %8 = load i64, ptr %total, align 8 + store %"char[]" { ptr @.str.2, i64 1 }, ptr %taddr, align 8 + %9 = insertvalue %any undef, ptr %taddr, 0 + %10 = insertvalue %any %9, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + store %any %10, ptr %varargslots, align 16 + %11 = call i64 @std.io.Formatter.printf(ptr %retparam2, ptr %2, ptr @.str.1, i64 4, ptr %varargslots, i64 1) + %not_err3 = icmp eq i64 %11, 0 + %12 = call i1 @llvm.expect.i1(i1 %not_err3, i1 true) + br i1 %12, label %after_check5, label %assign_optional4 + +assign_optional4: ; preds = %noerr_block + store i64 %11, ptr %error_var1, align 8 + br label %guard_block6 + +after_check5: ; preds = %noerr_block + br label %noerr_block7 + +guard_block6: ; preds = %assign_optional4 + %13 = load i64, ptr %error_var1, align 8 + store i64 %13, ptr %reterr, align 8 + br label %err_retblock + +noerr_block7: ; preds = %after_check5 + %14 = load i64, ptr %retparam2, align 8 + %add = add i64 %8, %14 + store i64 %add, ptr %total, align 8 + %15 = load i64, ptr %total, align 8 + %16 = load i64, ptr %value, align 8 + %shl = shl i64 %16, 59 + %ashr = ashr i64 %shl, 61 + %trunc = trunc i64 %ashr to i32 + store i32 %trunc, ptr %taddr10, align 4 + %17 = insertvalue %any undef, ptr %taddr10, 0 + %18 = insertvalue %any %17, i64 ptrtoint (ptr @"$ct.int" to i64), 1 + store %any %18, ptr %varargslots9, align 16 + %19 = call i64 @std.io.Formatter.printf(ptr %retparam11, ptr %2, ptr @.str.3, i64 2, ptr %varargslots9, i64 1) + %not_err12 = icmp eq i64 %19, 0 + %20 = call i1 @llvm.expect.i1(i1 %not_err12, i1 true) + br i1 %20, label %after_check14, label %assign_optional13 + +assign_optional13: ; preds = %noerr_block7 + store i64 %19, ptr %error_var8, align 8 + br label %guard_block15 + +after_check14: ; preds = %noerr_block7 + br label %noerr_block16 + +guard_block15: ; preds = %assign_optional13 + %21 = load i64, ptr %error_var8, align 8 + store i64 %21, ptr %reterr, align 8 + br label %err_retblock + +noerr_block16: ; preds = %after_check14 + %22 = load i64, ptr %retparam11, align 8 + %add17 = add i64 %15, %22 + store i64 %add17, ptr %total, align 8 + %23 = load i64, ptr %total, align 8 + %24 = call i64 @std.io.Formatter.print(ptr %retparam19, ptr %2, ptr @.str.4, i64 2) + %not_err20 = icmp eq i64 %24, 0 + %25 = call i1 @llvm.expect.i1(i1 %not_err20, i1 true) + br i1 %25, label %after_check22, label %assign_optional21 + +assign_optional21: ; preds = %noerr_block16 + store i64 %24, ptr %error_var18, align 8 + br label %guard_block23 + +after_check22: ; preds = %noerr_block16 + br label %noerr_block24 + +guard_block23: ; preds = %assign_optional21 + %26 = load i64, ptr %error_var18, align 8 + store i64 %26, ptr %reterr, align 8 + br label %err_retblock + +noerr_block24: ; preds = %after_check22 + %27 = load i64, ptr %retparam19, align 8 + %add25 = add i64 %23, %27 + store i64 %add25, ptr %total, align 8 + %28 = load i64, ptr %total, align 8 + store %"char[]" { ptr @.str.6, i64 1 }, ptr %taddr28, align 8 + %29 = insertvalue %any undef, ptr %taddr28, 0 + %30 = insertvalue %any %29, i64 ptrtoint (ptr @"$ct.String" to i64), 1 + store %any %30, ptr %varargslots27, align 16 + %31 = call i64 @std.io.Formatter.printf(ptr %retparam29, ptr %2, ptr @.str.5, i64 4, ptr %varargslots27, i64 1) + %not_err30 = icmp eq i64 %31, 0 + %32 = call i1 @llvm.expect.i1(i1 %not_err30, i1 true) + br i1 %32, label %after_check32, label %assign_optional31 + +assign_optional31: ; preds = %noerr_block24 + store i64 %31, ptr %error_var26, align 8 + br label %guard_block33 + +after_check32: ; preds = %noerr_block24 + br label %noerr_block34 + +guard_block33: ; preds = %assign_optional31 + %33 = load i64, ptr %error_var26, align 8 + store i64 %33, ptr %reterr, align 8 + br label %err_retblock + +noerr_block34: ; preds = %after_check32 + %34 = load i64, ptr %retparam29, align 8 + %add35 = add i64 %28, %34 + store i64 %add35, ptr %total, align 8 + %35 = load i64, ptr %total, align 8 + %36 = load i64, ptr %value, align 8 + %lshrl = lshr i64 %36, 5 + %37 = and i64 63, %lshrl + %trunc38 = trunc i64 %37 to i32 + store i32 %trunc38, ptr %taddr39, align 4 + %38 = insertvalue %any undef, ptr %taddr39, 0 + %39 = insertvalue %any %38, i64 ptrtoint (ptr @"$ct.uint" to i64), 1 + store %any %39, ptr %varargslots37, align 16 + %40 = call i64 @std.io.Formatter.printf(ptr %retparam40, ptr %2, ptr @.str.7, i64 2, ptr %varargslots37, i64 1) + %not_err41 = icmp eq i64 %40, 0 + %41 = call i1 @llvm.expect.i1(i1 %not_err41, i1 true) + br i1 %41, label %after_check43, label %assign_optional42 + +assign_optional42: ; preds = %noerr_block34 + store i64 %40, ptr %error_var36, align 8 + br label %guard_block44 + +after_check43: ; preds = %noerr_block34 + br label %noerr_block45 + +guard_block44: ; preds = %assign_optional42 + %42 = load i64, ptr %error_var36, align 8 + store i64 %42, ptr %reterr, align 8 + br label %err_retblock + +noerr_block45: ; preds = %after_check43 + %43 = load i64, ptr %retparam40, align 8 + %add46 = add i64 %35, %43 + store i64 %add46, ptr %total, align 8 + %44 = load i64, ptr %total, align 8 + %45 = call i64 @std.io.Formatter.print(ptr %retparam47, ptr %2, ptr @.str.8, i64 2) + %not_err48 = icmp eq i64 %45, 0 + %46 = call i1 @llvm.expect.i1(i1 %not_err48, i1 true) + br i1 %46, label %after_check50, label %assign_optional49 + +assign_optional49: ; preds = %noerr_block45 + store i64 %45, ptr %reterr, align 8 + br label %err_retblock + +after_check50: ; preds = %noerr_block45 + %47 = load i64, ptr %retparam47, align 8 + %add51 = add i64 %44, %47 + store i64 %add51, ptr %0, align 8 + ret i64 0 + +err_retblock: ; preds = %assign_optional49, %guard_block44, %guard_block33, %guard_block23, %guard_block15, %guard_block6, %guard_block + %48 = load i64, ptr %reterr, align 8 + ret i64 %48 +} + +define i32 @main() #0 { +entry: + %d = alloca i64, align 8 + store i64 356, ptr %d, align 8 + %0 = load i64, ptr %d, align 8 + %1 = and i64 %0, -29 + %2 = or i64 %1, 12 + store i64 %2, ptr %d, align 8 + ret i32 0 +} \ No newline at end of file