| ... | ... | @@ -473,11 +473,20 @@ fn finishAirWithBranchDeaths( |
| 473 | 473 | fn finishAirResult(cg: *CodeGen, inst: Air.Inst.Index, result: WValue) InnerError!void { |
| 474 | 474 | // results of `none` can never be referenced. |
| 475 | 475 | if (result != .none) { |
| 476 | | const trackable_result = if (result != .stack) |
| 477 | | result |
| 478 | | else |
| 479 | | try result.toLocal(cg, cg.typeOfIndex(inst)); |
| 480 | | try cg.values.putNoClobber(cg.gpa, inst.toRef(), trackable_result); |
| 476 | if (cg.liveness.isUnused(inst)) { |
| 477 | if (result == .stack) { |
| 478 | try cg.addTag(.drop); |
| 479 | } else { |
| 480 | var unused_result = result; |
| 481 | unused_result.free(cg); |
| 482 | } |
| 483 | } else { |
| 484 | const trackable_result = if (result != .stack) |
| 485 | result |
| 486 | else |
| 487 | try result.toLocal(cg, cg.typeOfIndex(inst)); |
| 488 | try cg.values.putNoClobber(cg.gpa, inst.toRef(), trackable_result); |
| 489 | } |
| 481 | 490 | } |
| 482 | 491 | |
| 483 | 492 | if (std.debug.runtime_safety) { |
| ... | ... | @@ -510,6 +519,27 @@ fn processDeath(cg: *CodeGen, ref: Air.Inst.Ref) void { |
| 510 | 519 | cg.releaseLocal(value.local); |
| 511 | 520 | } |
| 512 | 521 | |
| 522 | fn verifyLocalPool(cg: *CodeGen) void { |
| 523 | if (true) return; // TODO: test more |
| 524 | if (!std.debug.runtime_safety) return; |
| 525 | |
| 526 | var free_count: usize = 0; |
| 527 | for ([_]std.wasm.Valtype{ .i32, .i64, .f32, .f64, .v128 }) |valtype| { |
| 528 | var next = cg.local_pool.freeList(valtype).*; |
| 529 | while (next.unwrap()) |index| { |
| 530 | assert(index >= cg.wasm_param_count); |
| 531 | const pool_index = index - cg.wasm_param_count; |
| 532 | assert(pool_index < cg.local_pool.locals.items.len); |
| 533 | assert(index != cg.initial_stack_value.local); |
| 534 | assert(index != cg.bottom_stack_value.local); |
| 535 | assert(cg.mir_locals.items[pool_index] == valtype); |
| 536 | free_count += 1; |
| 537 | next = cg.local_pool.locals.items[pool_index].next_free; |
| 538 | } |
| 539 | } |
| 540 | assert(free_count + 2 == cg.local_pool.locals.items.len); |
| 541 | } |
| 542 | |
| 513 | 543 | pub fn addInst(cg: *CodeGen, inst: Mir.Inst) error{OutOfMemory}!void { |
| 514 | 544 | try cg.mir_instructions.append(cg.gpa, inst); |
| 515 | 545 | } |
| ... | ... | @@ -656,10 +686,8 @@ pub fn typeToValtype(ty: Type, zcu: *const Zcu, target: *const std.Target) std.w |
| 656 | 686 | /// Differently from `typeToValtype` this also allows `void` to create a block |
| 657 | 687 | /// with no return type |
| 658 | 688 | fn genBlockType(ty: Type, zcu: *const Zcu, target: *const std.Target) std.wasm.BlockType { |
| 659 | | return switch (ty.ip_index) { |
| 660 | | .void_type, .noreturn_type => .empty, |
| 661 | | else => .fromValtype(typeToValtype(ty, zcu, target)), |
| 662 | | }; |
| 689 | if (!ty.hasRuntimeBits(zcu)) return .empty; |
| 690 | return .fromValtype(typeToValtype(ty, zcu, target)); |
| 663 | 691 | } |
| 664 | 692 | |
| 665 | 693 | /// Returns `ptr` with `offset` applied. |
| ... | ... | @@ -1339,7 +1367,8 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 1339 | 1367 | |
| 1340 | 1368 | try cg.emitWValue(vec_ptr); |
| 1341 | 1369 | try cg.emitScaledPointerOffset(elem_idx, elem_size, .add); |
| 1342 | | const ptr = try WValue.toLocal(.stack, cg, Type.usize); |
| 1370 | var ptr = try WValue.toLocal(.stack, cg, Type.usize); |
| 1371 | defer ptr.free(cg); |
| 1343 | 1372 | |
| 1344 | 1373 | try cg.store(ptr, elem_val, elem_ty, .{}); |
| 1345 | 1374 | |
| ... | ... | @@ -1975,7 +2004,8 @@ fn airRet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 1975 | 2004 | try cg.restoreStackPointer(); |
| 1976 | 2005 | try cg.addTag(.@"return"); |
| 1977 | 2006 | |
| 1978 | | return cg.finishAir(inst, .none, &.{un_op}); |
| 2007 | try cg.finishAir(inst, .none, &.{un_op}); |
| 2008 | cg.verifyLocalPool(); |
| 1979 | 2009 | } |
| 1980 | 2010 | |
| 1981 | 2011 | fn airRetPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| ... | ... | @@ -2026,7 +2056,8 @@ fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2026 | 2056 | |
| 2027 | 2057 | try cg.restoreStackPointer(); |
| 2028 | 2058 | try cg.addTag(.@"return"); |
| 2029 | | return cg.finishAir(inst, .none, &.{un_op}); |
| 2059 | try cg.finishAir(inst, .none, &.{un_op}); |
| 2060 | cg.verifyLocalPool(); |
| 2030 | 2061 | } |
| 2031 | 2062 | |
| 2032 | 2063 | fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) InnerError!void { |
| ... | ... | @@ -2156,7 +2187,8 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) |
| 2156 | 2187 | try cg.addLocal(.local_set, result_local.local); |
| 2157 | 2188 | break :result_value result_local; |
| 2158 | 2189 | } else { |
| 2159 | | const result_local = try cg.allocLocal(scalar_type); |
| 2190 | var result_local = try cg.allocLocal(scalar_type); |
| 2191 | defer result_local.free(cg); |
| 2160 | 2192 | try cg.addLocal(.local_set, result_local.local); |
| 2161 | 2193 | const result = try cg.allocStack(ret_ty); |
| 2162 | 2194 | try cg.store(result, result_local, scalar_type, .{}); |
| ... | ... | @@ -2166,7 +2198,8 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) |
| 2166 | 2198 | .double_i64, .indirect => unreachable, |
| 2167 | 2199 | .unrolled => |vector| { |
| 2168 | 2200 | assert(vector.len == 1); |
| 2169 | | const result_local = try cg.allocLocal(vector.elem_type); |
| 2201 | var result_local = try cg.allocLocal(vector.elem_type); |
| 2202 | defer result_local.free(cg); |
| 2170 | 2203 | // save call result from operand stack |
| 2171 | 2204 | try cg.addLocal(.local_set, result_local.local); |
| 2172 | 2205 | const result = try cg.allocStack(ret_ty); |
| ... | ... | @@ -2223,7 +2256,8 @@ fn airVaArg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2223 | 2256 | const abi_size: u32 = @intCast(load_ty.abiSize(zcu)); |
| 2224 | 2257 | const abi_align: u32 = @intCast(load_ty.abiAlignment(zcu).toByteUnits().?); |
| 2225 | 2258 | |
| 2226 | | const arg_ptr = try cg.allocLocal(.usize); |
| 2259 | var arg_ptr = try cg.allocLocal(.usize); |
| 2260 | defer arg_ptr.free(cg); |
| 2227 | 2261 | _ = try cg.load(operand, .usize, .{}); |
| 2228 | 2262 | |
| 2229 | 2263 | if (abi_align > 1) { |
| ... | ... | @@ -3027,12 +3061,14 @@ fn intAnd(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue |
| 3027 | 3061 | |
| 3028 | 3062 | const lhs_lsb = try cg.load(lhs, .u64, .{}); |
| 3029 | 3063 | const rhs_lsb = try cg.load(rhs, .u64, .{}); |
| 3030 | | const and_lsb = try (try cg.intAnd(.u64, lhs_lsb, rhs_lsb)).toLocal(cg, Type.u64); |
| 3064 | var and_lsb = try (try cg.intAnd(.u64, lhs_lsb, rhs_lsb)).toLocal(cg, Type.u64); |
| 3065 | defer and_lsb.free(cg); |
| 3031 | 3066 | try cg.store(result, and_lsb, .u64, .{}); |
| 3032 | 3067 | |
| 3033 | 3068 | const lhs_msb = try cg.load(lhs, .u64, .{ .offset = 8 }); |
| 3034 | 3069 | const rhs_msb = try cg.load(rhs, .u64, .{ .offset = 8 }); |
| 3035 | | const and_msb = try (try cg.intAnd(.u64, lhs_msb, rhs_msb)).toLocal(cg, Type.u64); |
| 3070 | var and_msb = try (try cg.intAnd(.u64, lhs_msb, rhs_msb)).toLocal(cg, Type.u64); |
| 3071 | defer and_msb.free(cg); |
| 3036 | 3072 | try cg.store(result, and_msb, .u64, .{ .offset = 8 }); |
| 3037 | 3073 | |
| 3038 | 3074 | return result; |
| ... | ... | @@ -3071,12 +3107,14 @@ fn intOr(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue |
| 3071 | 3107 | |
| 3072 | 3108 | const lhs_lsb = try cg.load(lhs, .u64, .{}); |
| 3073 | 3109 | const rhs_lsb = try cg.load(rhs, .u64, .{}); |
| 3074 | | const or_lsb = try (try cg.intOr(.u64, lhs_lsb, rhs_lsb)).toLocal(cg, Type.u64); |
| 3110 | var or_lsb = try (try cg.intOr(.u64, lhs_lsb, rhs_lsb)).toLocal(cg, Type.u64); |
| 3111 | defer or_lsb.free(cg); |
| 3075 | 3112 | try cg.store(result, or_lsb, .u64, .{}); |
| 3076 | 3113 | |
| 3077 | 3114 | const lhs_msb = try cg.load(lhs, .u64, .{ .offset = 8 }); |
| 3078 | 3115 | const rhs_msb = try cg.load(rhs, .u64, .{ .offset = 8 }); |
| 3079 | | const or_msb = try (try cg.intOr(.u64, lhs_msb, rhs_msb)).toLocal(cg, Type.u64); |
| 3116 | var or_msb = try (try cg.intOr(.u64, lhs_msb, rhs_msb)).toLocal(cg, Type.u64); |
| 3117 | defer or_msb.free(cg); |
| 3080 | 3118 | try cg.store(result, or_msb, .u64, .{ .offset = 8 }); |
| 3081 | 3119 | |
| 3082 | 3120 | return result; |
| ... | ... | @@ -3115,12 +3153,14 @@ fn intXor(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue |
| 3115 | 3153 | |
| 3116 | 3154 | const lhs_lsb = try cg.load(lhs, .u64, .{}); |
| 3117 | 3155 | const rhs_lsb = try cg.load(rhs, .u64, .{}); |
| 3118 | | const xor_lsb = try (try cg.intXor(.u64, lhs_lsb, rhs_lsb)).toLocal(cg, Type.u64); |
| 3156 | var xor_lsb = try (try cg.intXor(.u64, lhs_lsb, rhs_lsb)).toLocal(cg, Type.u64); |
| 3157 | defer xor_lsb.free(cg); |
| 3119 | 3158 | try cg.store(result, xor_lsb, .u64, .{}); |
| 3120 | 3159 | |
| 3121 | 3160 | const lhs_msb = try cg.load(lhs, .u64, .{ .offset = 8 }); |
| 3122 | 3161 | const rhs_msb = try cg.load(rhs, .u64, .{ .offset = 8 }); |
| 3123 | | const xor_msb = try (try cg.intXor(.u64, lhs_msb, rhs_msb)).toLocal(cg, Type.u64); |
| 3162 | var xor_msb = try (try cg.intXor(.u64, lhs_msb, rhs_msb)).toLocal(cg, Type.u64); |
| 3163 | defer xor_msb.free(cg); |
| 3124 | 3164 | try cg.store(result, xor_msb, .u64, .{ .offset = 8 }); |
| 3125 | 3165 | |
| 3126 | 3166 | return result; |
| ... | ... | @@ -4103,6 +4143,19 @@ fn intSubOverflow(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerErro |
| 4103 | 4143 | } |
| 4104 | 4144 | |
| 4105 | 4145 | fn intMulOverflow(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError!OverflowResult { |
| 4146 | if (int_ty.bits > 64 and (int_ty.bits != 128 or !int_ty.is_signed)) { |
| 4147 | const result = try cg.allocInt(int_ty); |
| 4148 | |
| 4149 | try cg.emitWValue(result); |
| 4150 | try cg.emitWValue(lhs); |
| 4151 | try cg.emitWValue(rhs); |
| 4152 | try cg.addImm32(@intFromBool(int_ty.is_signed)); |
| 4153 | try cg.addImm32(int_ty.bits); |
| 4154 | try cg.addCallIntrinsic(.__mulo_limb64); |
| 4155 | |
| 4156 | return .{ .result = result, .ov = .stack }; |
| 4157 | } |
| 4158 | |
| 4106 | 4159 | const overflow_bit = try cg.allocLocal(Type.u32); |
| 4107 | 4160 | try cg.addImm32(0); |
| 4108 | 4161 | try cg.addLocal(.local_set, overflow_bit.local); |
| ... | ... | @@ -4112,7 +4165,8 @@ fn intMulOverflow(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) Inner |
| 4112 | 4165 | const lhs_upcast = try cg.intCast(new_ty, int_ty, lhs); |
| 4113 | 4166 | const rhs_upcast = try cg.intCast(new_ty, int_ty, rhs); |
| 4114 | 4167 | const mul_raw = try cg.intMul(new_ty, lhs_upcast, rhs_upcast); |
| 4115 | | const bin_op = try cg.toLocalInt(mul_raw, new_ty); |
| 4168 | var bin_op = try cg.toLocalInt(mul_raw, new_ty); |
| 4169 | defer bin_op.free(cg); |
| 4116 | 4170 | |
| 4117 | 4171 | const res = try cg.intTrunc(int_ty, new_ty, bin_op); |
| 4118 | 4172 | const res_tmp = try cg.toLocalInt(res, int_ty); |
| ... | ... | @@ -4126,7 +4180,8 @@ fn intMulOverflow(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) Inner |
| 4126 | 4180 | const lhs_upcast = try cg.intCast(new_ty, int_ty, lhs); |
| 4127 | 4181 | const rhs_upcast = try cg.intCast(new_ty, int_ty, rhs); |
| 4128 | 4182 | const mul_raw = try cg.intMul(new_ty, lhs_upcast, rhs_upcast); |
| 4129 | | const bin_op = try cg.toLocalInt(mul_raw, new_ty); |
| 4183 | var bin_op = try cg.toLocalInt(mul_raw, new_ty); |
| 4184 | defer bin_op.free(cg); |
| 4130 | 4185 | |
| 4131 | 4186 | const res = try cg.intTrunc(int_ty, new_ty, bin_op); |
| 4132 | 4187 | const res_tmp = try cg.toLocalInt(res, int_ty); |
| ... | ... | @@ -4135,7 +4190,8 @@ fn intMulOverflow(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) Inner |
| 4135 | 4190 | _ = try cg.intCmp(new_ty, .neq, res_upcast, bin_op); |
| 4136 | 4191 | try cg.addLocal(.local_set, overflow_bit.local); |
| 4137 | 4192 | break :blk res_tmp; |
| 4138 | | } else if (int_ty.bits == 128 and int_ty.is_signed) blk: { |
| 4193 | } else blk: { |
| 4194 | assert(int_ty.bits == 128 and int_ty.is_signed); |
| 4139 | 4195 | const overflow_ret = try cg.allocStack(Type.i32); |
| 4140 | 4196 | const res = try cg.callIntrinsic( |
| 4141 | 4197 | .__muloti4, |
| ... | ... | @@ -4146,17 +4202,6 @@ fn intMulOverflow(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) Inner |
| 4146 | 4202 | _ = try cg.load(overflow_ret, .i32, .{}); |
| 4147 | 4203 | try cg.addLocal(.local_set, overflow_bit.local); |
| 4148 | 4204 | break :blk res; |
| 4149 | | } else { |
| 4150 | | const result = try cg.allocInt(int_ty); |
| 4151 | | |
| 4152 | | try cg.emitWValue(result); |
| 4153 | | try cg.emitWValue(lhs); |
| 4154 | | try cg.emitWValue(rhs); |
| 4155 | | try cg.addImm32(@intFromBool(int_ty.is_signed)); |
| 4156 | | try cg.addImm32(int_ty.bits); |
| 4157 | | try cg.addCallIntrinsic(.__mulo_limb64); |
| 4158 | | |
| 4159 | | return .{ .result = result, .ov = .stack }; |
| 4160 | 4205 | }; |
| 4161 | 4206 | |
| 4162 | 4207 | return .{ .result = result_val, .ov = .{ .local = overflow_bit.local } }; |
| ... | ... | @@ -5212,13 +5257,19 @@ fn airBlock(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5212 | 5257 | |
| 5213 | 5258 | fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, block_ty: Type, body: []const Air.Inst.Index) InnerError!void { |
| 5214 | 5259 | const zcu = cg.pt.zcu; |
| 5215 | | // if wasm_block_ty is non-empty, we create a register to store the temporary value |
| 5260 | |
| 5261 | if (block_ty.isNoReturn(zcu)) { |
| 5262 | assert(cg.liveness.getBlock(inst).deaths.len == 0); |
| 5263 | try cg.genBody(body); |
| 5264 | return cg.finishAir(inst, .none, &.{}); |
| 5265 | } |
| 5266 | |
| 5216 | 5267 | const block_result: WValue = if (block_ty.hasRuntimeBits(zcu)) |
| 5217 | | try cg.allocLocal(block_ty) |
| 5268 | .stack |
| 5218 | 5269 | else |
| 5219 | 5270 | .none; |
| 5220 | 5271 | |
| 5221 | | try cg.startBlock(.block, .empty); |
| 5272 | try cg.startBlock(.block, genBlockType(block_ty, zcu, cg.target)); |
| 5222 | 5273 | // Here we set the current block idx, so breaks know the depth to jump |
| 5223 | 5274 | // to when breaking out. |
| 5224 | 5275 | try cg.blocks.putNoClobber(cg.gpa, inst, .{ |
| ... | ... | @@ -5266,6 +5317,7 @@ fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5266 | 5317 | |
| 5267 | 5318 | try cg.genBody(block.body); |
| 5268 | 5319 | try cg.endBlock(); |
| 5320 | try cg.addTag(.@"unreachable"); |
| 5269 | 5321 | |
| 5270 | 5322 | return cg.finishAir(inst, .none, &.{}); |
| 5271 | 5323 | } |
| ... | ... | @@ -5557,11 +5609,13 @@ fn airBr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5557 | 5609 | const br = cg.air.instructions.items(.data)[@backingInt(inst)].br; |
| 5558 | 5610 | const block = cg.blocks.get(br.block_inst).?; |
| 5559 | 5611 | |
| 5560 | | // if operand has codegen bits we should break with a value |
| 5561 | | if (block.value != .none) { |
| 5562 | | const operand = try cg.resolveInst(br.operand); |
| 5563 | | try cg.emitWValue(operand); |
| 5564 | | try cg.addLocal(.local_set, block.value.local); |
| 5612 | switch (block.value) { |
| 5613 | .none => {}, |
| 5614 | .stack => { |
| 5615 | const operand = try cg.resolveInst(br.operand); |
| 5616 | try cg.emitWValue(operand); |
| 5617 | }, |
| 5618 | else => unreachable, |
| 5565 | 5619 | } |
| 5566 | 5620 | |
| 5567 | 5621 | // We map every block to its block index. |
| ... | ... | @@ -5584,7 +5638,8 @@ fn airRepeat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5584 | 5638 | |
| 5585 | 5639 | fn airTrap(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5586 | 5640 | try cg.addTag(.@"unreachable"); |
| 5587 | | return cg.finishAir(inst, .none, &.{}); |
| 5641 | try cg.finishAir(inst, .none, &.{}); |
| 5642 | cg.verifyLocalPool(); |
| 5588 | 5643 | } |
| 5589 | 5644 | |
| 5590 | 5645 | fn airBreakpoint(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| ... | ... | @@ -5596,7 +5651,8 @@ fn airBreakpoint(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5596 | 5651 | |
| 5597 | 5652 | fn airUnreachable(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5598 | 5653 | try cg.addTag(.@"unreachable"); |
| 5599 | | return cg.finishAir(inst, .none, &.{}); |
| 5654 | try cg.finishAir(inst, .none, &.{}); |
| 5655 | cg.verifyLocalPool(); |
| 5600 | 5656 | } |
| 5601 | 5657 | |
| 5602 | 5658 | fn airNopCast(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| ... | ... | @@ -5839,6 +5895,7 @@ fn airAggFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5839 | 5895 | return cg.finishAir(inst, result, &.{struct_field.struct_operand}); |
| 5840 | 5896 | } |
| 5841 | 5897 | |
| 5898 | // Both `.switch_br` and `.loop_switch_br` are noreturn. |
| 5842 | 5899 | fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) InnerError!void { |
| 5843 | 5900 | const pt = cg.pt; |
| 5844 | 5901 | const zcu = pt.zcu; |
| ... | ... | @@ -5850,9 +5907,9 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner |
| 5850 | 5907 | |
| 5851 | 5908 | assert(target_ty.hasRuntimeBits(zcu)); |
| 5852 | 5909 | |
| 5853 | | // swap target value with placeholder local, for dispatching |
| 5910 | const operand_dies = cg.liveness.operandDies(inst, 0); |
| 5854 | 5911 | var owned_target: WValue = .none; |
| 5855 | | defer owned_target.free(cg); |
| 5912 | errdefer owned_target.free(cg); |
| 5856 | 5913 | const target = if (is_dispatch_loop) target: { |
| 5857 | 5914 | const initial_target = try cg.resolveInst(switch_br.operand); |
| 5858 | 5915 | owned_target = try cg.allocLocal(target_ty); |
| ... | ... | @@ -5879,7 +5936,8 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner |
| 5879 | 5936 | var it = switch_br.iterateCases(); |
| 5880 | 5937 | const else_body = it.elseBody(); |
| 5881 | 5938 | |
| 5882 | | if (cg.liveness.operandDies(inst, 0)) cg.processDeath(switch_br.operand); |
| 5939 | if (operand_dies) cg.processDeath(switch_br.operand); |
| 5940 | owned_target.free(cg); |
| 5883 | 5941 | |
| 5884 | 5942 | { |
| 5885 | 5943 | try cg.pushBranch(); |
| ... | ... | @@ -5890,6 +5948,7 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner |
| 5890 | 5948 | |
| 5891 | 5949 | if (is_dispatch_loop) { |
| 5892 | 5950 | try cg.endBlock(); // dispatch loop end |
| 5951 | try cg.addTag(.@"unreachable"); |
| 5893 | 5952 | } |
| 5894 | 5953 | return cg.finishAir(inst, .none, &.{}); |
| 5895 | 5954 | } |
| ... | ... | @@ -5934,8 +5993,6 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner |
| 5934 | 5993 | break :width width_bigint.toConst().toInt(u32) catch null; |
| 5935 | 5994 | }; |
| 5936 | 5995 | |
| 5937 | | try cg.startBlock(.block, .empty); // whole switch block start |
| 5938 | | |
| 5939 | 5996 | for (0..branch_count) |_| { |
| 5940 | 5997 | try cg.startBlock(.block, .empty); |
| 5941 | 5998 | } |
| ... | ... | @@ -6010,7 +6067,8 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner |
| 6010 | 6067 | try cg.addLabel(.br, branch_count - 1); |
| 6011 | 6068 | } |
| 6012 | 6069 | |
| 6013 | | if (cg.liveness.operandDies(inst, 0)) cg.processDeath(switch_br.operand); |
| 6070 | if (operand_dies) cg.processDeath(switch_br.operand); |
| 6071 | owned_target.free(cg); |
| 6014 | 6072 | |
| 6015 | 6073 | var cases_it = switch_br.iterateCases(); |
| 6016 | 6074 | while (cases_it.next()) |case| { |
| ... | ... | @@ -6022,8 +6080,6 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner |
| 6022 | 6080 | for (branch_liveness.deaths[case.idx]) |death| cg.processDeath(death.toRef()); |
| 6023 | 6081 | try cg.genBody(case.body); |
| 6024 | 6082 | } |
| 6025 | | |
| 6026 | | try cg.addLabel(.br, branch_count - case.idx - 1); // matching case found and executed => exit switch |
| 6027 | 6083 | } |
| 6028 | 6084 | |
| 6029 | 6085 | try cg.endBlock(); |
| ... | ... | @@ -6040,10 +6096,9 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner |
| 6040 | 6096 | try cg.addTag(.@"unreachable"); |
| 6041 | 6097 | } |
| 6042 | 6098 | |
| 6043 | | try cg.endBlock(); // whole switch block end |
| 6044 | | |
| 6045 | 6099 | if (is_dispatch_loop) { |
| 6046 | 6100 | try cg.endBlock(); // dispatch loop end |
| 6101 | try cg.addTag(.@"unreachable"); |
| 6047 | 6102 | } |
| 6048 | 6103 | |
| 6049 | 6104 | return cg.finishAir(inst, .none, &.{}); |
| ... | ... | @@ -6547,11 +6602,6 @@ fn airMemset(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void { |
| 6547 | 6602 | const ptr = try cg.resolveInst(bin_op.lhs); |
| 6548 | 6603 | const ptr_ty = cg.typeOf(bin_op.lhs); |
| 6549 | 6604 | const value = try cg.resolveInst(bin_op.rhs); |
| 6550 | | const len = switch (ptr_ty.ptrSize(zcu)) { |
| 6551 | | .slice => try cg.sliceLen(ptr), |
| 6552 | | .one => @as(WValue, .{ .imm32 = @as(u32, @intCast(ptr_ty.childType(zcu).arrayLen(zcu))) }), |
| 6553 | | .c, .many => unreachable, |
| 6554 | | }; |
| 6555 | 6605 | |
| 6556 | 6606 | const elem_ty = if (ptr_ty.ptrSize(zcu) == .one) |
| 6557 | 6607 | ptr_ty.childType(zcu).childType(zcu) |
| ... | ... | @@ -6562,7 +6612,14 @@ fn airMemset(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void { |
| 6562 | 6612 | return cg.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs }); |
| 6563 | 6613 | } |
| 6564 | 6614 | |
| 6565 | | const dst_ptr = try cg.sliceOrArrayPtr(ptr, ptr_ty); |
| 6615 | var dst_ptr = try cg.sliceOrArrayPtr(ptr, ptr_ty); |
| 6616 | defer if (ptr_ty.isSlice(zcu)) dst_ptr.free(cg); |
| 6617 | var len = switch (ptr_ty.ptrSize(zcu)) { |
| 6618 | .slice => try cg.sliceLen(ptr), |
| 6619 | .one => @as(WValue, .{ .imm32 = @as(u32, @intCast(ptr_ty.childType(zcu).arrayLen(zcu))) }), |
| 6620 | .c, .many => unreachable, |
| 6621 | }; |
| 6622 | defer len.free(cg); |
| 6566 | 6623 | try cg.memset(elem_ty, dst_ptr, len, value); |
| 6567 | 6624 | |
| 6568 | 6625 | return cg.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs }); |
| ... | ... | @@ -6614,11 +6671,13 @@ fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue) |
| 6614 | 6671 | return; |
| 6615 | 6672 | } |
| 6616 | 6673 | |
| 6674 | var owned_final_len: WValue = .none; |
| 6675 | defer owned_final_len.free(cg); |
| 6617 | 6676 | const final_len: WValue = switch (len) { |
| 6618 | 6677 | .imm32 => |val| .{ .imm32 = val * abi_size }, |
| 6619 | 6678 | .imm64 => |val| .{ .imm64 = val * abi_size }, |
| 6620 | 6679 | else => if (abi_size != 1) blk: { |
| 6621 | | const new_len = try cg.ensureAllocLocal(Type.usize); |
| 6680 | owned_final_len = try cg.allocLocal(Type.usize); |
| 6622 | 6681 | try cg.emitWValue(len); |
| 6623 | 6682 | switch (cg.ptr_size) { |
| 6624 | 6683 | .wasm32 => { |
| ... | ... | @@ -6630,8 +6689,8 @@ fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue) |
| 6630 | 6689 | try cg.addTag(.i64_mul); |
| 6631 | 6690 | }, |
| 6632 | 6691 | } |
| 6633 | | try cg.addLocal(.local_set, new_len.local); |
| 6634 | | break :blk new_len; |
| 6692 | try cg.addLocal(.local_set, owned_final_len.local); |
| 6693 | break :blk owned_final_len; |
| 6635 | 6694 | } else len, |
| 6636 | 6695 | }; |
| 6637 | 6696 | |
| ... | ... | @@ -7179,7 +7238,7 @@ fn airMemcpy(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7179 | 7238 | const ptr_elem_ty = dst_ty.childType(zcu); |
| 7180 | 7239 | const src = try cg.resolveInst(bin_op.rhs); |
| 7181 | 7240 | const src_ty = cg.typeOf(bin_op.rhs); |
| 7182 | | const len = switch (dst_ty.ptrSize(zcu)) { |
| 7241 | var len = switch (dst_ty.ptrSize(zcu)) { |
| 7183 | 7242 | .slice => blk: { |
| 7184 | 7243 | const slice_len = try cg.sliceLen(dst); |
| 7185 | 7244 | if (ptr_elem_ty.abiSize(zcu) != 1) { |
| ... | ... | @@ -7195,8 +7254,11 @@ fn airMemcpy(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7195 | 7254 | }), |
| 7196 | 7255 | .c, .many => unreachable, |
| 7197 | 7256 | }; |
| 7198 | | const dst_ptr = try cg.sliceOrArrayPtr(dst, dst_ty); |
| 7199 | | const src_ptr = try cg.sliceOrArrayPtr(src, src_ty); |
| 7257 | defer len.free(cg); |
| 7258 | var dst_ptr = try cg.sliceOrArrayPtr(dst, dst_ty); |
| 7259 | defer if (dst_ty.isSlice(zcu)) dst_ptr.free(cg); |
| 7260 | var src_ptr = try cg.sliceOrArrayPtr(src, src_ty); |
| 7261 | defer if (src_ty.isSlice(zcu)) src_ptr.free(cg); |
| 7200 | 7262 | try cg.memcpy(dst_ptr, src_ptr, len); |
| 7201 | 7263 | |
| 7202 | 7264 | return cg.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs }); |
| ... | ... | @@ -7210,7 +7272,7 @@ fn airMemmove(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7210 | 7272 | const ptr_elem_ty = dst_ty.childType(zcu); |
| 7211 | 7273 | const src = try cg.resolveInst(bin_op.rhs); |
| 7212 | 7274 | const src_ty = cg.typeOf(bin_op.rhs); |
| 7213 | | const len = switch (dst_ty.ptrSize(zcu)) { |
| 7275 | var len = switch (dst_ty.ptrSize(zcu)) { |
| 7214 | 7276 | .slice => blk: { |
| 7215 | 7277 | const slice_len = try cg.sliceLen(dst); |
| 7216 | 7278 | if (ptr_elem_ty.abiSize(zcu) != 1) { |
| ... | ... | @@ -7226,8 +7288,11 @@ fn airMemmove(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7226 | 7288 | }), |
| 7227 | 7289 | .c, .many => unreachable, |
| 7228 | 7290 | }; |
| 7229 | | const dst_ptr = try cg.sliceOrArrayPtr(dst, dst_ty); |
| 7230 | | const src_ptr = try cg.sliceOrArrayPtr(src, src_ty); |
| 7291 | defer len.free(cg); |
| 7292 | var dst_ptr = try cg.sliceOrArrayPtr(dst, dst_ty); |
| 7293 | defer if (dst_ty.isSlice(zcu)) dst_ptr.free(cg); |
| 7294 | var src_ptr = try cg.sliceOrArrayPtr(src, src_ty); |
| 7295 | defer if (src_ty.isSlice(zcu)) src_ptr.free(cg); |
| 7231 | 7296 | try cg.memmove(dst_ptr, src_ptr, len); |
| 7232 | 7297 | |
| 7233 | 7298 | return cg.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs }); |
| ... | ... | @@ -7295,7 +7360,8 @@ fn airDbgVar( |
| 7295 | 7360 | ) InnerError!void { |
| 7296 | 7361 | _ = is_ptr; |
| 7297 | 7362 | _ = local_tag; |
| 7298 | | return cg.finishAir(inst, .none, &.{}); |
| 7363 | const pl_op = cg.air.instructions.items(.data)[@backingInt(inst)].pl_op; |
| 7364 | return cg.finishAir(inst, .none, &.{pl_op.operand}); |
| 7299 | 7365 | } |
| 7300 | 7366 | |
| 7301 | 7367 | fn airTry(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| ... | ... | @@ -7555,9 +7621,10 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7555 | 7621 | const expected_val = try cg.resolveInst(extra.expected_value); |
| 7556 | 7622 | const new_val = try cg.resolveInst(extra.new_value); |
| 7557 | 7623 | |
| 7558 | | const cmp_result = try cg.allocLocal(Type.bool); |
| 7624 | var cmp_result = try cg.allocLocal(Type.bool); |
| 7625 | defer cmp_result.free(cg); |
| 7559 | 7626 | |
| 7560 | | const ptr_val = if (cg.useAtomicFeature()) val: { |
| 7627 | var ptr_val = if (cg.useAtomicFeature()) val: { |
| 7561 | 7628 | const val_local = try cg.allocLocal(ty); |
| 7562 | 7629 | try cg.emitMemBase(ptr_operand); |
| 7563 | 7630 | try cg.emitWValue(expected_val); |
| ... | ... | @@ -7599,7 +7666,8 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7599 | 7666 | try cg.addTag(.i32_xor); |
| 7600 | 7667 | try cg.addImm32(1); |
| 7601 | 7668 | try cg.addTag(.i32_and); |
| 7602 | | const and_result = try WValue.toLocal(.stack, cg, Type.bool); |
| 7669 | var and_result = try WValue.toLocal(.stack, cg, Type.bool); |
| 7670 | defer and_result.free(cg); |
| 7603 | 7671 | const result_ptr = try cg.allocStack(result_ty); |
| 7604 | 7672 | try cg.store(result_ptr, and_result, .bool, .{ .offset = ty.abiSize(zcu) }); |
| 7605 | 7673 | try cg.store(result_ptr, ptr_val, ty, .{}); |
| ... | ... | @@ -7611,6 +7679,7 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7611 | 7679 | try cg.addTag(.select); |
| 7612 | 7680 | break :val .stack; |
| 7613 | 7681 | }; |
| 7682 | defer ptr_val.free(cg); |
| 7614 | 7683 | |
| 7615 | 7684 | return cg.finishAir(inst, result, &.{ extra.ptr, extra.expected_value, extra.new_value }); |
| 7616 | 7685 | } |
| ... | ... | @@ -7695,7 +7764,8 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7695 | 7764 | .alignment = ty.abiAlignment(zcu).toStdMem(), |
| 7696 | 7765 | }, |
| 7697 | 7766 | ); |
| 7698 | | const select_res = try cg.allocLocal(ty); |
| 7767 | var select_res = try cg.allocLocal(ty); |
| 7768 | defer select_res.free(cg); |
| 7699 | 7769 | try cg.addLocal(.local_tee, select_res.local); |
| 7700 | 7770 | _ = try cg.intCmp(int_ty, .neq, .stack, value); // leave on stack so we can use it for br_if |
| 7701 | 7771 | |
| ... | ... | @@ -7908,6 +7978,11 @@ fn airAsm(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7908 | 7978 | if (unwrapped_asm.source.len != 0) { |
| 7909 | 7979 | var local_map: assembly.LocalMap = .empty; |
| 7910 | 7980 | defer local_map.deinit(cg.gpa); |
| 7981 | var input_locals: std.ArrayList(WValue) = try .initCapacity(cg.gpa, inputs.len); |
| 7982 | defer { |
| 7983 | for (input_locals.items) |*input_local| input_local.free(cg); |
| 7984 | input_locals.deinit(cg.gpa); |
| 7985 | } |
| 7911 | 7986 | |
| 7912 | 7987 | { |
| 7913 | 7988 | var it = unwrapped_asm.iterateOutputs(); |
| ... | ... | @@ -7940,6 +8015,7 @@ fn airAsm(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7940 | 8015 | |
| 7941 | 8016 | try cg.emitWValue(operand); |
| 7942 | 8017 | const op_local = try WValue.toLocal(.stack, cg, cg.typeOf(input.operand)); |
| 8018 | input_locals.appendAssumeCapacity(op_local); |
| 7943 | 8019 | |
| 7944 | 8020 | const gop = try local_map.getOrPutValue(cg.gpa, name, op_local.local); |
| 7945 | 8021 | if (gop.found_existing) { |