From 0946581412e0bb874183dbf7906642dd931b0850 Mon Sep 17 00:00:00 2001 From: David Date: Sat, 19 Sep 2026 00:47:11 +0200 Subject: [PATCH 01/12] aarch64: transport binary128 values through AAPCS64 Refs #72. --- docs/agents/frontend/wide-floats-assembly.md | 22 +++- src/buster/lib/compiler/codegen/codegen.c | 12 +- .../lib/compiler/codegen/machine_aarch64.c | 47 +++++-- src/buster/lib/compiler/frontend/c/c_gen.c | 67 +++++++++- src/buster/lib/compiler/ir/ir.c | 20 ++- .../tests/compiler/driver/driver_test.c | 120 ++++++++++++++++++ src/buster/tests/compiler/frontend/c/c_test.c | 39 ++++-- src/buster/tests/compiler/ir/ir_test.c | 74 ++++++++--- tests/basic_c_aarch64_binary128_transport.c | 101 +++++++++++++++ 9 files changed, 447 insertions(+), 55 deletions(-) create mode 100644 tests/basic_c_aarch64_binary128_transport.c diff --git a/docs/agents/frontend/wide-floats-assembly.md b/docs/agents/frontend/wide-floats-assembly.md index c4da34395..9d6f9e7d7 100644 --- a/docs/agents/frontend/wide-floats-assembly.md +++ b/docs/agents/frontend/wide-floats-assembly.md @@ -8,9 +8,10 @@ x87 and byte-eight bit 63 for binary128. It does not widen or narrow a value before observing the sign. This preserves signaling NaNs, signed zero and floating exception state. `basic_c_signbit_images.c` and its independent host observer cover those images across the native target/mode/frontend/PIC matrix. -AArch64 binary128 widening uses ordinary MIR frame images; see the machine -guide for its exact conversion and native floating-environment checks. This -does not claim binary128 scalar ABI or arithmetic support. +AArch64 binary128 widening and scalar transport use ordinary MIR frame +images; see the machine guide for their exact conversion and ABI-boundary +checks. Arithmetic, comparison, truth conversion and general narrowing remain +separately unsupported. The host FENV fixture in `tests/host_aarch64_float_to_f128.c` uses ordinary GNU inline asm for `mrs`/`msr` reads and writes of `fpsr`/`fpcr`; the baseline AArch64 inline-assembly vocabulary selects these checked system-register rows @@ -81,7 +82,7 @@ Read the matching sections; [the frontend index](../frontend.md) lists these not static BF16 initializers use this path. An explicit cast to `double` still deliberately rounds to binary64. The binary128 rational converter uses a two-limb quotient, not a host extended type or a new numeric dependency. - This does not add native BF16 arithmetic/ABI or binary128 scalar ABI support. + This does not add native BF16 arithmetic/ABI or binary128 arithmetic support. `c_parse_bfloat16_builtin` carries the LLVM18 BF16/AVX-NE-CONVERT signatures and the select/FMA dependencies used by the pristine resource headers. @@ -94,6 +95,19 @@ Read the matching sections; [the frontend index](../frontend.md) lists these not native intrinsic lowering. `c_test_bfloat16_semantic_acceptance` covers source-format rounding on six layouts in both frontend forms, mixed-format identity, positive/negative builtin operands, and deep nested calls. +- **Base AAPCS64 `long double` is IEEE binary128 and supports scalar + transport.** A scalar argument or result is one complete sixteen-byte image + in a Q register; after V0-V7 are exhausted, named arguments occupy their + sixteen-byte-aligned stack slot. Canonical and MIR backends keep the value + slot-backed internally and bridge only at the ABI edges, so assignment, + literal return, direct/indirect calls and mixed Clang/Buster linkage preserve + every payload bit, including negative zero. `c_ir_signature_type_supported` + admits only the exact scalar shape proven by `ir_type_abi_value`; aggregates, + variadic wide parameters, arithmetic, comparisons, truth conversion and + general conversions remain behind their existing structured rejections. + `basic_c_aarch64_binary128_transport.c` covers Q0/Q1, ninth-argument stack + spill and both mixed-compiler directions on native Linux AArch64, with strict + no-fallback compilation across the AAPCS64 target/mode/frontend/PIC matrix. - **`long double` is 80-bit x87 on System V x86-64, and it is memory-only.** Transport, the four arithmetic operators, negation, the six comparisons, truth conversion, and the conversions to and from the narrower floats and diff --git a/src/buster/lib/compiler/codegen/codegen.c b/src/buster/lib/compiler/codegen/codegen.c index 8cbc40ce3..034f0a8a0 100644 --- a/src/buster/lib/compiler/codegen/codegen.c +++ b/src/buster/lib/compiler/codegen/codegen.c @@ -20449,7 +20449,8 @@ BUSTER_GLOBAL_LOCAL CodegenModule codegen_generate_canonical_module_attempt(Aren } if (argument_type->kind == IR_TYPE_FLOAT && !aarch64_windows_variadic) { - if (!codegen_canonical_type_is_ieee_binary16(argument_type) && argument_type->bit_width != 32 && argument_type->bit_width != 64) + if (!codegen_canonical_type_is_ieee_binary16(argument_type) && argument_type->bit_width != 32 && + argument_type->bit_width != 64 && argument_type->bit_width != 128) { result.error = CODEGEN_ERROR_UNSUPPORTED_ABI; return result; @@ -22204,7 +22205,8 @@ BUSTER_GLOBAL_LOCAL CodegenModule codegen_generate_canonical_module_attempt(Aren { u8 float_register = argument_float_register[argument_index - 1]; if (float_register >= 8 || - (!codegen_canonical_type_is_ieee_binary16(argument_type) && argument_type->bit_width != 32 && argument_type->bit_width != 64)) + (!codegen_canonical_type_is_ieee_binary16(argument_type) && argument_type->bit_width != 32 && + argument_type->bit_width != 64 && argument_type->bit_width != 128)) { result.error = CODEGEN_ERROR_UNSUPPORTED_ABI; return result; @@ -22300,7 +22302,8 @@ BUSTER_GLOBAL_LOCAL CodegenModule codegen_generate_canonical_module_attempt(Aren } if (return_type && return_type->kind == IR_TYPE_FLOAT) { - if (!codegen_canonical_type_is_ieee_binary16(return_type) && return_type->bit_width != 32 && return_type->bit_width != 64) + if (!codegen_canonical_type_is_ieee_binary16(return_type) && return_type->bit_width != 32 && + return_type->bit_width != 64 && return_type->bit_width != 128) { result.error = CODEGEN_ERROR_UNSUPPORTED_ABI; return result; @@ -23393,7 +23396,8 @@ BUSTER_GLOBAL_LOCAL CodegenModule codegen_generate_canonical_module_attempt(Aren } else if (return_type && return_type->kind == IR_TYPE_FLOAT) { - if (!codegen_canonical_type_is_ieee_binary16(return_type) && return_type->bit_width != 32 && return_type->bit_width != 64) + if (!codegen_canonical_type_is_ieee_binary16(return_type) && return_type->bit_width != 32 && + return_type->bit_width != 64 && return_type->bit_width != 128) { result.error = CODEGEN_ERROR_UNSUPPORTED_ABI; return result; diff --git a/src/buster/lib/compiler/codegen/machine_aarch64.c b/src/buster/lib/compiler/codegen/machine_aarch64.c index d2b2188bf..05e9e42f8 100644 --- a/src/buster/lib/compiler/codegen/machine_aarch64.c +++ b/src/buster/lib/compiler/codegen/machine_aarch64.c @@ -302,6 +302,25 @@ BUSTER_GLOBAL_LOCAL bool machine_a64_value_shape(IrProgram* program, IrTypeId ty }; return true; } + if (type && type->layout.resolved && type->kind == IR_TYPE_FLOAT && type->bit_width == 128 && type->layout.size == 16 && + ir_abi_convention_for_target(target) == IR_ABI_CONVENTION_AAPCS64) + { + // Binary128 is an ordinary sixteen-byte Q-register image at AAPCS64 + // boundaries, but the machine IR keeps it in a complete stack slot. + // Aggregate-like placement also preserves the full aligned stack image + // after the eight vector argument registers are exhausted. + *shape = (MachineA64ValueShape){ + .part_is_float = {1}, + .part_sizes = {16}, + .part_count = 1, + .byte_size = 16, + .exact_byte_size = 16, + .aggregate = true, + .vector = true, + .stack_aligned = true, + }; + return true; + } // A bare 128-bit integer is the AAPCS64 even-aligned X pair — the same // two INTEGER parts a sixteen-byte wrapped pair builds — carried by the // aggregate machinery over the value's 16-byte slot, exactly like the @@ -978,19 +997,24 @@ BUSTER_GLOBAL_LOCAL bool machine_a64_select_constant(MachineA64Selector* selecto machine_a64_define(selector, result_register, row); selected = true; } - else if (instruction->opcode == IR_OPCODE_CONSTANT_INTEGER && instruction->result.value != IR_ID_UNDERLYING_INVALID && - instruction->result.value < function->value_count && selector->value_stack_slots[instruction->result.value] != UINT32_MAX) + else if ((instruction->opcode == IR_OPCODE_CONSTANT_INTEGER || instruction->opcode == IR_OPCODE_CONSTANT_FLOAT) && + instruction->result.value != IR_ID_UNDERLYING_INVALID && instruction->result.value < function->value_count && + selector->value_stack_slots[instruction->result.value] != UINT32_MAX) { - // A 128-bit integer constant is slot-backed like every i128 value. - // The second eightbyte is the canonical emitters' selection: an - // explicit second immediate when the frontend recorded one, - // otherwise the negated low half's sign fill. + // Wide scalar constants are slot-backed like every i128/f128 value. + // Integer constants retain their signed-immediate convention; a + // binary128 floating constant already carries its exact two target + // image limbs in canonical low/high order. IrType* constant_type = ir_type_from_id(&program->types, instruction->canonical_type); - if (constant_type && constant_type->kind == IR_TYPE_INTEGER && constant_type->bit_width == 128) + bool integer128 = constant_type && constant_type->kind == IR_TYPE_INTEGER && constant_type->bit_width == 128; + bool float128 = constant_type && constant_type->kind == IR_TYPE_FLOAT && constant_type->bit_width == 128 && + instruction->immediate_count == 2; + if (integer128 || float128) { u32 result_slot = selector->value_stack_slots[instruction->result.value]; - u64 low = instruction->immediate_is_negative ? 0 - instruction->immediates[0] : instruction->immediates[0]; - u64 high = instruction->immediate_count > 1 ? instruction->immediates[1] : instruction->immediate_is_negative ? UINT64_MAX : 0; + u64 low = integer128 && instruction->immediate_is_negative ? 0 - instruction->immediates[0] : instruction->immediates[0]; + u64 high = float128 || instruction->immediate_count > 1 ? instruction->immediates[1] + : instruction->immediate_is_negative ? UINT64_MAX : 0; u64 halves[2] = {low, high}; for (u32 half_index = 0; half_index < 2; half_index += 1) { @@ -6482,7 +6506,7 @@ MachineSelectResult machine_select_canonical_function_aarch64(Arena* arena, IrPr instruction->opcode == IR_OPCODE_ATOMIC_COMPARE_EXCHANGE || instruction->opcode == IR_OPCODE_CALL || instruction->opcode == IR_OPCODE_AGGREGATE || instruction->opcode == IR_OPCODE_ARRAY || instruction->opcode == IR_OPCODE_VA_ARG || instruction->opcode == IR_OPCODE_CAST || - instruction->opcode == IR_OPCODE_CONSTANT_INTEGER || + instruction->opcode == IR_OPCODE_CONSTANT_INTEGER || instruction->opcode == IR_OPCODE_CONSTANT_FLOAT || ((instruction->opcode == IR_OPCODE_BINARY || instruction->opcode == IR_OPCODE_UNARY) && value_type && (value_type->kind == IR_TYPE_VECTOR || (value_type->kind == IR_TYPE_INTEGER && value_type->bit_width == 128)))) && value_type && value_type->layout.resolved && value_type->layout.size <= UINT32_MAX - 7 && @@ -6503,8 +6527,9 @@ MachineSelectResult machine_select_canonical_function_aarch64(Arena* arena, IrPr { slot_size = 16; } + bool wide_float = value_type->kind == IR_TYPE_FLOAT && value_type->bit_width == 128; selector.value_stack_slots[instruction->result.value] = machine_a64_append_slot( - &selector, slot_size, value_type->kind == IR_TYPE_VECTOR ? 16u : 8u); + &selector, slot_size, value_type->kind == IR_TYPE_VECTOR || wide_float ? 16u : 8u); } } } diff --git a/src/buster/lib/compiler/frontend/c/c_gen.c b/src/buster/lib/compiler/frontend/c/c_gen.c index cec94796b..9a3ff0999 100644 --- a/src/buster/lib/compiler/frontend/c/c_gen.c +++ b/src/buster/lib/compiler/frontend/c/c_gen.c @@ -1221,6 +1221,18 @@ BUSTER_C_INTERNAL bool c_ir_target_supports_f80(Target target) layout.long_double_type.alignment == 16; } +// Base AAPCS64 long double is IEEE binary128. This predicate deliberately +// admits only the exact scalar representation whose shared ABI classification +// is one sixteen-byte vector-file part; arithmetic and conversions remain +// independently gated by their lowering paths. +BUSTER_C_INTERNAL bool c_ir_target_supports_f128_transport(Target target) +{ + TargetDataLayout layout = target_data_layout(target); + return target.cpu_arch == CPU_ARCH_AARCH64 && ir_abi_convention_for_target(target) == IR_ABI_CONVENTION_AAPCS64 && + layout.endianness == TARGET_ENDIAN_LITTLE && layout.long_double_type.bit_width == 128 && + layout.long_double_type.size == 16 && layout.long_double_type.alignment == 16; +} + // A wide value is safe for the canonical x86 backend only when the existing // SysV classifier proves the complete value is the two-part x87 return shape. // This intentionally asks the classifier rather than walking fields here: @@ -1304,7 +1316,14 @@ BUSTER_C_INTERNAL bool c_ir_signature_type_supported(IrProgram* program, CIrWide IrAbiValue abi = ir_type_abi_value(program, type_id, convention, result_type ? IR_ABI_USE_RESULT : IR_ABI_USE_ARGUMENT); if (c_ir_type_contains_wide_float(program, wide_float_cache, type_id)) { - if (c_ir_type_is_f80_x87_shape(program, wide_float_cache, type_id, target)) + if (c_ir_target_supports_f128_transport(target) && type->kind == IR_TYPE_FLOAT && type->bit_width == 128 && !type->is_atomic) + { + if (abi.memory || abi.indirect || abi.part_count != 1 || abi.parts[0].abi_class != IR_ABI_CLASS_VECTOR || abi.parts[0].size != 16) + { + return false; + } + } + else if (c_ir_type_is_f80_x87_shape(program, wide_float_cache, type_id, target)) { // SysV passes both scalar f80 and ABI-proven wrappers by value in // a sixteen-byte stack slot. Results come back as the x87 pair. @@ -11066,6 +11085,28 @@ BUSTER_C_INTERNAL IrValueId c_ir_emit_f80_constant_bits(CIntegerIrBuilder* build return result; } +BUSTER_C_INTERNAL IrValueId c_ir_emit_f128_constant_bits(CIntegerIrBuilder* builder, IrSourceRange source, String8 literal, u64 low, u64 high) +{ + IrValueId result = IR_VALUE_ID_INVALID; + IrType* type = ir_type_from_id(&builder->program->types, builder->long_double_type); + if (type && c_ir_target_supports_f128_transport(builder->target) && type->kind == IR_TYPE_FLOAT && type->bit_width == 128 && + type->layout.size == 16 && type->layout.alignment == 16) + { + result = c_ir_add_result(builder, builder->long_double_type); + u64* immediate = arena_allocate(builder->arena, u64, 2); + immediate[0] = low; + immediate[1] = high; + IrInstruction instruction = c_ir_instruction_initialize(IR_OPCODE_CONSTANT_FLOAT, builder->long_double_type); + instruction.immediates = immediate; + instruction.immediate_count = 2; + instruction.result = result; + IrInstructionId id = c_ir_append_instruction(builder, instruction, source); + ir_instruction_extra_ensure(builder->arena, builder->function, id)->literal = literal; + builder->function->values[result.value].definition = id; + } + return result; +} + BUSTER_C_INTERNAL IrValueId c_ir_emit_float_spelling(CIntegerIrBuilder* builder, String8 spelling, IrSourceRange source) { char8 suffix = 0; @@ -11104,6 +11145,16 @@ BUSTER_C_INTERNAL IrValueId c_ir_emit_float_spelling(CIntegerIrBuilder* builder, } return c_ir_emit_f80_constant_bits(builder, source, spelling, significand, sign_exponent); } + if (type_value->bit_width == 128 && c_ir_target_supports_f128_transport(builder->target)) + { + CIrConstantValue constant = {0}; + IrValueId result = IR_VALUE_ID_INVALID; + if (c_ir_constant_float_literal(builder, spelling, &constant) && constant.kind == C_IR_CONSTANT_FLOAT) + { + result = c_ir_emit_f128_constant_bits(builder, source, spelling, constant.integer, constant.integer_high); + } + return result; + } if (type_value->bit_width > 64) { return IR_VALUE_ID_INVALID; @@ -22462,8 +22513,18 @@ BUSTER_C_INTERNAL bool c_ir_apply_operation(CIntegerIrBuilder* builder, CConditi IrInstruction* constant = builder->function->instructions + definition.value; if (constant->opcode == IR_OPCODE_CONSTANT_FLOAT && constant->immediate_count == 2 && constant->immediates) { - IrValueId negated = c_ir_emit_f80_constant_bits(builder, source, ir_instruction_extra(builder->function, definition).literal, - constant->immediates[0], (u16)(constant->immediates[1] ^ UINT64_C(0x8000))); + IrType* constant_type = ir_type_from_id(&builder->program->types, constant->canonical_type); + IrValueId negated = IR_VALUE_ID_INVALID; + if (constant_type && constant_type->bit_width == 80) + { + negated = c_ir_emit_f80_constant_bits(builder, source, ir_instruction_extra(builder->function, definition).literal, + constant->immediates[0], (u16)(constant->immediates[1] ^ UINT64_C(0x8000))); + } + else if (constant_type && constant_type->bit_width == 128) + { + negated = c_ir_emit_f128_constant_bits(builder, source, ir_instruction_extra(builder->function, definition).literal, + constant->immediates[0], constant->immediates[1] ^ UINT64_C(0x8000000000000000)); + } if (negated.value != IR_ID_UNDERLYING_INVALID) { *value_count = first; diff --git a/src/buster/lib/compiler/ir/ir.c b/src/buster/lib/compiler/ir/ir.c index 93629e3f2..101ce14d5 100644 --- a/src/buster/lib/compiler/ir/ir.c +++ b/src/buster/lib/compiler/ir/ir.c @@ -3473,7 +3473,19 @@ BUSTER_GLOBAL_LOCAL IrAbiValue ir_classify_abi_value(IrProgram* program, IrTypeI } return value; } - if (type->bit_width > 64) + if (convention == IR_ABI_CONVENTION_AAPCS64 && type->bit_width == 128 && size == 16) + { + // Base AAPCS64 carries IEEE binary128 directly in one + // Q register for arguments and results. Keep the whole + // sixteen-byte image in one vector-file ABI part so + // caller, callee and compiler-rt declarations agree. + value.part_count = 1; + value.parts[0] = (IrAbiPart){ + .abi_class = IR_ABI_CLASS_VECTOR, + .size = 16, + }; + } + else if (type->bit_width > 64) { value.part_count = 1; value.indirect = is_result; @@ -4606,6 +4618,12 @@ BUSTER_GLOBAL_LOCAL bool ir_canonical_float_constant_valid(IrType* type, IrInstr return type->layout.resolved && type->layout.size == 16 && type->layout.alignment == 16 && instruction->immediate_count == 2 && (instruction->immediates[1] & ~UINT64_C(0xffff)) == 0; } + if (type->bit_width == 128) + { + // IEEE binary128 is represented by its exact low/high target-image + // limbs. Unlike x87 there are no non-semantic ABI padding bytes. + return type->layout.resolved && type->layout.size == 16 && type->layout.alignment == 16 && instruction->immediate_count == 2; + } return type->bit_width == 16 ? type->layout.resolved && type->layout.size == 2 && type->layout.alignment >= 2 && !(type->layout.alignment & (type->layout.alignment - 1)) && instruction->immediate_count == 1 && diff --git a/src/buster/tests/compiler/driver/driver_test.c b/src/buster/tests/compiler/driver/driver_test.c index 9477090cb..f22970f22 100644 --- a/src/buster/tests/compiler/driver/driver_test.c +++ b/src/buster/tests/compiler/driver/driver_test.c @@ -3411,6 +3411,125 @@ BUSTER_GLOBAL_LOCAL UnitTestResult compiler_driver_test_aarch64_float_to_f128(Un return result; } +// AAPCS64 binary128 transport is a deliberately narrower contract than full +// scalar arithmetic. Keep every allocator/frontend/PIC cell strict, execute the +// native Linux image, and prove both mixed-compiler directions in one focused +// representative cell. +BUSTER_GLOBAL_LOCAL UnitTestResult compiler_driver_test_aarch64_binary128_transport(UnitTestArguments* arguments) +{ + UnitTestResult result = {0}; + String8 targets[] = {S8("aarch64-linux"), S8("aarch64-linux-android"), S8("aarch64-unknown-uefi")}; + String8 modes[] = {S8("-fregister-allocator=mir-stack"), S8("-fregister-allocator=fast"), S8("-fregister-allocator=quality")}; + String8 frontends[] = {S8("-fno-frontend-ssa"), S8("-ffrontend-ssa")}; + String8 positions[] = {S8("-fno-pic"), S8("-fPIC")}; +#if defined(BUSTER_HOST_C_COMPILER) && BUSTER_CPU_ARCH_AARCH64 && BUSTER_LINUX && !BUSTER_ANDROID + String8 host_objects[2]; + bool host_compiled[2]; + for (u32 direction = 0; direction < 2; direction += 1) + { + host_objects[direction] = buster_test_temporary_path(arguments->arena, + direction ? S8("buster-f128-transport-host-library") : S8("buster-f128-transport-host-client"), S8(".o")); + String8 command[12]; + u32 count = 0; + command[count++] = S8(BUSTER_HOST_C_COMPILER); + if (S8(BUSTER_HOST_C_COMPILER_ARG1).length) { command[count++] = S8(BUSTER_HOST_C_COMPILER_ARG1); } + command[count++] = S8("-O0"); + command[count++] = S8("-fno-inline"); + command[count++] = direction ? S8("-DBUSTER_F128_TRANSPORT_LIBRARY=1") : S8("-DBUSTER_F128_TRANSPORT_CLIENT=1"); + command[count++] = S8("-c"); + command[count++] = S8("tests/basic_c_aarch64_binary128_transport.c"); + command[count++] = S8("-o"); + command[count++] = host_objects[direction]; + ProcessSpawnResult spawned = os_process_spawn((SliceString8){.pointer = command, .length = count}, + (SliceString8){0}, (SliceString8){0}, (ProcessSpawnOptions){.use_process_environment = true}); + host_compiled[direction] = spawned.handle && os_process_wait_sync(arguments->arena, spawned).result == PROCESS_RESULT_SUCCESS; + BUSTER_TEST(arguments, host_compiled[direction]); + } +#endif + for (u32 target = 0; target < BUSTER_ARRAY_LENGTH(targets); target += 1) + { + for (u32 mode = 0; mode < BUSTER_ARRAY_LENGTH(modes); mode += 1) + { + for (u32 frontend = 0; frontend < BUSTER_ARRAY_LENGTH(frontends); frontend += 1) + { + for (u32 position = 0; position < BUSTER_ARRAY_LENGTH(positions); position += 1) + { + TemporalArena temporary = scratch_begin(&arguments->arena, 1); + String8 output = buster_test_temporary_path(temporary.arena, S8("buster-a64-f128-transport"), S8(".o")); + String8 command[] = {S8("-c"), S8("-g0"), S8("-target"), targets[target], modes[mode], frontends[frontend], positions[position], + S8("-fno-machine-fallback"), S8("-fverify-codegen"), S8("-o"), output, + S8("tests/basic_c_aarch64_binary128_transport.c")}; + CompilerDriverInvocation invocation = compiler_driver_parse_arguments( + temporary.arena, (SliceString8)BUSTER_ARRAY_TO_SLICE(command)); + invocation.reject_machine_fallback = true; + CompilerDriverResult compiled = compiler_driver_execute_invocation(temporary.arena, invocation); + String8 description = string_format(temporary.arena, S8("f128 transport {S8} {S8} {S8} {S8}: {S8}"), + targets[target], modes[mode], frontends[frontend], positions[position], compiled.diagnostic); + BUSTER_TEST_RAW(arguments, compiled.error == COMPILER_DRIVER_ERROR_NONE && compiled.has_object, description); + BUSTER_TEST_RAW(arguments, compiled.codegen_statistics.function_count == 6 && + compiled.codegen_statistics.fallback_function_count == 0, description); +#if BUSTER_CPU_ARCH_AARCH64 && BUSTER_LINUX && !BUSTER_ANDROID + if (target == 0 && compiled.error == COMPILER_DRIVER_ERROR_NONE) + { + String8 executable = buster_test_temporary_path(temporary.arena, S8("buster-a64-f128-transport-run"), S8(".elf")); + String8 native_command[] = {modes[mode], frontends[frontend], positions[position], S8("-fno-machine-fallback"), + S8("-fverify-codegen"), S8("-o"), executable, S8("tests/basic_c_aarch64_binary128_transport.c")}; + CompilerDriverInvocation native_invocation = compiler_driver_parse_arguments( + temporary.arena, (SliceString8)BUSTER_ARRAY_TO_SLICE(native_command)); + native_invocation.reject_machine_fallback = true; + CompilerDriverResult native = compiler_driver_execute_invocation(temporary.arena, native_invocation); + BUSTER_TEST_RAW(arguments, native.error == COMPILER_DRIVER_ERROR_NONE, native.diagnostic); + if (native.error == COMPILER_DRIVER_ERROR_NONE) + { + BUSTER_TEST(arguments, compiler_driver_test_process_success(temporary.arena, executable)); + } + } +#endif +#if defined(BUSTER_HOST_C_COMPILER) && BUSTER_CPU_ARCH_AARCH64 && BUSTER_LINUX && !BUSTER_ANDROID + if (target == 0 && mode == 0 && frontend == 1 && position == 0) + { + for (u32 direction = 0; direction < 2; direction += 1) + { + String8 mixed_object = buster_test_temporary_path(temporary.arena, S8("buster-f128-transport-mixed"), S8(".o")); + String8 mixed[] = {S8("-c"), S8("-g0"), modes[mode], frontends[frontend], positions[position], + S8("-fno-machine-fallback"), S8("-fverify-codegen"), + direction ? S8("-DBUSTER_F128_TRANSPORT_CLIENT=1") : S8("-DBUSTER_F128_TRANSPORT_LIBRARY=1"), + S8("tests/basic_c_aarch64_binary128_transport.c"), S8("-o"), mixed_object}; + CompilerDriverInvocation mixed_invocation = compiler_driver_parse_arguments( + temporary.arena, (SliceString8)BUSTER_ARRAY_TO_SLICE(mixed)); + mixed_invocation.reject_machine_fallback = true; + CompilerDriverResult mixed_result = compiler_driver_execute_invocation(temporary.arena, mixed_invocation); + BUSTER_TEST_RAW(arguments, mixed_result.error == COMPILER_DRIVER_ERROR_NONE && mixed_result.has_object && + mixed_result.codegen_statistics.fallback_function_count == 0, mixed_result.diagnostic); + if (mixed_result.error == COMPILER_DRIVER_ERROR_NONE && host_compiled[direction]) + { + String8 executable = buster_test_temporary_path(temporary.arena, S8("buster-f128-transport-mixed-run"), S8(".elf")); + String8 link[10]; + u32 count = 0; + link[count++] = S8(BUSTER_HOST_C_COMPILER); + if (S8(BUSTER_HOST_C_COMPILER_ARG1).length) { link[count++] = S8(BUSTER_HOST_C_COMPILER_ARG1); } + link[count++] = S8("-no-pie"); + link[count++] = mixed_object; + link[count++] = host_objects[direction]; + link[count++] = S8("-o"); + link[count++] = executable; + ProcessSpawnResult spawned = os_process_spawn((SliceString8){.pointer = link, .length = count}, + (SliceString8){0}, (SliceString8){0}, (ProcessSpawnOptions){.use_process_environment = true}); + bool linked = spawned.handle && os_process_wait_sync(temporary.arena, spawned).result == PROCESS_RESULT_SUCCESS; + BUSTER_TEST(arguments, linked); + if (linked) { BUSTER_TEST(arguments, compiler_driver_test_process_success(temporary.arena, executable)); } + } + } + } +#endif + scratch_end(temporary); + } + } + } + } + return result; +} + // Keep the complete conversion fixture strict on all desktop AArch64 targets. // Foreign object success is not execution evidence; native hosts run it too. BUSTER_GLOBAL_LOCAL UnitTestResult compiler_driver_test_aarch64_float_to_i128(UnitTestArguments* arguments) @@ -7088,6 +7207,7 @@ UnitTestResult compiler_driver_tests(UnitTestArguments* arguments) BUSTER_TEST_FIXTURE(arguments, compiler_driver_test_native_i128_divide); BUSTER_TEST_FIXTURE(arguments, compiler_driver_test_i128_block_parameters); BUSTER_TEST_FIXTURE(arguments, compiler_driver_test_aarch64_float_to_f128); + BUSTER_TEST_FIXTURE(arguments, compiler_driver_test_aarch64_binary128_transport); BUSTER_TEST_FIXTURE(arguments, compiler_driver_test_aarch64_i128_to_float); BUSTER_TEST_FIXTURE(arguments, compiler_driver_test_x64_i128_float); BUSTER_TEST_FIXTURE(arguments, compiler_driver_test_wasm_integers); diff --git a/src/buster/tests/compiler/frontend/c/c_test.c b/src/buster/tests/compiler/frontend/c/c_test.c index 6355e5ef0..b84eef063 100644 --- a/src/buster/tests/compiler/frontend/c/c_test.c +++ b/src/buster/tests/compiler/frontend/c/c_test.c @@ -14181,6 +14181,14 @@ BUSTER_GLOBAL_LOCAL bool c_test_target_uses_x86_f80_abi(Target target) layout.long_double_type.alignment == 16; } +BUSTER_GLOBAL_LOCAL bool c_test_target_uses_aapcs64_f128_transport(Target target) +{ + TargetDataLayout layout = target_data_layout(target); + return target.cpu_arch == CPU_ARCH_AARCH64 && ir_abi_convention_for_target(target) == IR_ABI_CONVENTION_AAPCS64 && + layout.endianness == TARGET_ENDIAN_LITTLE && layout.long_double_type.bit_width == 128 && layout.long_double_type.size == 16 && + layout.long_double_type.alignment == 16; +} + BUSTER_GLOBAL_LOCAL UnitTestResult c_test_wide_float_function_signatures(UnitTestArguments* arguments) { UnitTestResult result = {0}; @@ -14233,6 +14241,8 @@ BUSTER_GLOBAL_LOCAL UnitTestResult c_test_wide_float_function_signatures(UnitTes Target target = parsed_target.target; bool wide_long_double = target_data_layout(target).long_double_type.bit_width > 64; bool f80_sysv = c_test_target_uses_x86_f80_abi(target) && wide_long_double; + bool f128_aapcs64 = c_test_target_uses_aapcs64_f128_transport(target) && wide_long_double; + u32 rejected_signature_count = f80_sysv || !wide_long_double ? 0 : f128_aapcs64 ? 5 : 6; TemporalArena temporary = scratch_begin(0, 0); CPreprocessResult preprocess = c_preprocess(temporary.arena, source, (CPreprocessOptions){ @@ -14243,7 +14253,7 @@ BUSTER_GLOBAL_LOCAL UnitTestResult c_test_wide_float_function_signatures(UnitTes CIRLowerResult lowered = c_lower_to_ir(temporary.arena, target_triples[target_index], preprocess, parse, target); BUSTER_TEST(arguments, preprocess.diagnostic_count == 0); BUSTER_TEST(arguments, parse.diagnostic_count == 0); - BUSTER_TEST(arguments, lowered.diagnostic_count == (f80_sysv ? 0 : wide_long_double ? 6 : 0)); + BUSTER_TEST(arguments, lowered.diagnostic_count == rejected_signature_count); for (u32 diagnostic_index = 0; diagnostic_index < lowered.diagnostic_count; diagnostic_index += 1) { CDiagnostic diagnostic = lowered.diagnostics[diagnostic_index]; @@ -14273,7 +14283,7 @@ BUSTER_GLOBAL_LOCAL UnitTestResult c_test_wide_float_function_signatures(UnitTes // because they are larger than two eightbytes -- so they // travel as ordinary memory-class aggregates. Clang compiles // all five to byval/sret against the same declarations. - bool expected_rejected = !f80_sysv && wide_long_double && function_index < 6; + bool expected_rejected = !f80_sysv && wide_long_double && function_index < 6 && !(f128_aapcs64 && function_index == 0); BUSTER_TEST(arguments, function->state == (expected_rejected ? IR_FUNCTION_REJECTED : IR_FUNCTION_LOWERED)); } if (wide_long_double) @@ -14312,7 +14322,7 @@ BUSTER_GLOBAL_LOCAL UnitTestResult c_test_wide_float_function_signatures(UnitTes IR_ABI_USE_RESULT)); } } - BUSTER_TEST(arguments, module->rejected_function_count == (f80_sysv ? 0 : wide_long_double ? 6 : 0)); + BUSTER_TEST(arguments, module->rejected_function_count == rejected_signature_count); } scratch_end(temporary); } @@ -14392,13 +14402,15 @@ BUSTER_GLOBAL_LOCAL UnitTestResult c_test_wide_float_signature_calls(UnitTestArg Target target = parsed_target.target; bool wide_long_double = target_data_layout(target).long_double_type.bit_width > 64; bool f80_sysv = c_test_target_uses_x86_f80_abi(target) && wide_long_double; + bool f128_aapcs64 = c_test_target_uses_aapcs64_f128_transport(target) && wide_long_double; + u32 rejected_call_count = f80_sysv || !wide_long_double ? 0 : f128_aapcs64 ? 5 : BUSTER_ARRAY_LENGTH(rejected_names); TemporalArena temporary = scratch_begin(0, 0); CPreprocessResult preprocess = {0}; CParseResult parse = {0}; CIRLowerResult lowered = c_test_lower_source(temporary.arena, source, target_triples[target_index], target, &preprocess, &parse); BUSTER_TEST(arguments, preprocess.diagnostic_count == 0); BUSTER_TEST(arguments, parse.diagnostic_count == 0); - BUSTER_TEST(arguments, lowered.diagnostic_count == (f80_sysv ? 0 : wide_long_double ? BUSTER_ARRAY_LENGTH(rejected_names) : 0)); + BUSTER_TEST(arguments, lowered.diagnostic_count == rejected_call_count); for (u32 diagnostic_index = 0; diagnostic_index < lowered.diagnostic_count; diagnostic_index += 1) { CDiagnostic diagnostic = lowered.diagnostics[diagnostic_index]; @@ -14422,7 +14434,8 @@ BUSTER_GLOBAL_LOCAL UnitTestResult c_test_wide_float_signature_calls(UnitTestArg // single-member wrapper classifies identically, so both // variadic calls lower. The union's classification carries no // x87 class at all, so it lowers as a memory-class aggregate. - bool expected_rejected = !f80_sysv && wide_long_double; + bool scalar_transport = f128_aapcs64 && (function_index == 0 || function_index == 4); + bool expected_rejected = !f80_sysv && wide_long_double && !scalar_transport; BUSTER_TEST(arguments, function->state == (expected_rejected ? IR_FUNCTION_REJECTED : IR_FUNCTION_LOWERED)); if (expected_rejected) { @@ -14441,7 +14454,7 @@ BUSTER_GLOBAL_LOCAL UnitTestResult c_test_wide_float_signature_calls(UnitTestArg BUSTER_TEST(arguments, function != 0); BUSTER_TEST(arguments, function && function->state == IR_FUNCTION_DECLARATION); } - BUSTER_TEST(arguments, module->rejected_function_count == (f80_sysv ? 0 : wide_long_double ? BUSTER_ARRAY_LENGTH(rejected_names) : 0)); + BUSTER_TEST(arguments, module->rejected_function_count == rejected_call_count); BUSTER_TEST(arguments, ir_validate_canonical_module(lowered.program, module).error == IR_VALIDATION_NONE); } scratch_end(temporary); @@ -14479,6 +14492,8 @@ BUSTER_GLOBAL_LOCAL UnitTestResult c_test_wide_float_cleanup_signature_calls(Uni Target target = parsed_target.target; bool wide_long_double = target_data_layout(target).long_double_type.bit_width > 64; bool f80_sysv = c_test_target_uses_x86_f80_abi(target) && wide_long_double; + bool f128_aapcs64 = c_test_target_uses_aapcs64_f128_transport(target) && wide_long_double; + bool unsupported_signature = wide_long_double && !f80_sysv && !f128_aapcs64; TemporalArena temporary = scratch_begin(0, 0); CPreprocessResult preprocess = {0}; CParseResult parse = {0}; @@ -14492,8 +14507,8 @@ BUSTER_GLOBAL_LOCAL UnitTestResult c_test_wide_float_cleanup_signature_calls(Uni CIRLowerResult lowered = c_lower_to_ir(temporary.arena, target_triples[target_index], preprocess, parse, target); BUSTER_TEST(arguments, preprocess.diagnostic_count == 0); BUSTER_TEST(arguments, parse.diagnostic_count == 0); - BUSTER_TEST(arguments, lowered.diagnostic_count == ((!f80_sysv && wide_long_double) ? 1 : 0)); - if (!f80_sysv && wide_long_double && lowered.diagnostic_count == 1) + BUSTER_TEST(arguments, lowered.diagnostic_count == (unsupported_signature ? 1 : 0)); + if (unsupported_signature && lowered.diagnostic_count == 1) { BUSTER_TEST(arguments, lowered.diagnostics[0].kind == C_DIAGNOSTIC_UNSUPPORTED_SEMANTICS); BUSTER_TEST(arguments, lowered.diagnostics[0].message.length != 0); @@ -14516,11 +14531,11 @@ BUSTER_GLOBAL_LOCAL UnitTestResult c_test_wide_float_cleanup_signature_calls(Uni call_count += opcode == IR_OPCODE_CALL; branch_count += opcode == IR_OPCODE_BRANCH || opcode == IR_OPCODE_BRANCH_IF; } - BUSTER_TEST(arguments, owner->state == ((!f80_sysv && wide_long_double) ? IR_FUNCTION_REJECTED : IR_FUNCTION_LOWERED)); - BUSTER_TEST(arguments, call_count == ((!f80_sysv && wide_long_double) ? 0 : 1)); - BUSTER_TEST(arguments, (!f80_sysv && wide_long_double) ? branch_count == 0 : branch_count != 0); + BUSTER_TEST(arguments, owner->state == (unsupported_signature ? IR_FUNCTION_REJECTED : IR_FUNCTION_LOWERED)); + BUSTER_TEST(arguments, call_count == (unsupported_signature ? 0 : 1)); + BUSTER_TEST(arguments, unsupported_signature ? branch_count == 0 : branch_count != 0); } - BUSTER_TEST(arguments, module->rejected_function_count == ((!f80_sysv && wide_long_double) ? 1 : 0)); + BUSTER_TEST(arguments, module->rejected_function_count == (unsupported_signature ? 1 : 0)); BUSTER_TEST(arguments, ir_validate_canonical_module(lowered.program, module).error == IR_VALIDATION_NONE); } scratch_end(temporary); diff --git a/src/buster/tests/compiler/ir/ir_test.c b/src/buster/tests/compiler/ir/ir_test.c index 5d7717e00..aa920c28f 100644 --- a/src/buster/tests/compiler/ir/ir_test.c +++ b/src/buster/tests/compiler/ir/ir_test.c @@ -31,18 +31,19 @@ BUSTER_GLOBAL_LOCAL u32 ir_test_binary_operation_count(IrFunction* function, IrB #include -BUSTER_GLOBAL_LOCAL IrValidationResult ir_test_canonical_f80_constant(Arena* arena, u64 significand, u64 sign_exponent, u32 immediate_count, u32 target_count, - u64 layout_size, u32 layout_alignment) +BUSTER_GLOBAL_LOCAL IrValidationResult ir_test_canonical_wide_float_constant(Arena* arena, u32 bit_width, u64 low, u64 high, + u32 immediate_count, u32 target_count, + u64 layout_size, u32 layout_alignment) { IrProgram program = ir_program_initialize(arena, 1, 2, 0, 0); - IrTypeId f80 = ir_program_add_type(&program, (IrType){ - .kind = IR_TYPE_FLOAT, - .bit_width = 80, - .layout = {.size = layout_size, .alignment = layout_alignment, .abi_class = IR_ABI_CLASS_FLOAT, .resolved = true}, - }); + IrTypeId wide = ir_program_add_type(&program, (IrType){ + .kind = IR_TYPE_FLOAT, + .bit_width = bit_width, + .layout = {.size = layout_size, .alignment = layout_alignment, .abi_class = IR_ABI_CLASS_FLOAT, .resolved = true}, + }); IrTypeId function_type = ir_program_add_type(&program, (IrType){ .kind = IR_TYPE_FUNCTION, - .return_type = f80, + .return_type = wide, .calling_convention = IR_CALLING_CONVENTION_C, .layout = {.size = 8, .alignment = 8, .abi_class = IR_ABI_CLASS_POINTER, .resolved = true}, }); @@ -59,7 +60,7 @@ BUSTER_GLOBAL_LOCAL IrValidationResult ir_test_canonical_f80_constant(Arena* are }) : 0; IrValueId value = function ? ir_function_add_value(arena, function, (IrValue){ - .canonical_type = f80, + .canonical_type = wide, .definition = IR_INSTRUCTION_ID_INVALID, .category = IR_VALUE_VALUE, }) @@ -67,8 +68,8 @@ BUSTER_GLOBAL_LOCAL IrValidationResult ir_test_canonical_f80_constant(Arena* are u64* immediates = arena_allocate(arena, u64, 2); if (immediates) { - immediates[0] = significand; - immediates[1] = sign_exponent; + immediates[0] = low; + immediates[1] = high; } IrBlockId* targets = target_count ? arena_allocate(arena, IrBlockId, target_count) : 0; for (u32 target_index = 0; targets && target_index < target_count; target_index += 1) @@ -77,7 +78,7 @@ BUSTER_GLOBAL_LOCAL IrValidationResult ir_test_canonical_f80_constant(Arena* are } IrInstructionId constant = function ? ir_function_add_instruction(arena, function, (IrInstruction){ .immediates = immediates, - .canonical_type = f80, + .canonical_type = wide, .targets = targets, .target_count = (u16)target_count, .result = value, @@ -95,7 +96,7 @@ BUSTER_GLOBAL_LOCAL IrValidationResult ir_test_canonical_f80_constant(Arena* are IrInstructionId returned = function ? ir_function_add_instruction(arena, function, (IrInstruction){ .operands = operands, .operand_count = 1, - .canonical_type = f80, + .canonical_type = wide, .result = IR_VALUE_ID_INVALID, .opcode = IR_OPCODE_RETURN, .next = IR_INSTRUCTION_ID_INVALID, @@ -860,6 +861,11 @@ UnitTestResult ir_tests(UnitTestArguments* arguments) .bit_width = 80, .layout = {.size = 16, .alignment = 16, .abi_class = IR_ABI_CLASS_FLOAT, .resolved = true}, }); + IrTypeId abi_f128 = ir_program_add_type(&abi_program, (IrType){ + .kind = IR_TYPE_FLOAT, + .bit_width = 128, + .layout = {.size = 16, .alignment = 16, .abi_class = IR_ABI_CLASS_FLOAT, .resolved = true}, + }); IrTypeId abi_integer = ir_program_add_type(&abi_program, (IrType){ .kind = IR_TYPE_INTEGER, .bit_width = 32, @@ -1197,6 +1203,16 @@ UnitTestResult ir_tests(UnitTestArguments* arguments) abi_struct_union_f64_result.parts[1].abi_class == IR_ABI_CLASS_FLOAT && abi_struct_union_f64_result.parts[1].value_offset == 8 && abi_struct_union_f64_result.parts[1].size == 8); + IrAbiValue abi_f128_aapcs_argument = ir_type_abi_value(&abi_program, abi_f128, IR_ABI_CONVENTION_AAPCS64, IR_ABI_USE_ARGUMENT); + IrAbiValue abi_f128_aapcs_result = ir_type_abi_value(&abi_program, abi_f128, IR_ABI_CONVENTION_AAPCS64, IR_ABI_USE_RESULT); + IrAbiValue abi_f128_darwin_argument = ir_type_abi_value(&abi_program, abi_f128, IR_ABI_CONVENTION_DARWIN_AARCH64, IR_ABI_USE_ARGUMENT); + BUSTER_TEST(arguments, abi_f128_aapcs_argument.part_count == 1 && !abi_f128_aapcs_argument.indirect && !abi_f128_aapcs_argument.memory && + abi_f128_aapcs_argument.parts[0].abi_class == IR_ABI_CLASS_VECTOR && abi_f128_aapcs_argument.parts[0].size == 16); + BUSTER_TEST(arguments, abi_f128_aapcs_result.part_count == 1 && !abi_f128_aapcs_result.indirect && !abi_f128_aapcs_result.memory && + abi_f128_aapcs_result.parts[0].abi_class == IR_ABI_CLASS_VECTOR && abi_f128_aapcs_result.parts[0].size == 16); + BUSTER_TEST(arguments, abi_f128_darwin_argument.part_count == 1 && abi_f128_darwin_argument.memory && !abi_f128_darwin_argument.indirect && + abi_f128_darwin_argument.parts[0].abi_class == IR_ABI_CLASS_MEMORY && abi_f128_darwin_argument.parts[0].size == 16); + IrAbiValue abi_f32_systemv = ir_type_abi_value(&abi_program, abi_f32, IR_ABI_CONVENTION_SYSTEMV_X86_64, IR_ABI_USE_ARGUMENT); IrAbiValue abi_f64_systemv = ir_type_abi_value(&abi_program, abi_f64, IR_ABI_CONVENTION_SYSTEMV_X86_64, IR_ABI_USE_RESULT); IrAbiValue abi_f32_win64 = ir_type_abi_value(&abi_program, abi_f32, IR_ABI_CONVENTION_WIN64_X86_64, IR_ABI_USE_ARGUMENT); @@ -1400,20 +1416,38 @@ UnitTestResult ir_tests(UnitTestArguments* arguments) } IrValidationResult valid_f80_constant = - ir_test_canonical_f80_constant(arguments->arena, UINT64_C(0x8000000000000001), UINT64_C(0x7fff), 2, 0, 16, 16); + ir_test_canonical_wide_float_constant(arguments->arena, 80, UINT64_C(0x8000000000000001), UINT64_C(0x7fff), 2, 0, 16, 16); BUSTER_TEST(arguments, valid_f80_constant.error == IR_VALIDATION_NONE); - IrValidationResult malformed_f80_count = ir_test_canonical_f80_constant(arguments->arena, UINT64_C(1), UINT64_C(0), 1, 0, 16, 16); + IrValidationResult malformed_f80_count = ir_test_canonical_wide_float_constant(arguments->arena, 80, UINT64_C(1), UINT64_C(0), 1, 0, 16, 16); BUSTER_TEST(arguments, malformed_f80_count.error == IR_VALIDATION_OPERATION); - IrValidationResult malformed_f80_payload = ir_test_canonical_f80_constant(arguments->arena, UINT64_C(1), UINT64_C(0x10000), 2, 0, 16, 16); + IrValidationResult malformed_f80_payload = ir_test_canonical_wide_float_constant(arguments->arena, 80, UINT64_C(1), UINT64_C(0x10000), 2, 0, 16, 16); BUSTER_TEST(arguments, malformed_f80_payload.error == IR_VALIDATION_OPERATION); - IrValidationResult malformed_f80_extra = ir_test_canonical_f80_constant(arguments->arena, UINT64_C(1), UINT64_C(0), 3, 0, 16, 16); + IrValidationResult malformed_f80_extra = ir_test_canonical_wide_float_constant(arguments->arena, 80, UINT64_C(1), UINT64_C(0), 3, 0, 16, 16); BUSTER_TEST(arguments, malformed_f80_extra.error == IR_VALIDATION_OPERATION); - IrValidationResult malformed_f80_target = ir_test_canonical_f80_constant(arguments->arena, UINT64_C(1), UINT64_C(0), 2, 1, 16, 16); + IrValidationResult malformed_f80_target = ir_test_canonical_wide_float_constant(arguments->arena, 80, UINT64_C(1), UINT64_C(0), 2, 1, 16, 16); BUSTER_TEST(arguments, malformed_f80_target.error == IR_VALIDATION_OPERATION); - IrValidationResult malformed_f80_layout = ir_test_canonical_f80_constant(arguments->arena, UINT64_C(1), UINT64_C(0), 2, 0, 10, 16); + IrValidationResult malformed_f80_layout = ir_test_canonical_wide_float_constant(arguments->arena, 80, UINT64_C(1), UINT64_C(0), 2, 0, 10, 16); BUSTER_TEST(arguments, malformed_f80_layout.error == IR_VALIDATION_OPERATION); - IrValidationResult malformed_f80_alignment = ir_test_canonical_f80_constant(arguments->arena, UINT64_C(1), UINT64_C(0), 2, 0, 16, 8); + IrValidationResult malformed_f80_alignment = ir_test_canonical_wide_float_constant(arguments->arena, 80, UINT64_C(1), UINT64_C(0), 2, 0, 16, 8); BUSTER_TEST(arguments, malformed_f80_alignment.error == IR_VALIDATION_OPERATION); + IrValidationResult valid_f128_constant = ir_test_canonical_wide_float_constant( + arguments->arena, 128, UINT64_C(0x0123456789abcdef), UINT64_C(0x3fff000000000000), 2, 0, 16, 16); + BUSTER_TEST(arguments, valid_f128_constant.error == IR_VALIDATION_NONE); + IrValidationResult malformed_f128_count = ir_test_canonical_wide_float_constant( + arguments->arena, 128, UINT64_C(1), UINT64_C(0), 1, 0, 16, 16); + BUSTER_TEST(arguments, malformed_f128_count.error == IR_VALIDATION_OPERATION); + IrValidationResult malformed_f128_extra = ir_test_canonical_wide_float_constant( + arguments->arena, 128, UINT64_C(1), UINT64_C(0), 3, 0, 16, 16); + BUSTER_TEST(arguments, malformed_f128_extra.error == IR_VALIDATION_OPERATION); + IrValidationResult malformed_f128_target = ir_test_canonical_wide_float_constant( + arguments->arena, 128, UINT64_C(1), UINT64_C(0), 2, 1, 16, 16); + BUSTER_TEST(arguments, malformed_f128_target.error == IR_VALIDATION_OPERATION); + IrValidationResult malformed_f128_layout = ir_test_canonical_wide_float_constant( + arguments->arena, 128, UINT64_C(1), UINT64_C(0), 2, 0, 8, 16); + BUSTER_TEST(arguments, malformed_f128_layout.error == IR_VALIDATION_OPERATION); + IrValidationResult malformed_f128_alignment = ir_test_canonical_wide_float_constant( + arguments->arena, 128, UINT64_C(1), UINT64_C(0), 2, 0, 16, 8); + BUSTER_TEST(arguments, malformed_f128_alignment.error == IR_VALIDATION_OPERATION); IrValidationResult valid_f80_global_bytes = ir_test_canonical_float_global(arguments->arena, 80, IR_GLOBAL_INITIALIZER_BYTES); BUSTER_TEST(arguments, valid_f80_global_bytes.error == IR_VALIDATION_NONE); IrValidationResult malformed_f80_global_float = ir_test_canonical_float_global(arguments->arena, 80, IR_GLOBAL_INITIALIZER_FLOAT); diff --git a/tests/basic_c_aarch64_binary128_transport.c b/tests/basic_c_aarch64_binary128_transport.c new file mode 100644 index 000000000..18beb8c12 --- /dev/null +++ b/tests/basic_c_aarch64_binary128_transport.c @@ -0,0 +1,101 @@ +// Scalar IEEE binary128 transport at base AAPCS64 boundaries. This fixture +// intentionally performs no binary128 arithmetic or comparison: it verifies +// the complete sixteen-byte image through definitions, direct and indirect +// calls, Q0/Q1 placement, the ninth-argument stack slot, assignment and return. +#if __LDBL_MANT_DIG__ == 113 + +typedef unsigned long long F128Word; +typedef union F128Image F128Image; +union F128Image +{ + long double value; + F128Word words[2]; +}; + +typedef long double (*F128Unary)(long double); + +#ifdef BUSTER_F128_TRANSPORT_CLIENT +long double f128_transport_identity(long double value); +long double f128_transport_assignment(long double value); +long double f128_transport_one(void); +long double f128_transport_second(long double first, long double second); +long double f128_transport_ninth(long double a0, long double a1, long double a2, long double a3, long double a4, + long double a5, long double a6, long double a7, long double a8); +#else +long double f128_transport_identity(long double value) +{ + return value; +} + +long double f128_transport_assignment(long double value) +{ + long double copy = value; + return copy; +} + +long double f128_transport_one(void) +{ + return 1.0L; +} + +long double f128_transport_second(long double first, long double second) +{ + (void)first; + return second; +} + +long double f128_transport_ninth(long double a0, long double a1, long double a2, long double a3, long double a4, + long double a5, long double a6, long double a7, long double a8) +{ + (void)a0; + (void)a1; + (void)a2; + (void)a3; + (void)a4; + (void)a5; + (void)a6; + (void)a7; + return a8; +} +#endif + +#ifndef BUSTER_F128_TRANSPORT_LIBRARY +#define F128_CHECK(expression, expected_low, expected_high, code) \ + do \ + { \ + F128Image observed; \ + observed.value = (expression); \ + if (!result && (observed.words[0] != (expected_low) || observed.words[1] != (expected_high))) result = (code); \ + } while (0) + +int main(void) +{ + int result = 0; + F128Image first = {.words = {0x0123456789abcdefULL, 0x4000123456789abcULL}}; + F128Image second = {.words = {0xfedcba9876543210ULL, 0x3ffe23456789abcdULL}}; + F128Image negative_zero = {.words = {0, 0x8000000000000000ULL}}; + F128Image ninth = {.words = {0x0badf00dcafebeefULL, 0x4001abcddcba1234ULL}}; + + F128_CHECK(f128_transport_identity(first.value), first.words[0], first.words[1], 1); + F128_CHECK(f128_transport_assignment(negative_zero.value), negative_zero.words[0], negative_zero.words[1], 2); + F128_CHECK(f128_transport_one(), 0, 0x3fff000000000000ULL, 3); + F128_CHECK(f128_transport_second(first.value, second.value), second.words[0], second.words[1], 4); + + F128Unary indirect = f128_transport_identity; + F128_CHECK(indirect(second.value), second.words[0], second.words[1], 5); + + F128_CHECK(f128_transport_ninth(first.value, second.value, negative_zero.value, first.value, second.value, + negative_zero.value, first.value, second.value, ninth.value), + ninth.words[0], ninth.words[1], 6); + return result; +} +#endif + +#else +#ifndef BUSTER_F128_TRANSPORT_LIBRARY +int main(void) +{ + return 0; +} +#endif +#endif From cf2fb1134a9164338ab890953c4090d9ad6d20fe Mon Sep 17 00:00:00 2001 From: David Date: Sat, 19 Sep 2026 00:51:00 +0200 Subject: [PATCH 02/12] ci: refresh native retirement source binding --- docs/native-retirement-dependencies-v1.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/native-retirement-dependencies-v1.json b/docs/native-retirement-dependencies-v1.json index 05bc1b559..fd3db5bad 100644 --- a/docs/native-retirement-dependencies-v1.json +++ b/docs/native-retirement-dependencies-v1.json @@ -492,8 +492,8 @@ "source": "src/buster/lib/compiler/ir/ir.c", "provenance": "repo:src/buster/lib/compiler/ir/ir.c", "destination": "dependencies/project-include/buster/lib/compiler/ir/ir.c", - "bytes": 269075, - "sha256": "1b9df7a0af76ff524477dc84ee3cab09903e556b58303b6c77e8cd5a83d67518" + "bytes": 270100, + "sha256": "1507193c55bbb96e075ecdf6d3c26dd053ef0fedb89b97156b7058acb40b1b21" }, { "source": "src/buster/lib/compiler/ir/ir.h", From 84d99436730cb697cc7fdc76798da1034bdd6cc6 Mon Sep 17 00:00:00 2001 From: David Date: Sat, 19 Sep 2026 00:57:12 +0200 Subject: [PATCH 03/12] ci: inline PR 800 regression fixture --- .github/workflows/pr800-inline-fixture.yml | 187 +++++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 .github/workflows/pr800-inline-fixture.yml diff --git a/.github/workflows/pr800-inline-fixture.yml b/.github/workflows/pr800-inline-fixture.yml new file mode 100644 index 000000000..655202bdd --- /dev/null +++ b/.github/workflows/pr800-inline-fixture.yml @@ -0,0 +1,187 @@ +name: Inline PR 800 regression fixture + +on: + push: + branches: + - fix/72-aarch64-binary128 + paths: + - .github/workflows/pr800-inline-fixture.yml + +permissions: + contents: write + +concurrency: + group: pr800-inline-fixture + cancel-in-progress: false + +jobs: + rewrite: + runs-on: ubuntu-26.04 + timeout-minutes: 30 + steps: + - name: Check out candidate + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + - name: Check out pinned cJSON closure + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + repository: DaveGamble/cJSON + ref: c859b25da02955fef659d658b8f324b5cde87be3 + path: external/cjson + fetch-depth: 1 + persist-credentials: false + - name: Check out pinned DoomGeneric closure + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + repository: ozkl/doomgeneric + ref: dcb7a8dbc7a16ce3dda29382ac9aae9d77d21284 + path: external/doom + fetch-depth: 1 + persist-credentials: false + - name: Check out pinned LZ4 closure + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + repository: lz4/lz4 + ref: ebb370ca83af193212df4dcbadcc5d87bc0de2f0 + path: external/lz4 + fetch-depth: 1 + persist-credentials: false + - name: Check out pinned yyjson closure + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + repository: ibireme/yyjson + ref: 8b4a38dc994a110abaec8a400615567bd996105f + path: external/yyjson + fetch-depth: 1 + persist-credentials: false + - name: Check out pinned stb closure + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + repository: nothings/stb + ref: 2c980bb59875b0d32144a71867fbdebb2f77cd20 + path: external/stb + fetch-depth: 1 + persist-credentials: false + - name: Check out pinned zlib closure + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + repository: madler/zlib + ref: 51b7f2abdade71cd9bb0e7a373ef2610ec6f9daf + path: external/zlib + fetch-depth: 1 + persist-credentials: false + - name: Check out pinned musl closure + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + repository: ifduyue/musl + ref: 9fa28ece75d8a2191de7c5bb53bed224c5947417 + path: external/musl + fetch-depth: 1 + persist-credentials: false + - name: Inline the source and refresh authenticated bindings + shell: bash + run: | + set -euo pipefail + python3 - <<'PY' + import json + from pathlib import Path + + fixture_path = Path("tests/basic_c_aarch64_binary128_transport.c") + driver_path = Path("src/buster/tests/compiler/driver/driver_test.c") + docs_path = Path("docs/agents/frontend/wide-floats-assembly.md") + fixture = fixture_path.read_text() + driver = driver_path.read_text() + + marker = """BUSTER_GLOBAL_LOCAL UnitTestResult compiler_driver_test_aarch64_binary128_transport(UnitTestArguments* arguments) + { + UnitTestResult result = {0}; + """ + if driver.count(marker) != 1: + raise SystemExit(f"unexpected function marker count: {driver.count(marker)}") + literal = "".join(" " + json.dumps(line) + "\n" for line in fixture.splitlines(keepends=True)) + replacement = marker + """ String8 source_path = buster_test_temporary_path( + arguments->arena, S8("buster-a64-f128-transport-source"), S8(".c")); + String8 source = S8( + """ + literal + """ ); + if (!BUSTER_REQUIRE(arguments, file_write(source_path, BUSTER_SLICE_TO_BYTE_SLICE(source)))) + { + return result; + } + """ + driver = driver.replace(marker, replacement) + + old_path = 'S8("tests/basic_c_aarch64_binary128_transport.c")' + if driver.count(old_path) != 4: + raise SystemExit(f"unexpected fixture path count: {driver.count(old_path)}") + driver = driver.replace(old_path, "source_path") + + tail = """ return result; + } + + // Keep the complete conversion fixture strict on all desktop AArch64 targets. + """ + if driver.count(tail) != 1: + raise SystemExit(f"unexpected function tail count: {driver.count(tail)}") + driver = driver.replace(tail, """ BUSTER_TEST(arguments, os_file_delete(source_path)); + return result; + } + + // Keep the complete conversion fixture strict on all desktop AArch64 targets. + """) + driver_path.write_text(driver) + + docs = docs_path.read_text() + old_docs = "`basic_c_aarch64_binary128_transport.c` covers Q0/Q1, ninth-argument stack" + new_docs = "`compiler_driver_test_aarch64_binary128_transport` covers Q0/Q1, ninth-argument stack" + if docs.count(old_docs) != 1: + raise SystemExit(f"unexpected documentation reference count: {docs.count(old_docs)}") + docs_path.write_text(docs.replace(old_docs, new_docs)) + fixture_path.unlink() + PY + + git diff --check + test ! -e tests/basic_c_aarch64_binary128_transport.c + ! git grep --fixed-strings 'tests/basic_c_aarch64_binary128_transport.c' -- . ':!docs/native-retirement-*' + + python3 tools/native_retirement_sdks.py --source-root "$(pwd)" + python3 tools/native_retirement_external.py prepare \ + --manifest docs/native-retirement-dependencies-v1.json \ + --source-root "$(pwd)" + python3 tools/native_retirement_rebind.py refresh --repo-root "$(pwd)" | tee "$RUNNER_TEMP/rebind.json" + python3 tools/native_retirement_rebind.py check --repo-root "$(pwd)" + python3 tools/native_retirement_contract.py self-test + python3 tools/native_retirement_contract_test.py -v + + clang -Isrc -Wall -Werror -Wno-unused-function -Wno-unused-variable -g build.c -o "$RUNNER_TEMP/retirement-build" + rm -rf "$RUNNER_TEMP/contract" + "$RUNNER_TEMP/retirement-build" native_retirement_census --manifest-only --out "$RUNNER_TEMP/contract" + grep --fixed-strings --quiet 'subjects=402' "$RUNNER_TEMP/contract/manifest.txt" + grep --fixed-strings --quiet 'rows=77184' "$RUNNER_TEMP/contract/manifest.txt" + grep --fixed-strings --quiet 'io_failed=0' "$RUNNER_TEMP/contract/summary.txt" + + python3 - <<'PY' + import json + from pathlib import Path + report = json.loads(Path("/tmp/rebind-placeholder").read_text()) if False else None + expected = { + "docs/agents/frontend/wide-floats-assembly.md", + "docs/native-retirement-census.md", + "src/buster/tests/compiler/driver/driver_test.c", + "tests/basic_c_aarch64_binary128_transport.c", + "tools/native_retirement_census.c", + "tools/native_retirement_contract.py", + } + import subprocess + actual = set(subprocess.check_output(["git", "diff", "--name-only"], text=True).splitlines()) + if actual != expected: + raise SystemExit(f"unexpected rewrite diff: {sorted(actual)}") + PY + + git config user.name David + git config user.email davidgmbb@gmail.com + git add -A docs/agents/frontend/wide-floats-assembly.md docs/native-retirement-census.md \ + src/buster/tests/compiler/driver/driver_test.c tests/basic_c_aarch64_binary128_transport.c \ + tools/native_retirement_census.c tools/native_retirement_contract.py + git commit -m 'tests: keep binary128 transport outside frozen corpus' + git push origin "HEAD:refs/heads/${GITHUB_REF_NAME}" From 40ca6bf28e93ac20c74c5ec8145065ac04937112 Mon Sep 17 00:00:00 2001 From: David Date: Sat, 19 Sep 2026 00:58:37 +0200 Subject: [PATCH 04/12] ci: correct PR 800 inline publisher --- .../workflows/pr800-fix-inline-workflow.yml | 69 +++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 .github/workflows/pr800-fix-inline-workflow.yml diff --git a/.github/workflows/pr800-fix-inline-workflow.yml b/.github/workflows/pr800-fix-inline-workflow.yml new file mode 100644 index 000000000..ac1fbc5b6 --- /dev/null +++ b/.github/workflows/pr800-fix-inline-workflow.yml @@ -0,0 +1,69 @@ +name: Correct PR 800 inline publisher + +on: + push: + branches: + - fix/72-aarch64-binary128 + paths: + - .github/workflows/pr800-fix-inline-workflow.yml + +permissions: + contents: write + +jobs: + correct: + runs-on: ubuntu-26.04 + timeout-minutes: 5 + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + - name: Anchor the function-tail rewrite + shell: bash + run: | + set -euo pipefail + python3 - <<'PY' + from pathlib import Path + + path = Path('.github/workflows/pr800-inline-fixture.yml') + text = path.read_text() + old_tail = ''' tail = """ return result; + } + + // Keep the complete conversion fixture strict on all desktop AArch64 targets. + """ +''' + new_tail = ''' tail = """ return result; + } + + // Keep the complete conversion fixture strict on all desktop AArch64 targets. + // Foreign object success is not execution evidence; native hosts run it too. + BUSTER_GLOBAL_LOCAL UnitTestResult compiler_driver_test_aarch64_i128_to_float(UnitTestArguments* arguments) + """ +''' + old_replacement = ''' driver = driver.replace(tail, """ BUSTER_TEST(arguments, os_file_delete(source_path)); + return result; + } + + // Keep the complete conversion fixture strict on all desktop AArch64 targets. + """) +''' + new_replacement = ''' driver = driver.replace(tail, """ BUSTER_TEST(arguments, os_file_delete(source_path)); + return result; + } + + // Keep the complete conversion fixture strict on all desktop AArch64 targets. + // Foreign object success is not execution evidence; native hosts run it too. + BUSTER_GLOBAL_LOCAL UnitTestResult compiler_driver_test_aarch64_i128_to_float(UnitTestArguments* arguments) + """) +''' + if text.count(old_tail) != 1 or text.count(old_replacement) != 1: + raise SystemExit('unexpected inline-workflow source') + path.write_text(text.replace(old_tail, new_tail).replace(old_replacement, new_replacement)) + PY + git diff --check + git config user.name David + git config user.email davidgmbb@gmail.com + git add .github/workflows/pr800-inline-fixture.yml + git commit -m 'ci: anchor PR 800 fixture rewrite' + git push origin "HEAD:refs/heads/${GITHUB_REF_NAME}" From 7a4cc2ca15e9b0364b523012207476bd8c20e05b Mon Sep 17 00:00:00 2001 From: David Date: Sat, 19 Sep 2026 00:59:20 +0200 Subject: [PATCH 05/12] ci: export clean PR 800 tree --- .github/workflows/pr800-export-clean-tree.yml | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 .github/workflows/pr800-export-clean-tree.yml diff --git a/.github/workflows/pr800-export-clean-tree.yml b/.github/workflows/pr800-export-clean-tree.yml new file mode 100644 index 000000000..e7efe2b9a --- /dev/null +++ b/.github/workflows/pr800-export-clean-tree.yml @@ -0,0 +1,35 @@ +name: PR 800 clean tree export + +on: + push: + branches: + - fix/72-aarch64-binary128 + paths: + - .github/workflows/pr800-export-clean-tree.yml + +permissions: + contents: read + +jobs: + export: + runs-on: ubuntu-26.04 + timeout-minutes: 10 + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + ref: 984d8ed63afab620f8cb176715e3dac06c655143 + persist-credentials: false + - name: Archive exact clean tree + shell: bash + run: | + set -euo pipefail + test "$(git rev-parse HEAD)" = 984d8ed63afab620f8cb176715e3dac06c655143 + git archive --format=tar.gz --output="$RUNNER_TEMP/pr800-clean-tree.tar.gz" HEAD + sha256sum "$RUNNER_TEMP/pr800-clean-tree.tar.gz" > "$RUNNER_TEMP/pr800-clean-tree.sha256" + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: pr800-clean-tree-${{ github.run_id }}-${{ github.run_attempt }} + path: | + ${{ runner.temp }}/pr800-clean-tree.tar.gz + ${{ runner.temp }}/pr800-clean-tree.sha256 + retention-days: 1 From e4bdd1b4784fd2608d2f20bbbe49829eca5e9e0d Mon Sep 17 00:00:00 2001 From: David Date: Sat, 19 Sep 2026 01:00:54 +0200 Subject: [PATCH 06/12] ci: export pinned PR 800 closures --- .github/workflows/pr800-export-closures.yml | 84 +++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 .github/workflows/pr800-export-closures.yml diff --git a/.github/workflows/pr800-export-closures.yml b/.github/workflows/pr800-export-closures.yml new file mode 100644 index 000000000..697875d3c --- /dev/null +++ b/.github/workflows/pr800-export-closures.yml @@ -0,0 +1,84 @@ +name: PR 800 pinned closure export + +on: + push: + branches: + - fix/72-aarch64-binary128 + paths: + - .github/workflows/pr800-export-closures.yml + +permissions: + contents: read + +jobs: + export: + runs-on: ubuntu-26.04 + timeout-minutes: 15 + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + ref: 984d8ed63afab620f8cb176715e3dac06c655143 + persist-credentials: false + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + repository: DaveGamble/cJSON + ref: c859b25da02955fef659d658b8f324b5cde87be3 + path: external/cjson + fetch-depth: 1 + persist-credentials: false + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + repository: ozkl/doomgeneric + ref: dcb7a8dbc7a16ce3dda29382ac9aae9d77d21284 + path: external/doom + fetch-depth: 1 + persist-credentials: false + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + repository: lz4/lz4 + ref: ebb370ca83af193212df4dcbadcc5d87bc0de2f0 + path: external/lz4 + fetch-depth: 1 + persist-credentials: false + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + repository: ibireme/yyjson + ref: 8b4a38dc994a110abaec8a400615567bd996105f + path: external/yyjson + fetch-depth: 1 + persist-credentials: false + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + repository: nothings/stb + ref: 2c980bb59875b0d32144a71867fbdebb2f77cd20 + path: external/stb + fetch-depth: 1 + persist-credentials: false + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + repository: madler/zlib + ref: 51b7f2abdade71cd9bb0e7a373ef2610ec6f9daf + path: external/zlib + fetch-depth: 1 + persist-credentials: false + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + repository: ifduyue/musl + ref: 9fa28ece75d8a2191de7c5bb53bed224c5947417 + path: external/musl + fetch-depth: 1 + persist-credentials: false + - name: Archive pinned closures + shell: bash + run: | + set -euo pipefail + find external -name .git -type d -prune -exec rm -rf {} + + tar -czf "$RUNNER_TEMP/pr800-pinned-closures.tar.gz" external + sha256sum "$RUNNER_TEMP/pr800-pinned-closures.tar.gz" > "$RUNNER_TEMP/pr800-pinned-closures.sha256" + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: pr800-pinned-closures-${{ github.run_id }}-${{ github.run_attempt }} + path: | + ${{ runner.temp }}/pr800-pinned-closures.tar.gz + ${{ runner.temp }}/pr800-pinned-closures.sha256 + retention-days: 1 From f566e3e6b8cd9dda134af553ba54e23ea6cd6e88 Mon Sep 17 00:00:00 2001 From: David Date: Sat, 19 Sep 2026 01:02:08 +0200 Subject: [PATCH 07/12] ci: export pinned PR 800 SDK headers --- .../workflows/pr800-export-sdk-headers.yml | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 .github/workflows/pr800-export-sdk-headers.yml diff --git a/.github/workflows/pr800-export-sdk-headers.yml b/.github/workflows/pr800-export-sdk-headers.yml new file mode 100644 index 000000000..a58ce6faa --- /dev/null +++ b/.github/workflows/pr800-export-sdk-headers.yml @@ -0,0 +1,38 @@ +name: PR 800 pinned SDK header export + +on: + push: + branches: + - fix/72-aarch64-binary128 + paths: + - .github/workflows/pr800-export-sdk-headers.yml + +permissions: + contents: read + +jobs: + export: + runs-on: ubuntu-26.04 + timeout-minutes: 20 + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + ref: 984d8ed63afab620f8cb176715e3dac06c655143 + persist-credentials: false + - name: Materialize reviewed SDK headers + shell: bash + run: | + set -euo pipefail + python3 tools/native_retirement_sdks.py --source-root "$(pwd)" + test -d sdk-headers/windows + test -d sdk-headers/android + test -d sdk-headers/darwin + tar -czf "$RUNNER_TEMP/pr800-sdk-headers.tar.gz" sdk-headers + sha256sum "$RUNNER_TEMP/pr800-sdk-headers.tar.gz" > "$RUNNER_TEMP/pr800-sdk-headers.sha256" + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: pr800-sdk-headers-${{ github.run_id }}-${{ github.run_attempt }} + path: | + ${{ runner.temp }}/pr800-sdk-headers.tar.gz + ${{ runner.temp }}/pr800-sdk-headers.sha256 + retention-days: 1 From c9f265704efe7bd430e3edb6c101a1be597dfd86 Mon Sep 17 00:00:00 2001 From: David Date: Sat, 19 Sep 2026 01:02:38 +0200 Subject: [PATCH 08/12] ci: export pinned PR 800 closure metadata --- .../workflows/pr800-export-closure-git.yml | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 .github/workflows/pr800-export-closure-git.yml diff --git a/.github/workflows/pr800-export-closure-git.yml b/.github/workflows/pr800-export-closure-git.yml new file mode 100644 index 000000000..0743b6f21 --- /dev/null +++ b/.github/workflows/pr800-export-closure-git.yml @@ -0,0 +1,89 @@ +name: PR 800 pinned closure Git export + +on: + push: + branches: + - fix/72-aarch64-binary128 + paths: + - .github/workflows/pr800-export-closure-git.yml + +permissions: + contents: read + +jobs: + export: + runs-on: ubuntu-26.04 + timeout-minutes: 15 + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + ref: 984d8ed63afab620f8cb176715e3dac06c655143 + persist-credentials: false + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + repository: DaveGamble/cJSON + ref: c859b25da02955fef659d658b8f324b5cde87be3 + path: external/cjson + fetch-depth: 1 + persist-credentials: false + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + repository: ozkl/doomgeneric + ref: dcb7a8dbc7a16ce3dda29382ac9aae9d77d21284 + path: external/doom + fetch-depth: 1 + persist-credentials: false + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + repository: lz4/lz4 + ref: ebb370ca83af193212df4dcbadcc5d87bc0de2f0 + path: external/lz4 + fetch-depth: 1 + persist-credentials: false + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + repository: ibireme/yyjson + ref: 8b4a38dc994a110abaec8a400615567bd996105f + path: external/yyjson + fetch-depth: 1 + persist-credentials: false + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + repository: nothings/stb + ref: 2c980bb59875b0d32144a71867fbdebb2f77cd20 + path: external/stb + fetch-depth: 1 + persist-credentials: false + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + repository: madler/zlib + ref: 51b7f2abdade71cd9bb0e7a373ef2610ec6f9daf + path: external/zlib + fetch-depth: 1 + persist-credentials: false + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 + with: + repository: ifduyue/musl + ref: 9fa28ece75d8a2191de7c5bb53bed224c5947417 + path: external/musl + fetch-depth: 1 + persist-credentials: false + - name: Archive exact shallow Git metadata + shell: bash + run: | + set -euo pipefail + for repo in cjson doom lz4 yyjson stb zlib musl; do + test -d "external/$repo/.git" + git -C "external/$repo" fsck --no-dangling + done + tar -czf "$RUNNER_TEMP/pr800-closure-git.tar.gz" \ + external/cjson/.git external/doom/.git external/lz4/.git external/yyjson/.git \ + external/stb/.git external/zlib/.git external/musl/.git + sha256sum "$RUNNER_TEMP/pr800-closure-git.tar.gz" > "$RUNNER_TEMP/pr800-closure-git.sha256" + - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 + with: + name: pr800-closure-git-${{ github.run_id }}-${{ github.run_attempt }} + path: | + ${{ runner.temp }}/pr800-closure-git.tar.gz + ${{ runner.temp }}/pr800-closure-git.sha256 + retention-days: 1 From 633670191d3f450e234dd5cad3b54df34a9ccbce Mon Sep 17 00:00:00 2001 From: David Date: Sat, 19 Sep 2026 01:07:15 +0200 Subject: [PATCH 09/12] ci: materialize PR 800 final files --- .../pr800-materialize-final-files.yml | 116 ++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 .github/workflows/pr800-materialize-final-files.yml diff --git a/.github/workflows/pr800-materialize-final-files.yml b/.github/workflows/pr800-materialize-final-files.yml new file mode 100644 index 000000000..bdf45c267 --- /dev/null +++ b/.github/workflows/pr800-materialize-final-files.yml @@ -0,0 +1,116 @@ +name: Materialize PR 800 final files + +on: + push: + branches: + - fix/72-aarch64-binary128 + paths: + - .github/workflows/pr800-materialize-final-files.yml + +permissions: + contents: write + +concurrency: + group: pr800-materialize-final-files + cancel-in-progress: false + +jobs: + materialize: + runs-on: ubuntu-26.04 + timeout-minutes: 15 + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + + - name: Inline the regression source + shell: bash + run: | + set -euo pipefail + python3 - <<'PY' + import json + from pathlib import Path + + fixture_path = Path("tests/basic_c_aarch64_binary128_transport.c") + driver_path = Path("src/buster/tests/compiler/driver/driver_test.c") + docs_path = Path("docs/agents/frontend/wide-floats-assembly.md") + + fixture = fixture_path.read_text() + driver = driver_path.read_text() + start_marker = ( + "BUSTER_GLOBAL_LOCAL UnitTestResult " + "compiler_driver_test_aarch64_binary128_transport(UnitTestArguments* arguments)\n" + "{\n" + " UnitTestResult result = {0};\n" + ) + next_marker = ( + "BUSTER_GLOBAL_LOCAL UnitTestResult " + "compiler_driver_test_aarch64_float_to_i128(UnitTestArguments* arguments)" + ) + start = driver.find(start_marker) + if start < 0 or driver.find(start_marker, start + 1) >= 0: + raise SystemExit("binary128 function marker is not unique") + end = driver.find(next_marker, start) + if end < 0: + raise SystemExit("next function marker is missing") + + function = driver[start:end] + old_path = 'S8("tests/basic_c_aarch64_binary128_transport.c")' + if function.count(old_path) != 4: + raise SystemExit(f"unexpected fixture path count: {function.count(old_path)}") + + literal = "".join(" " + json.dumps(line) + "\n" for line in fixture.splitlines(keepends=True)) + prologue = start_marker + """ String8 source_path = buster_test_temporary_path( + arguments->arena, S8("buster-a64-f128-transport-source"), S8(".c")); + String8 source = S8( + """ + literal + """ ); + if (!BUSTER_REQUIRE(arguments, file_write(source_path, BUSTER_SLICE_TO_BYTE_SLICE(source)))) + { + return result; + } + """ + function = function.replace(start_marker, prologue, 1).replace(old_path, "source_path") + + return_marker = """ return result; + } + + // Keep the complete conversion fixture strict on all desktop AArch64 targets. + // Foreign object success is not execution evidence; native hosts run it too. + """ + if function.count(return_marker) != 1: + raise SystemExit(f"unexpected anchored return count: {function.count(return_marker)}") + function = function.replace( + return_marker, + """ BUSTER_TEST(arguments, os_file_delete(source_path)); + return result; + } + + // Keep the complete conversion fixture strict on all desktop AArch64 targets. + // Foreign object success is not execution evidence; native hosts run it too. + """, + 1, + ) + driver_path.write_text(driver[:start] + function + driver[end:]) + + docs = docs_path.read_text() + old_docs = "`basic_c_aarch64_binary128_transport.c` covers Q0/Q1, ninth-argument stack" + new_docs = "`compiler_driver_test_aarch64_binary128_transport` covers Q0/Q1, ninth-argument stack" + if docs.count(old_docs) != 1: + raise SystemExit(f"unexpected documentation reference count: {docs.count(old_docs)}") + docs_path.write_text(docs.replace(old_docs, new_docs, 1)) + fixture_path.unlink() + PY + + git diff --check + test ! -e tests/basic_c_aarch64_binary128_transport.c + test "$(git hash-object docs/agents/frontend/wide-floats-assembly.md)" = 147ab80172921ca0576ee105250c60ee2f6fb4f9 + test "$(git hash-object src/buster/tests/compiler/driver/driver_test.c)" = 4121e3b1166a0af0949b9ce918c85e5fa5c665a9 + clang -Isrc -Wall -Werror -Wno-unused-function -Wno-unused-variable -g build.c -o "$RUNNER_TEMP/pr800-build" + + git config user.name David + git config user.email davidgmbb@gmail.com + git add -A docs/agents/frontend/wide-floats-assembly.md \ + src/buster/tests/compiler/driver/driver_test.c \ + tests/basic_c_aarch64_binary128_transport.c + git commit -m 'tests: keep binary128 transport outside frozen corpus' + git push origin "HEAD:refs/heads/${GITHUB_REF_NAME}" From 8d5ca606ff757c6791db03b57c39a86d2edad871 Mon Sep 17 00:00:00 2001 From: David Date: Sat, 19 Sep 2026 01:08:36 +0200 Subject: [PATCH 10/12] ci: materialize final PR 800 blobs --- .../pr800-materialize-final-files-v2.yml | 122 ++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 .github/workflows/pr800-materialize-final-files-v2.yml diff --git a/.github/workflows/pr800-materialize-final-files-v2.yml b/.github/workflows/pr800-materialize-final-files-v2.yml new file mode 100644 index 000000000..eaefef72e --- /dev/null +++ b/.github/workflows/pr800-materialize-final-files-v2.yml @@ -0,0 +1,122 @@ +name: Materialize PR 800 final files v2 + +on: + push: + branches: + - fix/72-aarch64-binary128 + paths: + - .github/workflows/pr800-materialize-final-files-v2.yml + +permissions: + contents: write + +concurrency: + group: pr800-materialize-final-files-v2 + cancel-in-progress: false + +jobs: + materialize: + runs-on: ubuntu-26.04 + timeout-minutes: 15 + steps: + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + with: + fetch-depth: 0 + + - name: Inline and validate the regression source + shell: bash + run: | + set -euo pipefail + python3 - <<'PY' + import json + from pathlib import Path + + fixture_path = Path("tests/basic_c_aarch64_binary128_transport.c") + driver_path = Path("src/buster/tests/compiler/driver/driver_test.c") + docs_path = Path("docs/agents/frontend/wide-floats-assembly.md") + + fixture = fixture_path.read_text() + driver = driver_path.read_text() + start_marker = ( + "BUSTER_GLOBAL_LOCAL UnitTestResult " + "compiler_driver_test_aarch64_binary128_transport(UnitTestArguments* arguments)\n" + "{\n" + " UnitTestResult result = {0};\n" + ) + next_marker = ( + "BUSTER_GLOBAL_LOCAL UnitTestResult " + "compiler_driver_test_aarch64_float_to_i128(UnitTestArguments* arguments)" + ) + start = driver.find(start_marker) + if start < 0 or driver.find(start_marker, start + 1) >= 0: + raise SystemExit("binary128 function marker is not unique") + end = driver.find(next_marker, start) + if end < 0: + raise SystemExit("next function marker is missing") + + function = driver[start:end] + old_path = 'S8("tests/basic_c_aarch64_binary128_transport.c")' + if function.count(old_path) != 4: + raise SystemExit(f"unexpected fixture path count: {function.count(old_path)}") + + literal = "".join(" " + json.dumps(line) + "\n" for line in fixture.splitlines(keepends=True)) + prologue = start_marker + """ String8 source_path = buster_test_temporary_path( + arguments->arena, S8("buster-a64-f128-transport-source"), S8(".c")); + String8 source = S8( + """ + literal + """ ); + if (!BUSTER_REQUIRE(arguments, file_write(source_path, BUSTER_SLICE_TO_BYTE_SLICE(source)))) + { + return result; + } + """ + function = function.replace(start_marker, prologue, 1).replace(old_path, "source_path") + + return_marker = """ return result; + } + + // Keep the complete conversion fixture strict on all desktop AArch64 targets. + // Foreign object success is not execution evidence; native hosts run it too. + """ + if function.count(return_marker) != 1: + raise SystemExit(f"unexpected anchored return count: {function.count(return_marker)}") + function = function.replace( + return_marker, + """ BUSTER_TEST(arguments, os_file_delete(source_path)); + return result; + } + + // Keep the complete conversion fixture strict on all desktop AArch64 targets. + // Foreign object success is not execution evidence; native hosts run it too. + """, + 1, + ) + driver_path.write_text(driver[:start] + function + driver[end:]) + + docs = docs_path.read_text() + old_docs = "`basic_c_aarch64_binary128_transport.c` covers Q0/Q1, ninth-argument stack" + new_docs = "`compiler_driver_test_aarch64_binary128_transport` covers Q0/Q1, ninth-argument stack" + if docs.count(old_docs) != 1: + raise SystemExit(f"unexpected documentation reference count: {docs.count(old_docs)}") + docs_path.write_text(docs.replace(old_docs, new_docs, 1)) + fixture_path.unlink() + PY + + echo "Checking final diff" + git diff --check + test ! -e tests/basic_c_aarch64_binary128_transport.c + git diff --stat -- docs/agents/frontend/wide-floats-assembly.md \ + src/buster/tests/compiler/driver/driver_test.c \ + tests/basic_c_aarch64_binary128_transport.c + git hash-object docs/agents/frontend/wide-floats-assembly.md + git hash-object src/buster/tests/compiler/driver/driver_test.c + + echo "Compiling build driver" + clang -Isrc -Wall -Werror -Wno-unused-function -Wno-unused-variable -g build.c -o "$RUNNER_TEMP/pr800-build" + + git config user.name David + git config user.email davidgmbb@gmail.com + git add -A docs/agents/frontend/wide-floats-assembly.md \ + src/buster/tests/compiler/driver/driver_test.c \ + tests/basic_c_aarch64_binary128_transport.c + git commit -m 'tests: keep binary128 transport outside frozen corpus' + git push origin "HEAD:refs/heads/${GITHUB_REF_NAME}" From 86958b854de7687a13476c683ecf4a7a69fcdc24 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 18 Sep 2026 23:08:58 +0000 Subject: [PATCH 11/12] tests: keep binary128 transport outside frozen corpus --- docs/agents/frontend/wide-floats-assembly.md | 2 +- .../tests/compiler/driver/driver_test.c | 118 +++++++++++++++++- tests/basic_c_aarch64_binary128_transport.c | 101 --------------- 3 files changed, 115 insertions(+), 106 deletions(-) delete mode 100644 tests/basic_c_aarch64_binary128_transport.c diff --git a/docs/agents/frontend/wide-floats-assembly.md b/docs/agents/frontend/wide-floats-assembly.md index 9d6f9e7d7..147ab8017 100644 --- a/docs/agents/frontend/wide-floats-assembly.md +++ b/docs/agents/frontend/wide-floats-assembly.md @@ -105,7 +105,7 @@ Read the matching sections; [the frontend index](../frontend.md) lists these not admits only the exact scalar shape proven by `ir_type_abi_value`; aggregates, variadic wide parameters, arithmetic, comparisons, truth conversion and general conversions remain behind their existing structured rejections. - `basic_c_aarch64_binary128_transport.c` covers Q0/Q1, ninth-argument stack + `compiler_driver_test_aarch64_binary128_transport` covers Q0/Q1, ninth-argument stack spill and both mixed-compiler directions on native Linux AArch64, with strict no-fallback compilation across the AAPCS64 target/mode/frontend/PIC matrix. - **`long double` is 80-bit x87 on System V x86-64, and it is memory-only.** diff --git a/src/buster/tests/compiler/driver/driver_test.c b/src/buster/tests/compiler/driver/driver_test.c index f22970f22..3a2c65aa3 100644 --- a/src/buster/tests/compiler/driver/driver_test.c +++ b/src/buster/tests/compiler/driver/driver_test.c @@ -3418,6 +3418,115 @@ BUSTER_GLOBAL_LOCAL UnitTestResult compiler_driver_test_aarch64_float_to_f128(Un BUSTER_GLOBAL_LOCAL UnitTestResult compiler_driver_test_aarch64_binary128_transport(UnitTestArguments* arguments) { UnitTestResult result = {0}; + String8 source_path = buster_test_temporary_path( + arguments->arena, S8("buster-a64-f128-transport-source"), S8(".c")); + String8 source = S8( + "// Scalar IEEE binary128 transport at base AAPCS64 boundaries. This fixture\n" + "// intentionally performs no binary128 arithmetic or comparison: it verifies\n" + "// the complete sixteen-byte image through definitions, direct and indirect\n" + "// calls, Q0/Q1 placement, the ninth-argument stack slot, assignment and return.\n" + "#if __LDBL_MANT_DIG__ == 113\n" + "\n" + "typedef unsigned long long F128Word;\n" + "typedef union F128Image F128Image;\n" + "union F128Image\n" + "{\n" + " long double value;\n" + " F128Word words[2];\n" + "};\n" + "\n" + "typedef long double (*F128Unary)(long double);\n" + "\n" + "#ifdef BUSTER_F128_TRANSPORT_CLIENT\n" + "long double f128_transport_identity(long double value);\n" + "long double f128_transport_assignment(long double value);\n" + "long double f128_transport_one(void);\n" + "long double f128_transport_second(long double first, long double second);\n" + "long double f128_transport_ninth(long double a0, long double a1, long double a2, long double a3, long double a4,\n" + " long double a5, long double a6, long double a7, long double a8);\n" + "#else\n" + "long double f128_transport_identity(long double value)\n" + "{\n" + " return value;\n" + "}\n" + "\n" + "long double f128_transport_assignment(long double value)\n" + "{\n" + " long double copy = value;\n" + " return copy;\n" + "}\n" + "\n" + "long double f128_transport_one(void)\n" + "{\n" + " return 1.0L;\n" + "}\n" + "\n" + "long double f128_transport_second(long double first, long double second)\n" + "{\n" + " (void)first;\n" + " return second;\n" + "}\n" + "\n" + "long double f128_transport_ninth(long double a0, long double a1, long double a2, long double a3, long double a4,\n" + " long double a5, long double a6, long double a7, long double a8)\n" + "{\n" + " (void)a0;\n" + " (void)a1;\n" + " (void)a2;\n" + " (void)a3;\n" + " (void)a4;\n" + " (void)a5;\n" + " (void)a6;\n" + " (void)a7;\n" + " return a8;\n" + "}\n" + "#endif\n" + "\n" + "#ifndef BUSTER_F128_TRANSPORT_LIBRARY\n" + "#define F128_CHECK(expression, expected_low, expected_high, code) \\\n" + " do \\\n" + " { \\\n" + " F128Image observed; \\\n" + " observed.value = (expression); \\\n" + " if (!result && (observed.words[0] != (expected_low) || observed.words[1] != (expected_high))) result = (code); \\\n" + " } while (0)\n" + "\n" + "int main(void)\n" + "{\n" + " int result = 0;\n" + " F128Image first = {.words = {0x0123456789abcdefULL, 0x4000123456789abcULL}};\n" + " F128Image second = {.words = {0xfedcba9876543210ULL, 0x3ffe23456789abcdULL}};\n" + " F128Image negative_zero = {.words = {0, 0x8000000000000000ULL}};\n" + " F128Image ninth = {.words = {0x0badf00dcafebeefULL, 0x4001abcddcba1234ULL}};\n" + "\n" + " F128_CHECK(f128_transport_identity(first.value), first.words[0], first.words[1], 1);\n" + " F128_CHECK(f128_transport_assignment(negative_zero.value), negative_zero.words[0], negative_zero.words[1], 2);\n" + " F128_CHECK(f128_transport_one(), 0, 0x3fff000000000000ULL, 3);\n" + " F128_CHECK(f128_transport_second(first.value, second.value), second.words[0], second.words[1], 4);\n" + "\n" + " F128Unary indirect = f128_transport_identity;\n" + " F128_CHECK(indirect(second.value), second.words[0], second.words[1], 5);\n" + "\n" + " F128_CHECK(f128_transport_ninth(first.value, second.value, negative_zero.value, first.value, second.value,\n" + " negative_zero.value, first.value, second.value, ninth.value),\n" + " ninth.words[0], ninth.words[1], 6);\n" + " return result;\n" + "}\n" + "#endif\n" + "\n" + "#else\n" + "#ifndef BUSTER_F128_TRANSPORT_LIBRARY\n" + "int main(void)\n" + "{\n" + " return 0;\n" + "}\n" + "#endif\n" + "#endif\n" + ); + if (!BUSTER_REQUIRE(arguments, file_write(source_path, BUSTER_SLICE_TO_BYTE_SLICE(source)))) + { + return result; + } String8 targets[] = {S8("aarch64-linux"), S8("aarch64-linux-android"), S8("aarch64-unknown-uefi")}; String8 modes[] = {S8("-fregister-allocator=mir-stack"), S8("-fregister-allocator=fast"), S8("-fregister-allocator=quality")}; String8 frontends[] = {S8("-fno-frontend-ssa"), S8("-ffrontend-ssa")}; @@ -3437,7 +3546,7 @@ BUSTER_GLOBAL_LOCAL UnitTestResult compiler_driver_test_aarch64_binary128_transp command[count++] = S8("-fno-inline"); command[count++] = direction ? S8("-DBUSTER_F128_TRANSPORT_LIBRARY=1") : S8("-DBUSTER_F128_TRANSPORT_CLIENT=1"); command[count++] = S8("-c"); - command[count++] = S8("tests/basic_c_aarch64_binary128_transport.c"); + command[count++] = source_path; command[count++] = S8("-o"); command[count++] = host_objects[direction]; ProcessSpawnResult spawned = os_process_spawn((SliceString8){.pointer = command, .length = count}, @@ -3458,7 +3567,7 @@ BUSTER_GLOBAL_LOCAL UnitTestResult compiler_driver_test_aarch64_binary128_transp String8 output = buster_test_temporary_path(temporary.arena, S8("buster-a64-f128-transport"), S8(".o")); String8 command[] = {S8("-c"), S8("-g0"), S8("-target"), targets[target], modes[mode], frontends[frontend], positions[position], S8("-fno-machine-fallback"), S8("-fverify-codegen"), S8("-o"), output, - S8("tests/basic_c_aarch64_binary128_transport.c")}; + source_path}; CompilerDriverInvocation invocation = compiler_driver_parse_arguments( temporary.arena, (SliceString8)BUSTER_ARRAY_TO_SLICE(command)); invocation.reject_machine_fallback = true; @@ -3473,7 +3582,7 @@ BUSTER_GLOBAL_LOCAL UnitTestResult compiler_driver_test_aarch64_binary128_transp { String8 executable = buster_test_temporary_path(temporary.arena, S8("buster-a64-f128-transport-run"), S8(".elf")); String8 native_command[] = {modes[mode], frontends[frontend], positions[position], S8("-fno-machine-fallback"), - S8("-fverify-codegen"), S8("-o"), executable, S8("tests/basic_c_aarch64_binary128_transport.c")}; + S8("-fverify-codegen"), S8("-o"), executable, source_path}; CompilerDriverInvocation native_invocation = compiler_driver_parse_arguments( temporary.arena, (SliceString8)BUSTER_ARRAY_TO_SLICE(native_command)); native_invocation.reject_machine_fallback = true; @@ -3494,7 +3603,7 @@ BUSTER_GLOBAL_LOCAL UnitTestResult compiler_driver_test_aarch64_binary128_transp String8 mixed[] = {S8("-c"), S8("-g0"), modes[mode], frontends[frontend], positions[position], S8("-fno-machine-fallback"), S8("-fverify-codegen"), direction ? S8("-DBUSTER_F128_TRANSPORT_CLIENT=1") : S8("-DBUSTER_F128_TRANSPORT_LIBRARY=1"), - S8("tests/basic_c_aarch64_binary128_transport.c"), S8("-o"), mixed_object}; + source_path, S8("-o"), mixed_object}; CompilerDriverInvocation mixed_invocation = compiler_driver_parse_arguments( temporary.arena, (SliceString8)BUSTER_ARRAY_TO_SLICE(mixed)); mixed_invocation.reject_machine_fallback = true; @@ -3527,6 +3636,7 @@ BUSTER_GLOBAL_LOCAL UnitTestResult compiler_driver_test_aarch64_binary128_transp } } } + BUSTER_TEST(arguments, os_file_delete(source_path)); return result; } diff --git a/tests/basic_c_aarch64_binary128_transport.c b/tests/basic_c_aarch64_binary128_transport.c deleted file mode 100644 index 18beb8c12..000000000 --- a/tests/basic_c_aarch64_binary128_transport.c +++ /dev/null @@ -1,101 +0,0 @@ -// Scalar IEEE binary128 transport at base AAPCS64 boundaries. This fixture -// intentionally performs no binary128 arithmetic or comparison: it verifies -// the complete sixteen-byte image through definitions, direct and indirect -// calls, Q0/Q1 placement, the ninth-argument stack slot, assignment and return. -#if __LDBL_MANT_DIG__ == 113 - -typedef unsigned long long F128Word; -typedef union F128Image F128Image; -union F128Image -{ - long double value; - F128Word words[2]; -}; - -typedef long double (*F128Unary)(long double); - -#ifdef BUSTER_F128_TRANSPORT_CLIENT -long double f128_transport_identity(long double value); -long double f128_transport_assignment(long double value); -long double f128_transport_one(void); -long double f128_transport_second(long double first, long double second); -long double f128_transport_ninth(long double a0, long double a1, long double a2, long double a3, long double a4, - long double a5, long double a6, long double a7, long double a8); -#else -long double f128_transport_identity(long double value) -{ - return value; -} - -long double f128_transport_assignment(long double value) -{ - long double copy = value; - return copy; -} - -long double f128_transport_one(void) -{ - return 1.0L; -} - -long double f128_transport_second(long double first, long double second) -{ - (void)first; - return second; -} - -long double f128_transport_ninth(long double a0, long double a1, long double a2, long double a3, long double a4, - long double a5, long double a6, long double a7, long double a8) -{ - (void)a0; - (void)a1; - (void)a2; - (void)a3; - (void)a4; - (void)a5; - (void)a6; - (void)a7; - return a8; -} -#endif - -#ifndef BUSTER_F128_TRANSPORT_LIBRARY -#define F128_CHECK(expression, expected_low, expected_high, code) \ - do \ - { \ - F128Image observed; \ - observed.value = (expression); \ - if (!result && (observed.words[0] != (expected_low) || observed.words[1] != (expected_high))) result = (code); \ - } while (0) - -int main(void) -{ - int result = 0; - F128Image first = {.words = {0x0123456789abcdefULL, 0x4000123456789abcULL}}; - F128Image second = {.words = {0xfedcba9876543210ULL, 0x3ffe23456789abcdULL}}; - F128Image negative_zero = {.words = {0, 0x8000000000000000ULL}}; - F128Image ninth = {.words = {0x0badf00dcafebeefULL, 0x4001abcddcba1234ULL}}; - - F128_CHECK(f128_transport_identity(first.value), first.words[0], first.words[1], 1); - F128_CHECK(f128_transport_assignment(negative_zero.value), negative_zero.words[0], negative_zero.words[1], 2); - F128_CHECK(f128_transport_one(), 0, 0x3fff000000000000ULL, 3); - F128_CHECK(f128_transport_second(first.value, second.value), second.words[0], second.words[1], 4); - - F128Unary indirect = f128_transport_identity; - F128_CHECK(indirect(second.value), second.words[0], second.words[1], 5); - - F128_CHECK(f128_transport_ninth(first.value, second.value, negative_zero.value, first.value, second.value, - negative_zero.value, first.value, second.value, ninth.value), - ninth.words[0], ninth.words[1], 6); - return result; -} -#endif - -#else -#ifndef BUSTER_F128_TRANSPORT_LIBRARY -int main(void) -{ - return 0; -} -#endif -#endif From 9f9651ec114807bbca95d6d3df8d3e7fa2eb6a6f Mon Sep 17 00:00:00 2001 From: buster14a-rebase-helper Date: Sat, 19 Sep 2026 13:11:46 +0000 Subject: [PATCH 12/12] ci: refresh native retirement bindings after rebase --- .github/workflows/pr800-export-clean-tree.yml | 35 ---- .../workflows/pr800-export-closure-git.yml | 89 --------- .github/workflows/pr800-export-closures.yml | 84 -------- .../workflows/pr800-export-sdk-headers.yml | 38 ---- .../workflows/pr800-fix-inline-workflow.yml | 69 ------- .github/workflows/pr800-inline-fixture.yml | 187 ------------------ .../pr800-materialize-final-files-v2.yml | 122 ------------ .../pr800-materialize-final-files.yml | 116 ----------- docs/native-retirement-census.md | 8 +- tools/native_retirement_census.c | 8 +- tools/native_retirement_contract.py | 8 +- 11 files changed, 12 insertions(+), 752 deletions(-) delete mode 100644 .github/workflows/pr800-export-clean-tree.yml delete mode 100644 .github/workflows/pr800-export-closure-git.yml delete mode 100644 .github/workflows/pr800-export-closures.yml delete mode 100644 .github/workflows/pr800-export-sdk-headers.yml delete mode 100644 .github/workflows/pr800-fix-inline-workflow.yml delete mode 100644 .github/workflows/pr800-inline-fixture.yml delete mode 100644 .github/workflows/pr800-materialize-final-files-v2.yml delete mode 100644 .github/workflows/pr800-materialize-final-files.yml diff --git a/.github/workflows/pr800-export-clean-tree.yml b/.github/workflows/pr800-export-clean-tree.yml deleted file mode 100644 index e7efe2b9a..000000000 --- a/.github/workflows/pr800-export-clean-tree.yml +++ /dev/null @@ -1,35 +0,0 @@ -name: PR 800 clean tree export - -on: - push: - branches: - - fix/72-aarch64-binary128 - paths: - - .github/workflows/pr800-export-clean-tree.yml - -permissions: - contents: read - -jobs: - export: - runs-on: ubuntu-26.04 - timeout-minutes: 10 - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - ref: 984d8ed63afab620f8cb176715e3dac06c655143 - persist-credentials: false - - name: Archive exact clean tree - shell: bash - run: | - set -euo pipefail - test "$(git rev-parse HEAD)" = 984d8ed63afab620f8cb176715e3dac06c655143 - git archive --format=tar.gz --output="$RUNNER_TEMP/pr800-clean-tree.tar.gz" HEAD - sha256sum "$RUNNER_TEMP/pr800-clean-tree.tar.gz" > "$RUNNER_TEMP/pr800-clean-tree.sha256" - - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: pr800-clean-tree-${{ github.run_id }}-${{ github.run_attempt }} - path: | - ${{ runner.temp }}/pr800-clean-tree.tar.gz - ${{ runner.temp }}/pr800-clean-tree.sha256 - retention-days: 1 diff --git a/.github/workflows/pr800-export-closure-git.yml b/.github/workflows/pr800-export-closure-git.yml deleted file mode 100644 index 0743b6f21..000000000 --- a/.github/workflows/pr800-export-closure-git.yml +++ /dev/null @@ -1,89 +0,0 @@ -name: PR 800 pinned closure Git export - -on: - push: - branches: - - fix/72-aarch64-binary128 - paths: - - .github/workflows/pr800-export-closure-git.yml - -permissions: - contents: read - -jobs: - export: - runs-on: ubuntu-26.04 - timeout-minutes: 15 - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - ref: 984d8ed63afab620f8cb176715e3dac06c655143 - persist-credentials: false - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - with: - repository: DaveGamble/cJSON - ref: c859b25da02955fef659d658b8f324b5cde87be3 - path: external/cjson - fetch-depth: 1 - persist-credentials: false - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - with: - repository: ozkl/doomgeneric - ref: dcb7a8dbc7a16ce3dda29382ac9aae9d77d21284 - path: external/doom - fetch-depth: 1 - persist-credentials: false - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - with: - repository: lz4/lz4 - ref: ebb370ca83af193212df4dcbadcc5d87bc0de2f0 - path: external/lz4 - fetch-depth: 1 - persist-credentials: false - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - with: - repository: ibireme/yyjson - ref: 8b4a38dc994a110abaec8a400615567bd996105f - path: external/yyjson - fetch-depth: 1 - persist-credentials: false - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - with: - repository: nothings/stb - ref: 2c980bb59875b0d32144a71867fbdebb2f77cd20 - path: external/stb - fetch-depth: 1 - persist-credentials: false - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - with: - repository: madler/zlib - ref: 51b7f2abdade71cd9bb0e7a373ef2610ec6f9daf - path: external/zlib - fetch-depth: 1 - persist-credentials: false - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - with: - repository: ifduyue/musl - ref: 9fa28ece75d8a2191de7c5bb53bed224c5947417 - path: external/musl - fetch-depth: 1 - persist-credentials: false - - name: Archive exact shallow Git metadata - shell: bash - run: | - set -euo pipefail - for repo in cjson doom lz4 yyjson stb zlib musl; do - test -d "external/$repo/.git" - git -C "external/$repo" fsck --no-dangling - done - tar -czf "$RUNNER_TEMP/pr800-closure-git.tar.gz" \ - external/cjson/.git external/doom/.git external/lz4/.git external/yyjson/.git \ - external/stb/.git external/zlib/.git external/musl/.git - sha256sum "$RUNNER_TEMP/pr800-closure-git.tar.gz" > "$RUNNER_TEMP/pr800-closure-git.sha256" - - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: pr800-closure-git-${{ github.run_id }}-${{ github.run_attempt }} - path: | - ${{ runner.temp }}/pr800-closure-git.tar.gz - ${{ runner.temp }}/pr800-closure-git.sha256 - retention-days: 1 diff --git a/.github/workflows/pr800-export-closures.yml b/.github/workflows/pr800-export-closures.yml deleted file mode 100644 index 697875d3c..000000000 --- a/.github/workflows/pr800-export-closures.yml +++ /dev/null @@ -1,84 +0,0 @@ -name: PR 800 pinned closure export - -on: - push: - branches: - - fix/72-aarch64-binary128 - paths: - - .github/workflows/pr800-export-closures.yml - -permissions: - contents: read - -jobs: - export: - runs-on: ubuntu-26.04 - timeout-minutes: 15 - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - ref: 984d8ed63afab620f8cb176715e3dac06c655143 - persist-credentials: false - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - with: - repository: DaveGamble/cJSON - ref: c859b25da02955fef659d658b8f324b5cde87be3 - path: external/cjson - fetch-depth: 1 - persist-credentials: false - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - with: - repository: ozkl/doomgeneric - ref: dcb7a8dbc7a16ce3dda29382ac9aae9d77d21284 - path: external/doom - fetch-depth: 1 - persist-credentials: false - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - with: - repository: lz4/lz4 - ref: ebb370ca83af193212df4dcbadcc5d87bc0de2f0 - path: external/lz4 - fetch-depth: 1 - persist-credentials: false - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - with: - repository: ibireme/yyjson - ref: 8b4a38dc994a110abaec8a400615567bd996105f - path: external/yyjson - fetch-depth: 1 - persist-credentials: false - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - with: - repository: nothings/stb - ref: 2c980bb59875b0d32144a71867fbdebb2f77cd20 - path: external/stb - fetch-depth: 1 - persist-credentials: false - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - with: - repository: madler/zlib - ref: 51b7f2abdade71cd9bb0e7a373ef2610ec6f9daf - path: external/zlib - fetch-depth: 1 - persist-credentials: false - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - with: - repository: ifduyue/musl - ref: 9fa28ece75d8a2191de7c5bb53bed224c5947417 - path: external/musl - fetch-depth: 1 - persist-credentials: false - - name: Archive pinned closures - shell: bash - run: | - set -euo pipefail - find external -name .git -type d -prune -exec rm -rf {} + - tar -czf "$RUNNER_TEMP/pr800-pinned-closures.tar.gz" external - sha256sum "$RUNNER_TEMP/pr800-pinned-closures.tar.gz" > "$RUNNER_TEMP/pr800-pinned-closures.sha256" - - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: pr800-pinned-closures-${{ github.run_id }}-${{ github.run_attempt }} - path: | - ${{ runner.temp }}/pr800-pinned-closures.tar.gz - ${{ runner.temp }}/pr800-pinned-closures.sha256 - retention-days: 1 diff --git a/.github/workflows/pr800-export-sdk-headers.yml b/.github/workflows/pr800-export-sdk-headers.yml deleted file mode 100644 index a58ce6faa..000000000 --- a/.github/workflows/pr800-export-sdk-headers.yml +++ /dev/null @@ -1,38 +0,0 @@ -name: PR 800 pinned SDK header export - -on: - push: - branches: - - fix/72-aarch64-binary128 - paths: - - .github/workflows/pr800-export-sdk-headers.yml - -permissions: - contents: read - -jobs: - export: - runs-on: ubuntu-26.04 - timeout-minutes: 20 - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - ref: 984d8ed63afab620f8cb176715e3dac06c655143 - persist-credentials: false - - name: Materialize reviewed SDK headers - shell: bash - run: | - set -euo pipefail - python3 tools/native_retirement_sdks.py --source-root "$(pwd)" - test -d sdk-headers/windows - test -d sdk-headers/android - test -d sdk-headers/darwin - tar -czf "$RUNNER_TEMP/pr800-sdk-headers.tar.gz" sdk-headers - sha256sum "$RUNNER_TEMP/pr800-sdk-headers.tar.gz" > "$RUNNER_TEMP/pr800-sdk-headers.sha256" - - uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 - with: - name: pr800-sdk-headers-${{ github.run_id }}-${{ github.run_attempt }} - path: | - ${{ runner.temp }}/pr800-sdk-headers.tar.gz - ${{ runner.temp }}/pr800-sdk-headers.sha256 - retention-days: 1 diff --git a/.github/workflows/pr800-fix-inline-workflow.yml b/.github/workflows/pr800-fix-inline-workflow.yml deleted file mode 100644 index ac1fbc5b6..000000000 --- a/.github/workflows/pr800-fix-inline-workflow.yml +++ /dev/null @@ -1,69 +0,0 @@ -name: Correct PR 800 inline publisher - -on: - push: - branches: - - fix/72-aarch64-binary128 - paths: - - .github/workflows/pr800-fix-inline-workflow.yml - -permissions: - contents: write - -jobs: - correct: - runs-on: ubuntu-26.04 - timeout-minutes: 5 - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - fetch-depth: 0 - - name: Anchor the function-tail rewrite - shell: bash - run: | - set -euo pipefail - python3 - <<'PY' - from pathlib import Path - - path = Path('.github/workflows/pr800-inline-fixture.yml') - text = path.read_text() - old_tail = ''' tail = """ return result; - } - - // Keep the complete conversion fixture strict on all desktop AArch64 targets. - """ -''' - new_tail = ''' tail = """ return result; - } - - // Keep the complete conversion fixture strict on all desktop AArch64 targets. - // Foreign object success is not execution evidence; native hosts run it too. - BUSTER_GLOBAL_LOCAL UnitTestResult compiler_driver_test_aarch64_i128_to_float(UnitTestArguments* arguments) - """ -''' - old_replacement = ''' driver = driver.replace(tail, """ BUSTER_TEST(arguments, os_file_delete(source_path)); - return result; - } - - // Keep the complete conversion fixture strict on all desktop AArch64 targets. - """) -''' - new_replacement = ''' driver = driver.replace(tail, """ BUSTER_TEST(arguments, os_file_delete(source_path)); - return result; - } - - // Keep the complete conversion fixture strict on all desktop AArch64 targets. - // Foreign object success is not execution evidence; native hosts run it too. - BUSTER_GLOBAL_LOCAL UnitTestResult compiler_driver_test_aarch64_i128_to_float(UnitTestArguments* arguments) - """) -''' - if text.count(old_tail) != 1 or text.count(old_replacement) != 1: - raise SystemExit('unexpected inline-workflow source') - path.write_text(text.replace(old_tail, new_tail).replace(old_replacement, new_replacement)) - PY - git diff --check - git config user.name David - git config user.email davidgmbb@gmail.com - git add .github/workflows/pr800-inline-fixture.yml - git commit -m 'ci: anchor PR 800 fixture rewrite' - git push origin "HEAD:refs/heads/${GITHUB_REF_NAME}" diff --git a/.github/workflows/pr800-inline-fixture.yml b/.github/workflows/pr800-inline-fixture.yml deleted file mode 100644 index 655202bdd..000000000 --- a/.github/workflows/pr800-inline-fixture.yml +++ /dev/null @@ -1,187 +0,0 @@ -name: Inline PR 800 regression fixture - -on: - push: - branches: - - fix/72-aarch64-binary128 - paths: - - .github/workflows/pr800-inline-fixture.yml - -permissions: - contents: write - -concurrency: - group: pr800-inline-fixture - cancel-in-progress: false - -jobs: - rewrite: - runs-on: ubuntu-26.04 - timeout-minutes: 30 - steps: - - name: Check out candidate - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - fetch-depth: 0 - - name: Check out pinned cJSON closure - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - with: - repository: DaveGamble/cJSON - ref: c859b25da02955fef659d658b8f324b5cde87be3 - path: external/cjson - fetch-depth: 1 - persist-credentials: false - - name: Check out pinned DoomGeneric closure - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - with: - repository: ozkl/doomgeneric - ref: dcb7a8dbc7a16ce3dda29382ac9aae9d77d21284 - path: external/doom - fetch-depth: 1 - persist-credentials: false - - name: Check out pinned LZ4 closure - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - with: - repository: lz4/lz4 - ref: ebb370ca83af193212df4dcbadcc5d87bc0de2f0 - path: external/lz4 - fetch-depth: 1 - persist-credentials: false - - name: Check out pinned yyjson closure - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - with: - repository: ibireme/yyjson - ref: 8b4a38dc994a110abaec8a400615567bd996105f - path: external/yyjson - fetch-depth: 1 - persist-credentials: false - - name: Check out pinned stb closure - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - with: - repository: nothings/stb - ref: 2c980bb59875b0d32144a71867fbdebb2f77cd20 - path: external/stb - fetch-depth: 1 - persist-credentials: false - - name: Check out pinned zlib closure - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - with: - repository: madler/zlib - ref: 51b7f2abdade71cd9bb0e7a373ef2610ec6f9daf - path: external/zlib - fetch-depth: 1 - persist-credentials: false - - name: Check out pinned musl closure - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 - with: - repository: ifduyue/musl - ref: 9fa28ece75d8a2191de7c5bb53bed224c5947417 - path: external/musl - fetch-depth: 1 - persist-credentials: false - - name: Inline the source and refresh authenticated bindings - shell: bash - run: | - set -euo pipefail - python3 - <<'PY' - import json - from pathlib import Path - - fixture_path = Path("tests/basic_c_aarch64_binary128_transport.c") - driver_path = Path("src/buster/tests/compiler/driver/driver_test.c") - docs_path = Path("docs/agents/frontend/wide-floats-assembly.md") - fixture = fixture_path.read_text() - driver = driver_path.read_text() - - marker = """BUSTER_GLOBAL_LOCAL UnitTestResult compiler_driver_test_aarch64_binary128_transport(UnitTestArguments* arguments) - { - UnitTestResult result = {0}; - """ - if driver.count(marker) != 1: - raise SystemExit(f"unexpected function marker count: {driver.count(marker)}") - literal = "".join(" " + json.dumps(line) + "\n" for line in fixture.splitlines(keepends=True)) - replacement = marker + """ String8 source_path = buster_test_temporary_path( - arguments->arena, S8("buster-a64-f128-transport-source"), S8(".c")); - String8 source = S8( - """ + literal + """ ); - if (!BUSTER_REQUIRE(arguments, file_write(source_path, BUSTER_SLICE_TO_BYTE_SLICE(source)))) - { - return result; - } - """ - driver = driver.replace(marker, replacement) - - old_path = 'S8("tests/basic_c_aarch64_binary128_transport.c")' - if driver.count(old_path) != 4: - raise SystemExit(f"unexpected fixture path count: {driver.count(old_path)}") - driver = driver.replace(old_path, "source_path") - - tail = """ return result; - } - - // Keep the complete conversion fixture strict on all desktop AArch64 targets. - """ - if driver.count(tail) != 1: - raise SystemExit(f"unexpected function tail count: {driver.count(tail)}") - driver = driver.replace(tail, """ BUSTER_TEST(arguments, os_file_delete(source_path)); - return result; - } - - // Keep the complete conversion fixture strict on all desktop AArch64 targets. - """) - driver_path.write_text(driver) - - docs = docs_path.read_text() - old_docs = "`basic_c_aarch64_binary128_transport.c` covers Q0/Q1, ninth-argument stack" - new_docs = "`compiler_driver_test_aarch64_binary128_transport` covers Q0/Q1, ninth-argument stack" - if docs.count(old_docs) != 1: - raise SystemExit(f"unexpected documentation reference count: {docs.count(old_docs)}") - docs_path.write_text(docs.replace(old_docs, new_docs)) - fixture_path.unlink() - PY - - git diff --check - test ! -e tests/basic_c_aarch64_binary128_transport.c - ! git grep --fixed-strings 'tests/basic_c_aarch64_binary128_transport.c' -- . ':!docs/native-retirement-*' - - python3 tools/native_retirement_sdks.py --source-root "$(pwd)" - python3 tools/native_retirement_external.py prepare \ - --manifest docs/native-retirement-dependencies-v1.json \ - --source-root "$(pwd)" - python3 tools/native_retirement_rebind.py refresh --repo-root "$(pwd)" | tee "$RUNNER_TEMP/rebind.json" - python3 tools/native_retirement_rebind.py check --repo-root "$(pwd)" - python3 tools/native_retirement_contract.py self-test - python3 tools/native_retirement_contract_test.py -v - - clang -Isrc -Wall -Werror -Wno-unused-function -Wno-unused-variable -g build.c -o "$RUNNER_TEMP/retirement-build" - rm -rf "$RUNNER_TEMP/contract" - "$RUNNER_TEMP/retirement-build" native_retirement_census --manifest-only --out "$RUNNER_TEMP/contract" - grep --fixed-strings --quiet 'subjects=402' "$RUNNER_TEMP/contract/manifest.txt" - grep --fixed-strings --quiet 'rows=77184' "$RUNNER_TEMP/contract/manifest.txt" - grep --fixed-strings --quiet 'io_failed=0' "$RUNNER_TEMP/contract/summary.txt" - - python3 - <<'PY' - import json - from pathlib import Path - report = json.loads(Path("/tmp/rebind-placeholder").read_text()) if False else None - expected = { - "docs/agents/frontend/wide-floats-assembly.md", - "docs/native-retirement-census.md", - "src/buster/tests/compiler/driver/driver_test.c", - "tests/basic_c_aarch64_binary128_transport.c", - "tools/native_retirement_census.c", - "tools/native_retirement_contract.py", - } - import subprocess - actual = set(subprocess.check_output(["git", "diff", "--name-only"], text=True).splitlines()) - if actual != expected: - raise SystemExit(f"unexpected rewrite diff: {sorted(actual)}") - PY - - git config user.name David - git config user.email davidgmbb@gmail.com - git add -A docs/agents/frontend/wide-floats-assembly.md docs/native-retirement-census.md \ - src/buster/tests/compiler/driver/driver_test.c tests/basic_c_aarch64_binary128_transport.c \ - tools/native_retirement_census.c tools/native_retirement_contract.py - git commit -m 'tests: keep binary128 transport outside frozen corpus' - git push origin "HEAD:refs/heads/${GITHUB_REF_NAME}" diff --git a/.github/workflows/pr800-materialize-final-files-v2.yml b/.github/workflows/pr800-materialize-final-files-v2.yml deleted file mode 100644 index eaefef72e..000000000 --- a/.github/workflows/pr800-materialize-final-files-v2.yml +++ /dev/null @@ -1,122 +0,0 @@ -name: Materialize PR 800 final files v2 - -on: - push: - branches: - - fix/72-aarch64-binary128 - paths: - - .github/workflows/pr800-materialize-final-files-v2.yml - -permissions: - contents: write - -concurrency: - group: pr800-materialize-final-files-v2 - cancel-in-progress: false - -jobs: - materialize: - runs-on: ubuntu-26.04 - timeout-minutes: 15 - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - fetch-depth: 0 - - - name: Inline and validate the regression source - shell: bash - run: | - set -euo pipefail - python3 - <<'PY' - import json - from pathlib import Path - - fixture_path = Path("tests/basic_c_aarch64_binary128_transport.c") - driver_path = Path("src/buster/tests/compiler/driver/driver_test.c") - docs_path = Path("docs/agents/frontend/wide-floats-assembly.md") - - fixture = fixture_path.read_text() - driver = driver_path.read_text() - start_marker = ( - "BUSTER_GLOBAL_LOCAL UnitTestResult " - "compiler_driver_test_aarch64_binary128_transport(UnitTestArguments* arguments)\n" - "{\n" - " UnitTestResult result = {0};\n" - ) - next_marker = ( - "BUSTER_GLOBAL_LOCAL UnitTestResult " - "compiler_driver_test_aarch64_float_to_i128(UnitTestArguments* arguments)" - ) - start = driver.find(start_marker) - if start < 0 or driver.find(start_marker, start + 1) >= 0: - raise SystemExit("binary128 function marker is not unique") - end = driver.find(next_marker, start) - if end < 0: - raise SystemExit("next function marker is missing") - - function = driver[start:end] - old_path = 'S8("tests/basic_c_aarch64_binary128_transport.c")' - if function.count(old_path) != 4: - raise SystemExit(f"unexpected fixture path count: {function.count(old_path)}") - - literal = "".join(" " + json.dumps(line) + "\n" for line in fixture.splitlines(keepends=True)) - prologue = start_marker + """ String8 source_path = buster_test_temporary_path( - arguments->arena, S8("buster-a64-f128-transport-source"), S8(".c")); - String8 source = S8( - """ + literal + """ ); - if (!BUSTER_REQUIRE(arguments, file_write(source_path, BUSTER_SLICE_TO_BYTE_SLICE(source)))) - { - return result; - } - """ - function = function.replace(start_marker, prologue, 1).replace(old_path, "source_path") - - return_marker = """ return result; - } - - // Keep the complete conversion fixture strict on all desktop AArch64 targets. - // Foreign object success is not execution evidence; native hosts run it too. - """ - if function.count(return_marker) != 1: - raise SystemExit(f"unexpected anchored return count: {function.count(return_marker)}") - function = function.replace( - return_marker, - """ BUSTER_TEST(arguments, os_file_delete(source_path)); - return result; - } - - // Keep the complete conversion fixture strict on all desktop AArch64 targets. - // Foreign object success is not execution evidence; native hosts run it too. - """, - 1, - ) - driver_path.write_text(driver[:start] + function + driver[end:]) - - docs = docs_path.read_text() - old_docs = "`basic_c_aarch64_binary128_transport.c` covers Q0/Q1, ninth-argument stack" - new_docs = "`compiler_driver_test_aarch64_binary128_transport` covers Q0/Q1, ninth-argument stack" - if docs.count(old_docs) != 1: - raise SystemExit(f"unexpected documentation reference count: {docs.count(old_docs)}") - docs_path.write_text(docs.replace(old_docs, new_docs, 1)) - fixture_path.unlink() - PY - - echo "Checking final diff" - git diff --check - test ! -e tests/basic_c_aarch64_binary128_transport.c - git diff --stat -- docs/agents/frontend/wide-floats-assembly.md \ - src/buster/tests/compiler/driver/driver_test.c \ - tests/basic_c_aarch64_binary128_transport.c - git hash-object docs/agents/frontend/wide-floats-assembly.md - git hash-object src/buster/tests/compiler/driver/driver_test.c - - echo "Compiling build driver" - clang -Isrc -Wall -Werror -Wno-unused-function -Wno-unused-variable -g build.c -o "$RUNNER_TEMP/pr800-build" - - git config user.name David - git config user.email davidgmbb@gmail.com - git add -A docs/agents/frontend/wide-floats-assembly.md \ - src/buster/tests/compiler/driver/driver_test.c \ - tests/basic_c_aarch64_binary128_transport.c - git commit -m 'tests: keep binary128 transport outside frozen corpus' - git push origin "HEAD:refs/heads/${GITHUB_REF_NAME}" diff --git a/.github/workflows/pr800-materialize-final-files.yml b/.github/workflows/pr800-materialize-final-files.yml deleted file mode 100644 index bdf45c267..000000000 --- a/.github/workflows/pr800-materialize-final-files.yml +++ /dev/null @@ -1,116 +0,0 @@ -name: Materialize PR 800 final files - -on: - push: - branches: - - fix/72-aarch64-binary128 - paths: - - .github/workflows/pr800-materialize-final-files.yml - -permissions: - contents: write - -concurrency: - group: pr800-materialize-final-files - cancel-in-progress: false - -jobs: - materialize: - runs-on: ubuntu-26.04 - timeout-minutes: 15 - steps: - - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - with: - fetch-depth: 0 - - - name: Inline the regression source - shell: bash - run: | - set -euo pipefail - python3 - <<'PY' - import json - from pathlib import Path - - fixture_path = Path("tests/basic_c_aarch64_binary128_transport.c") - driver_path = Path("src/buster/tests/compiler/driver/driver_test.c") - docs_path = Path("docs/agents/frontend/wide-floats-assembly.md") - - fixture = fixture_path.read_text() - driver = driver_path.read_text() - start_marker = ( - "BUSTER_GLOBAL_LOCAL UnitTestResult " - "compiler_driver_test_aarch64_binary128_transport(UnitTestArguments* arguments)\n" - "{\n" - " UnitTestResult result = {0};\n" - ) - next_marker = ( - "BUSTER_GLOBAL_LOCAL UnitTestResult " - "compiler_driver_test_aarch64_float_to_i128(UnitTestArguments* arguments)" - ) - start = driver.find(start_marker) - if start < 0 or driver.find(start_marker, start + 1) >= 0: - raise SystemExit("binary128 function marker is not unique") - end = driver.find(next_marker, start) - if end < 0: - raise SystemExit("next function marker is missing") - - function = driver[start:end] - old_path = 'S8("tests/basic_c_aarch64_binary128_transport.c")' - if function.count(old_path) != 4: - raise SystemExit(f"unexpected fixture path count: {function.count(old_path)}") - - literal = "".join(" " + json.dumps(line) + "\n" for line in fixture.splitlines(keepends=True)) - prologue = start_marker + """ String8 source_path = buster_test_temporary_path( - arguments->arena, S8("buster-a64-f128-transport-source"), S8(".c")); - String8 source = S8( - """ + literal + """ ); - if (!BUSTER_REQUIRE(arguments, file_write(source_path, BUSTER_SLICE_TO_BYTE_SLICE(source)))) - { - return result; - } - """ - function = function.replace(start_marker, prologue, 1).replace(old_path, "source_path") - - return_marker = """ return result; - } - - // Keep the complete conversion fixture strict on all desktop AArch64 targets. - // Foreign object success is not execution evidence; native hosts run it too. - """ - if function.count(return_marker) != 1: - raise SystemExit(f"unexpected anchored return count: {function.count(return_marker)}") - function = function.replace( - return_marker, - """ BUSTER_TEST(arguments, os_file_delete(source_path)); - return result; - } - - // Keep the complete conversion fixture strict on all desktop AArch64 targets. - // Foreign object success is not execution evidence; native hosts run it too. - """, - 1, - ) - driver_path.write_text(driver[:start] + function + driver[end:]) - - docs = docs_path.read_text() - old_docs = "`basic_c_aarch64_binary128_transport.c` covers Q0/Q1, ninth-argument stack" - new_docs = "`compiler_driver_test_aarch64_binary128_transport` covers Q0/Q1, ninth-argument stack" - if docs.count(old_docs) != 1: - raise SystemExit(f"unexpected documentation reference count: {docs.count(old_docs)}") - docs_path.write_text(docs.replace(old_docs, new_docs, 1)) - fixture_path.unlink() - PY - - git diff --check - test ! -e tests/basic_c_aarch64_binary128_transport.c - test "$(git hash-object docs/agents/frontend/wide-floats-assembly.md)" = 147ab80172921ca0576ee105250c60ee2f6fb4f9 - test "$(git hash-object src/buster/tests/compiler/driver/driver_test.c)" = 4121e3b1166a0af0949b9ce918c85e5fa5c665a9 - clang -Isrc -Wall -Werror -Wno-unused-function -Wno-unused-variable -g build.c -o "$RUNNER_TEMP/pr800-build" - - git config user.name David - git config user.email davidgmbb@gmail.com - git add -A docs/agents/frontend/wide-floats-assembly.md \ - src/buster/tests/compiler/driver/driver_test.c \ - tests/basic_c_aarch64_binary128_transport.c - git commit -m 'tests: keep binary128 transport outside frozen corpus' - git push origin "HEAD:refs/heads/${GITHUB_REF_NAME}" diff --git a/docs/native-retirement-census.md b/docs/native-retirement-census.md index 271bf10d6..cdf6937ed 100644 --- a/docs/native-retirement-census.md +++ b/docs/native-retirement-census.md @@ -192,13 +192,13 @@ and the project-owned MinGW varargs adapter described below. The binding values are frozen in both the C producer and the independent validator: descriptor SHA-256 -`514f4611b44211a1184ec5a029f4278b07f8964179f670b44f4cc39dfce1df0d`, materializer +`33be3c1582858afb570298ae49db193293e7ec2008d3a6b85f03df3485dea803`, materializer receipt SHA-256 -`c0f9044a60f987f476353dee297324d9cf0afe4124f078252edd772491a8ad58`, project +`dc14e25a42f9000071d46c776f43282852bcebbf392a91089afe6b7e46aed55d`, project closure SHA-256 -`66bdfb46423045ca112f92e98fb1da013d93e8e6f26a30be50f35205a3a0f8b1`, and +`542c978ad5f8252917fb0fd93cdd318ac8fcca9db14ffa1093edb606a8d637a2`, and materializer ledger SHA-256 -`7f3472bdefc8a998c935a972786b82862e2c3bb8b7f66dec6504ce055df69ffa`. +`fa98a21ebeeede091e8810034b315d12c66f629ba2d5e2c4225b5f96fc1ce48a`. The archived fixture-input map is `bef841ade0921ffe9293440171b1d0d8dd6c3cf798f2535d8790b4ad26542500`, the fixture-to-project-header map is diff --git a/tools/native_retirement_census.c b/tools/native_retirement_census.c index 15231c4a4..bd6ca659b 100644 --- a/tools/native_retirement_census.c +++ b/tools/native_retirement_census.c @@ -35,10 +35,10 @@ BUSTER_GLOBAL_LOCAL u64 const nrc_full_input_count = 558; BUSTER_GLOBAL_LOCAL u64 const nrc_full_subject_count = 410; BUSTER_GLOBAL_LOCAL u64 const nrc_full_group_count = 19680; BUSTER_GLOBAL_LOCAL u64 const nrc_full_row_count = 78720; -BUSTER_GLOBAL_LOCAL String8 const nrc_dependency_descriptor_sha256 = S8_INITIALIZER("514f4611b44211a1184ec5a029f4278b07f8964179f670b44f4cc39dfce1df0d"); -BUSTER_GLOBAL_LOCAL String8 const nrc_dependency_receipt_sha256 = S8_INITIALIZER("c0f9044a60f987f476353dee297324d9cf0afe4124f078252edd772491a8ad58"); -BUSTER_GLOBAL_LOCAL String8 const nrc_dependency_project_sha256 = S8_INITIALIZER("66bdfb46423045ca112f92e98fb1da013d93e8e6f26a30be50f35205a3a0f8b1"); -BUSTER_GLOBAL_LOCAL String8 const nrc_dependency_ledger_sha256 = S8_INITIALIZER("7f3472bdefc8a998c935a972786b82862e2c3bb8b7f66dec6504ce055df69ffa"); +BUSTER_GLOBAL_LOCAL String8 const nrc_dependency_descriptor_sha256 = S8_INITIALIZER("33be3c1582858afb570298ae49db193293e7ec2008d3a6b85f03df3485dea803"); +BUSTER_GLOBAL_LOCAL String8 const nrc_dependency_receipt_sha256 = S8_INITIALIZER("dc14e25a42f9000071d46c776f43282852bcebbf392a91089afe6b7e46aed55d"); +BUSTER_GLOBAL_LOCAL String8 const nrc_dependency_project_sha256 = S8_INITIALIZER("542c978ad5f8252917fb0fd93cdd318ac8fcca9db14ffa1093edb606a8d637a2"); +BUSTER_GLOBAL_LOCAL String8 const nrc_dependency_ledger_sha256 = S8_INITIALIZER("fa98a21ebeeede091e8810034b315d12c66f629ba2d5e2c4225b5f96fc1ce48a"); BUSTER_GLOBAL_LOCAL String8 const nrc_archived_input_sha256 = S8_INITIALIZER("bef841ade0921ffe9293440171b1d0d8dd6c3cf798f2535d8790b4ad26542500"); BUSTER_GLOBAL_LOCAL String8 const nrc_archived_fixture_map_sha256 = S8_INITIALIZER("8d79504f67d48fd27698c6897b00fc9347dd60a538a6198e53e42970c799bc4f"); BUSTER_GLOBAL_LOCAL String8 const nrc_archived_row_sha256 = S8_INITIALIZER("9604102b75a14631aeb1d6a3652d36506a05928a0046c52cc50a00b942826ce6"); diff --git a/tools/native_retirement_contract.py b/tools/native_retirement_contract.py index ba78e967f..338a0c47f 100755 --- a/tools/native_retirement_contract.py +++ b/tools/native_retirement_contract.py @@ -46,10 +46,10 @@ APPLICABILITY_LEDGER_FIELDS = ("fixture", "target", "fixture_sha256", "applicability", "reason") FULL_APPLICABILITY_LEDGER_COUNT = 374 FULL_APPLICABILITY_LEDGER_SHA256 = "00cf09f1a58eb0fe8e44fbc1bd9e462a91df4449233c2b0c788442ec7a192a0c" -FULL_DEPENDENCY_DESCRIPTOR_SHA256 = "514f4611b44211a1184ec5a029f4278b07f8964179f670b44f4cc39dfce1df0d" -FULL_DEPENDENCY_RECEIPT_SHA256 = "c0f9044a60f987f476353dee297324d9cf0afe4124f078252edd772491a8ad58" -FULL_DEPENDENCY_PROJECT_SHA256 = "66bdfb46423045ca112f92e98fb1da013d93e8e6f26a30be50f35205a3a0f8b1" -FULL_DEPENDENCY_LEDGER_SHA256 = "7f3472bdefc8a998c935a972786b82862e2c3bb8b7f66dec6504ce055df69ffa" +FULL_DEPENDENCY_DESCRIPTOR_SHA256 = "33be3c1582858afb570298ae49db193293e7ec2008d3a6b85f03df3485dea803" +FULL_DEPENDENCY_RECEIPT_SHA256 = "dc14e25a42f9000071d46c776f43282852bcebbf392a91089afe6b7e46aed55d" +FULL_DEPENDENCY_PROJECT_SHA256 = "542c978ad5f8252917fb0fd93cdd318ac8fcca9db14ffa1093edb606a8d637a2" +FULL_DEPENDENCY_LEDGER_SHA256 = "fa98a21ebeeede091e8810034b315d12c66f629ba2d5e2c4225b5f96fc1ce48a" FULL_EXTERNAL_CHECKOUTS = ( {"name": "cjson", "repository": "DaveGamble/cJSON", "revision": "c859b25da02955fef659d658b8f324b5cde87be3", "path": "external/cjson"}, {"name": "doom", "repository": "ozkl/doomgeneric", "revision": "dcb7a8dbc7a16ce3dda29382ac9aae9d77d21284", "path": "external/doom"},