diff --git a/src/arch/riscv64/abi.zig b/src/arch/riscv64/abi.zig index 41a1850635..da74734de4 100644 --- a/src/arch/riscv64/abi.zig +++ b/src/arch/riscv64/abi.zig @@ -5,7 +5,7 @@ const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager; const Type = @import("../../type.zig").Type; const Module = @import("../../Module.zig"); -pub const Class = enum { memory, byval, integer, double_integer }; +pub const Class = enum { memory, byval, integer, double_integer, fields }; pub fn classifyType(ty: Type, mod: *Module) Class { const target = mod.getTarget(); @@ -19,6 +19,24 @@ pub fn classifyType(ty: Type, mod: *Module) Class { if (bit_size > max_byval_size) return .memory; return .byval; } + + if (std.Target.riscv.featureSetHas(target.cpu.features, .d)) fields: { + var any_fp = false; + var field_count: usize = 0; + for (0..ty.structFieldCount(mod)) |field_index| { + const field_ty = ty.structFieldType(field_index, mod); + if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; + if (field_ty.isRuntimeFloat()) + any_fp = true + else if (!field_ty.isAbiInt(mod)) + break :fields; + field_count += 1; + if (field_count > 2) break :fields; + } + std.debug.assert(field_count > 0 and field_count <= 2); + if (any_fp) return .fields; + } + // TODO this doesn't exactly match what clang produces but its better than nothing if (bit_size > max_byval_size) return .memory; if (bit_size > max_byval_size / 2) return .double_integer; diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 8706089a81..89803e62ec 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -10674,6 +10674,17 @@ fn lowerFnRetTy(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Bu return o.builder.structType(.normal, &.{ .i64, .i64 }); }, .byval => return o.lowerType(return_type), + .fields => { + var types_len: usize = 0; + var types: [8]Builder.Type = undefined; + for (0..return_type.structFieldCount(mod)) |field_index| { + const field_ty = return_type.structFieldType(field_index, mod); + if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; + types[types_len] = try o.lowerType(field_ty); + types_len += 1; + } + return o.builder.structType(.normal, types[0..types_len]); + }, } }, // TODO investigate C ABI for other architectures @@ -10887,14 +10898,24 @@ const ParamTypeIterator = struct { .riscv32, .riscv64 => { it.zig_index += 1; it.llvm_index += 1; - if (ty.toIntern() == .f16_type) { - return .as_u16; - } + if (ty.toIntern() == .f16_type and + !std.Target.riscv.featureSetHas(target.cpu.features, .d)) return .as_u16; switch (riscv_c_abi.classifyType(ty, mod)) { .memory => return .byref_mut, .byval => return .byval, .integer => return .abi_sized_int, .double_integer => return Lowering{ .i64_array = 2 }, + .fields => { + it.types_len = 0; + for (0..ty.structFieldCount(mod)) |field_index| { + const field_ty = ty.structFieldType(field_index, mod); + if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) continue; + it.types_buffer[it.types_len] = try it.object.lowerType(field_ty); + it.types_len += 1; + } + it.llvm_index += it.types_len - 1; + return .multiple_llvm_types; + }, } }, // TODO investigate C ABI for other architectures