| ... | ... | @@ -3834,7 +3834,7 @@ fn airSliceElemVal(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 3834 | 3834 | try func.addTag(.i32_mul); |
| 3835 | 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 | 3838 | try func.addLabel(.local_set, result_ptr.local.value); |
| 3839 | 3839 | |
| 3840 | 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 | 4301 | } |
| 4302 | 4302 | break :result_value result; |
| 4303 | 4303 | }, |
| 4304 | | .Struct => { |
| 4305 | | const result = try func.allocStack(result_ty); |
| 4306 | | const offset = try func.buildPointerOffset(result, 0, .new); // pointer to offset |
| 4307 | | for (elements) |elem, elem_index| { |
| 4308 | | if (result_ty.structFieldValueComptime(elem_index) != null) continue; |
| 4304 | .Struct => switch (result_ty.containerLayout()) { |
| 4305 | .Packed => { |
| 4306 | if (isByRef(result_ty, func.target)) { |
| 4307 | return func.fail("TODO: airAggregateInit for packed structs larger than 64 bits", .{}); |
| 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); |
| 4311 | | const elem_size = @intCast(u32, elem_ty.abiSize(func.target)); |
| 4312 | | const value = try func.resolveInst(elem); |
| 4313 | | try func.store(offset, value, elem_ty, 0); |
| 4354 | const elem_ty = result_ty.structFieldType(elem_index); |
| 4355 | const elem_size = @intCast(u32, elem_ty.abiSize(func.target)); |
| 4356 | const value = try func.resolveInst(elem); |
| 4357 | try func.store(offset, value, elem_ty, 0); |
| 4314 | 4358 | |
| 4315 | | if (elem_index < elements.len - 1) { |
| 4316 | | _ = try func.buildPointerOffset(offset, elem_size, .modify); |
| 4359 | if (elem_index < elements.len - 1) { |
| 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 | 4367 | .Vector => return func.fail("TODO: Wasm backend: implement airAggregateInit for vectors", .{}), |
| 4323 | 4368 | else => unreachable, |