| ... | @@ -3834,7 +3834,7 @@ fn airSliceElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -3834,7 +3834,7 @@ fn airSliceElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3834 | try func.addTag(.i32_mul); | 3834 | try func.addTag(.i32_mul); |
| 3835 | try func.addTag(.i32_add); | 3835 | try func.addTag(.i32_add); |
| 3836 | | 3836 | |
| 3837 | const result_ptr = try func.allocLocal(elem_ty); | 3837 | const result_ptr = try func.allocLocal(Type.usize); |
| 3838 | try func.addLabel(.local_set, result_ptr.local.value); | 3838 | try func.addLabel(.local_set, result_ptr.local.value); |
| 3839 | | 3839 | |
| 3840 | const result = if (!isByRef(elem_ty, func.target)) result: { | 3840 | const result = if (!isByRef(elem_ty, func.target)) result: { |
| ... | @@ -4301,23 +4301,68 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -4301,23 +4301,68 @@ fn airAggregateInit(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 4301 | } | 4301 | } |
| 4302 | break :result_value result; | 4302 | break :result_value result; |
| 4303 | }, | 4303 | }, |
| 4304 | .Struct => { | 4304 | .Struct => switch (result_ty.containerLayout()) { |
| 4305 | const result = try func.allocStack(result_ty); | 4305 | .Packed => { |
| 4306 | const offset = try func.buildPointerOffset(result, 0, .new); // pointer to offset | 4306 | if (isByRef(result_ty, func.target)) { |
| 4307 | for (elements) |elem, elem_index| { | 4307 | return func.fail("TODO: airAggregateInit for packed structs larger than 64 bits", .{}); |
| 4308 | if (result_ty.structFieldValueComptime(elem_index) != null) continue; | 4308 | } |
| | 4309 | const struct_obj = result_ty.castTag(.@"struct").?.data; |
| | 4310 | const fields = struct_obj.fields.values(); |
| | 4311 | const backing_type = struct_obj.backing_int_ty; |
| | 4312 | // we ensure a new local is created so it's zero-initialized |
| | 4313 | const result = try func.ensureAllocLocal(backing_type); |
| | 4314 | var current_bit: u16 = 0; |
| | 4315 | for (elements) |elem, elem_index| { |
| | 4316 | const field = fields[elem_index]; |
| | 4317 | if (!field.ty.hasRuntimeBitsIgnoreComptime()) continue; |
| | 4318 | |
| | 4319 | const shift_val = if (struct_obj.backing_int_ty.bitSize(func.target) <= 32) |
| | 4320 | WValue{ .imm32 = current_bit } |
| | 4321 | else |
| | 4322 | WValue{ .imm64 = current_bit }; |
| | 4323 | |
| | 4324 | const value = try func.resolveInst(elem); |
| | 4325 | const value_bit_size = @intCast(u16, field.ty.bitSize(func.target)); |
| | 4326 | var int_ty_payload: Type.Payload.Bits = .{ |
| | 4327 | .base = .{ .tag = .int_unsigned }, |
| | 4328 | .data = value_bit_size, |
| | 4329 | }; |
| | 4330 | const int_ty = Type.initPayload(&int_ty_payload.base); |
| | 4331 | |
| | 4332 | // load our current result on stack so we can perform all transformations |
| | 4333 | // using only stack values. Saving the cost of loads and stores. |
| | 4334 | try func.emitWValue(result); |
| | 4335 | const bitcasted = try func.bitcast(int_ty, field.ty, value); |
| | 4336 | const extended_val = try func.intcast(bitcasted, int_ty, backing_type); |
| | 4337 | // no need to shift any values when the current offset is 0 |
| | 4338 | const shifted = if (current_bit != 0) shifted: { |
| | 4339 | break :shifted try func.binOp(extended_val, shift_val, backing_type, .shl); |
| | 4340 | } else extended_val; |
| | 4341 | // we ignore the result as we keep it on the stack to assign it directly to `result` |
| | 4342 | _ = try func.binOp(.stack, shifted, backing_type, .@"or"); |
| | 4343 | try func.addLabel(.local_set, result.local.value); |
| | 4344 | current_bit += value_bit_size; |
| | 4345 | } |
| | 4346 | break :result_value result; |
| | 4347 | }, |
| | 4348 | else => { |
| | 4349 | const result = try func.allocStack(result_ty); |
| | 4350 | const offset = try func.buildPointerOffset(result, 0, .new); // pointer to offset |
| | 4351 | for (elements) |elem, elem_index| { |
| | 4352 | if (result_ty.structFieldValueComptime(elem_index) != null) continue; |
| 4309 | | 4353 | |
| 4310 | const elem_ty = result_ty.structFieldType(elem_index); | 4354 | const elem_ty = result_ty.structFieldType(elem_index); |
| 4311 | const elem_size = @intCast(u32, elem_ty.abiSize(func.target)); | 4355 | const elem_size = @intCast(u32, elem_ty.abiSize(func.target)); |
| 4312 | const value = try func.resolveInst(elem); | 4356 | const value = try func.resolveInst(elem); |
| 4313 | try func.store(offset, value, elem_ty, 0); | 4357 | try func.store(offset, value, elem_ty, 0); |
| 4314 | | 4358 | |
| 4315 | if (elem_index < elements.len - 1) { | 4359 | if (elem_index < elements.len - 1) { |
| 4316 | _ = try func.buildPointerOffset(offset, elem_size, .modify); | 4360 | _ = try func.buildPointerOffset(offset, elem_size, .modify); |
| | 4361 | } |
| 4317 | } | 4362 | } |
| 4318 | } | | |
| 4319 | | 4363 | |
| 4320 | break :result_value result; | 4364 | break :result_value result; |
| | 4365 | }, |
| 4321 | }, | 4366 | }, |
| 4322 | .Vector => return func.fail("TODO: Wasm backend: implement airAggregateInit for vectors", .{}), | 4367 | .Vector => return func.fail("TODO: Wasm backend: implement airAggregateInit for vectors", .{}), |
| 4323 | else => unreachable, | 4368 | else => unreachable, |