| ... | @@ -473,11 +473,20 @@ fn finishAirWithBranchDeaths( | ... | @@ -473,11 +473,20 @@ fn finishAirWithBranchDeaths( |
| 473 | fn finishAirResult(cg: *CodeGen, inst: Air.Inst.Index, result: WValue) InnerError!void { | 473 | fn finishAirResult(cg: *CodeGen, inst: Air.Inst.Index, result: WValue) InnerError!void { |
| 474 | // results of `none` can never be referenced. | 474 | // results of `none` can never be referenced. |
| 475 | if (result != .none) { | 475 | if (result != .none) { |
| 476 | const trackable_result = if (result != .stack) | 476 | if (cg.liveness.isUnused(inst)) { |
| 477 | result | 477 | if (result == .stack) { |
| 478 | else | 478 | try cg.addTag(.drop); |
| 479 | try result.toLocal(cg, cg.typeOfIndex(inst)); | 479 | } else { |
| 480 | try cg.values.putNoClobber(cg.gpa, inst.toRef(), trackable_result); | 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 | if (std.debug.runtime_safety) { | 492 | if (std.debug.runtime_safety) { |
| ... | @@ -510,6 +519,27 @@ fn processDeath(cg: *CodeGen, ref: Air.Inst.Ref) void { | ... | @@ -510,6 +519,27 @@ fn processDeath(cg: *CodeGen, ref: Air.Inst.Ref) void { |
| 510 | cg.releaseLocal(value.local); | 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 | pub fn addInst(cg: *CodeGen, inst: Mir.Inst) error{OutOfMemory}!void { | 543 | pub fn addInst(cg: *CodeGen, inst: Mir.Inst) error{OutOfMemory}!void { |
| 514 | try cg.mir_instructions.append(cg.gpa, inst); | 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,10 +686,8 @@ pub fn typeToValtype(ty: Type, zcu: *const Zcu, target: *const std.Target) std.w |
| 656 | /// Differently from `typeToValtype` this also allows `void` to create a block | 686 | /// Differently from `typeToValtype` this also allows `void` to create a block |
| 657 | /// with no return type | 687 | /// with no return type |
| 658 | fn genBlockType(ty: Type, zcu: *const Zcu, target: *const std.Target) std.wasm.BlockType { | 688 | fn genBlockType(ty: Type, zcu: *const Zcu, target: *const std.Target) std.wasm.BlockType { |
| 659 | return switch (ty.ip_index) { | 689 | if (!ty.hasRuntimeBits(zcu)) return .empty; |
| 660 | .void_type, .noreturn_type => .empty, | 690 | return .fromValtype(typeToValtype(ty, zcu, target)); |
| 661 | else => .fromValtype(typeToValtype(ty, zcu, target)), | | |
| 662 | }; | | |
| 663 | } | 691 | } |
| 664 | | 692 | |
| 665 | /// Returns `ptr` with `offset` applied. | 693 | /// Returns `ptr` with `offset` applied. |
| ... | @@ -1339,7 +1367,8 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -1339,7 +1367,8 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 1339 | | 1367 | |
| 1340 | try cg.emitWValue(vec_ptr); | 1368 | try cg.emitWValue(vec_ptr); |
| 1341 | try cg.emitScaledPointerOffset(elem_idx, elem_size, .add); | 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 | try cg.store(ptr, elem_val, elem_ty, .{}); | 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,7 +2004,8 @@ fn airRet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 1975 | try cg.restoreStackPointer(); | 2004 | try cg.restoreStackPointer(); |
| 1976 | try cg.addTag(.@"return"); | 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 | fn airRetPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 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,7 +2056,8 @@ fn airRetLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2026 | | 2056 | |
| 2027 | try cg.restoreStackPointer(); | 2057 | try cg.restoreStackPointer(); |
| 2028 | try cg.addTag(.@"return"); | 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 | fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) InnerError!void { | 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,7 +2187,8 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) |
| 2156 | try cg.addLocal(.local_set, result_local.local); | 2187 | try cg.addLocal(.local_set, result_local.local); |
| 2157 | break :result_value result_local; | 2188 | break :result_value result_local; |
| 2158 | } else { | 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 | try cg.addLocal(.local_set, result_local.local); | 2192 | try cg.addLocal(.local_set, result_local.local); |
| 2161 | const result = try cg.allocStack(ret_ty); | 2193 | const result = try cg.allocStack(ret_ty); |
| 2162 | try cg.store(result, result_local, scalar_type, .{}); | 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,7 +2198,8 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) |
| 2166 | .double_i64, .indirect => unreachable, | 2198 | .double_i64, .indirect => unreachable, |
| 2167 | .unrolled => |vector| { | 2199 | .unrolled => |vector| { |
| 2168 | assert(vector.len == 1); | 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 | // save call result from operand stack | 2203 | // save call result from operand stack |
| 2171 | try cg.addLocal(.local_set, result_local.local); | 2204 | try cg.addLocal(.local_set, result_local.local); |
| 2172 | const result = try cg.allocStack(ret_ty); | 2205 | const result = try cg.allocStack(ret_ty); |
| ... | @@ -2223,7 +2256,8 @@ fn airVaArg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -2223,7 +2256,8 @@ fn airVaArg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2223 | const abi_size: u32 = @intCast(load_ty.abiSize(zcu)); | 2256 | const abi_size: u32 = @intCast(load_ty.abiSize(zcu)); |
| 2224 | const abi_align: u32 = @intCast(load_ty.abiAlignment(zcu).toByteUnits().?); | 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 | _ = try cg.load(operand, .usize, .{}); | 2261 | _ = try cg.load(operand, .usize, .{}); |
| 2228 | | 2262 | |
| 2229 | if (abi_align > 1) { | 2263 | if (abi_align > 1) { |
| ... | @@ -3027,12 +3061,14 @@ fn intAnd(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue | ... | @@ -3027,12 +3061,14 @@ fn intAnd(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue |
| 3027 | | 3061 | |
| 3028 | const lhs_lsb = try cg.load(lhs, .u64, .{}); | 3062 | const lhs_lsb = try cg.load(lhs, .u64, .{}); |
| 3029 | const rhs_lsb = try cg.load(rhs, .u64, .{}); | 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 | try cg.store(result, and_lsb, .u64, .{}); | 3066 | try cg.store(result, and_lsb, .u64, .{}); |
| 3032 | | 3067 | |
| 3033 | const lhs_msb = try cg.load(lhs, .u64, .{ .offset = 8 }); | 3068 | const lhs_msb = try cg.load(lhs, .u64, .{ .offset = 8 }); |
| 3034 | const rhs_msb = try cg.load(rhs, .u64, .{ .offset = 8 }); | 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 | try cg.store(result, and_msb, .u64, .{ .offset = 8 }); | 3072 | try cg.store(result, and_msb, .u64, .{ .offset = 8 }); |
| 3037 | | 3073 | |
| 3038 | return result; | 3074 | return result; |
| ... | @@ -3071,12 +3107,14 @@ fn intOr(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue | ... | @@ -3071,12 +3107,14 @@ fn intOr(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue |
| 3071 | | 3107 | |
| 3072 | const lhs_lsb = try cg.load(lhs, .u64, .{}); | 3108 | const lhs_lsb = try cg.load(lhs, .u64, .{}); |
| 3073 | const rhs_lsb = try cg.load(rhs, .u64, .{}); | 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 | try cg.store(result, or_lsb, .u64, .{}); | 3112 | try cg.store(result, or_lsb, .u64, .{}); |
| 3076 | | 3113 | |
| 3077 | const lhs_msb = try cg.load(lhs, .u64, .{ .offset = 8 }); | 3114 | const lhs_msb = try cg.load(lhs, .u64, .{ .offset = 8 }); |
| 3078 | const rhs_msb = try cg.load(rhs, .u64, .{ .offset = 8 }); | 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 | try cg.store(result, or_msb, .u64, .{ .offset = 8 }); | 3118 | try cg.store(result, or_msb, .u64, .{ .offset = 8 }); |
| 3081 | | 3119 | |
| 3082 | return result; | 3120 | return result; |
| ... | @@ -3115,12 +3153,14 @@ fn intXor(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue | ... | @@ -3115,12 +3153,14 @@ fn intXor(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue |
| 3115 | | 3153 | |
| 3116 | const lhs_lsb = try cg.load(lhs, .u64, .{}); | 3154 | const lhs_lsb = try cg.load(lhs, .u64, .{}); |
| 3117 | const rhs_lsb = try cg.load(rhs, .u64, .{}); | 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 | try cg.store(result, xor_lsb, .u64, .{}); | 3158 | try cg.store(result, xor_lsb, .u64, .{}); |
| 3120 | | 3159 | |
| 3121 | const lhs_msb = try cg.load(lhs, .u64, .{ .offset = 8 }); | 3160 | const lhs_msb = try cg.load(lhs, .u64, .{ .offset = 8 }); |
| 3122 | const rhs_msb = try cg.load(rhs, .u64, .{ .offset = 8 }); | 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 | try cg.store(result, xor_msb, .u64, .{ .offset = 8 }); | 3164 | try cg.store(result, xor_msb, .u64, .{ .offset = 8 }); |
| 3125 | | 3165 | |
| 3126 | return result; | 3166 | return result; |
| ... | @@ -4103,6 +4143,19 @@ fn intSubOverflow(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerErro | ... | @@ -4103,6 +4143,19 @@ fn intSubOverflow(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerErro |
| 4103 | } | 4143 | } |
| 4104 | | 4144 | |
| 4105 | fn intMulOverflow(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError!OverflowResult { | 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 | const overflow_bit = try cg.allocLocal(Type.u32); | 4159 | const overflow_bit = try cg.allocLocal(Type.u32); |
| 4107 | try cg.addImm32(0); | 4160 | try cg.addImm32(0); |
| 4108 | try cg.addLocal(.local_set, overflow_bit.local); | 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,7 +4165,8 @@ fn intMulOverflow(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) Inner |
| 4112 | const lhs_upcast = try cg.intCast(new_ty, int_ty, lhs); | 4165 | const lhs_upcast = try cg.intCast(new_ty, int_ty, lhs); |
| 4113 | const rhs_upcast = try cg.intCast(new_ty, int_ty, rhs); | 4166 | const rhs_upcast = try cg.intCast(new_ty, int_ty, rhs); |
| 4114 | const mul_raw = try cg.intMul(new_ty, lhs_upcast, rhs_upcast); | 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 | const res = try cg.intTrunc(int_ty, new_ty, bin_op); | 4171 | const res = try cg.intTrunc(int_ty, new_ty, bin_op); |
| 4118 | const res_tmp = try cg.toLocalInt(res, int_ty); | 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,7 +4180,8 @@ fn intMulOverflow(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) Inner |
| 4126 | const lhs_upcast = try cg.intCast(new_ty, int_ty, lhs); | 4180 | const lhs_upcast = try cg.intCast(new_ty, int_ty, lhs); |
| 4127 | const rhs_upcast = try cg.intCast(new_ty, int_ty, rhs); | 4181 | const rhs_upcast = try cg.intCast(new_ty, int_ty, rhs); |
| 4128 | const mul_raw = try cg.intMul(new_ty, lhs_upcast, rhs_upcast); | 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 | const res = try cg.intTrunc(int_ty, new_ty, bin_op); | 4186 | const res = try cg.intTrunc(int_ty, new_ty, bin_op); |
| 4132 | const res_tmp = try cg.toLocalInt(res, int_ty); | 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,7 +4190,8 @@ fn intMulOverflow(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) Inner |
| 4135 | _ = try cg.intCmp(new_ty, .neq, res_upcast, bin_op); | 4190 | _ = try cg.intCmp(new_ty, .neq, res_upcast, bin_op); |
| 4136 | try cg.addLocal(.local_set, overflow_bit.local); | 4191 | try cg.addLocal(.local_set, overflow_bit.local); |
| 4137 | break :blk res_tmp; | 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 | const overflow_ret = try cg.allocStack(Type.i32); | 4195 | const overflow_ret = try cg.allocStack(Type.i32); |
| 4140 | const res = try cg.callIntrinsic( | 4196 | const res = try cg.callIntrinsic( |
| 4141 | .__muloti4, | 4197 | .__muloti4, |
| ... | @@ -4146,17 +4202,6 @@ fn intMulOverflow(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) Inner | ... | @@ -4146,17 +4202,6 @@ fn intMulOverflow(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) Inner |
| 4146 | _ = try cg.load(overflow_ret, .i32, .{}); | 4202 | _ = try cg.load(overflow_ret, .i32, .{}); |
| 4147 | try cg.addLocal(.local_set, overflow_bit.local); | 4203 | try cg.addLocal(.local_set, overflow_bit.local); |
| 4148 | break :blk res; | 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 | return .{ .result = result_val, .ov = .{ .local = overflow_bit.local } }; | 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,13 +5257,19 @@ fn airBlock(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5212 | | 5257 | |
| 5213 | fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, block_ty: Type, body: []const Air.Inst.Index) InnerError!void { | 5258 | fn lowerBlock(cg: *CodeGen, inst: Air.Inst.Index, block_ty: Type, body: []const Air.Inst.Index) InnerError!void { |
| 5214 | const zcu = cg.pt.zcu; | 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 | const block_result: WValue = if (block_ty.hasRuntimeBits(zcu)) | 5267 | const block_result: WValue = if (block_ty.hasRuntimeBits(zcu)) |
| 5217 | try cg.allocLocal(block_ty) | 5268 | .stack |
| 5218 | else | 5269 | else |
| 5219 | .none; | 5270 | .none; |
| 5220 | | 5271 | |
| 5221 | try cg.startBlock(.block, .empty); | 5272 | try cg.startBlock(.block, genBlockType(block_ty, zcu, cg.target)); |
| 5222 | // Here we set the current block idx, so breaks know the depth to jump | 5273 | // Here we set the current block idx, so breaks know the depth to jump |
| 5223 | // to when breaking out. | 5274 | // to when breaking out. |
| 5224 | try cg.blocks.putNoClobber(cg.gpa, inst, .{ | 5275 | try cg.blocks.putNoClobber(cg.gpa, inst, .{ |
| ... | @@ -5266,6 +5317,7 @@ fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5266,6 +5317,7 @@ fn airLoop(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5266 | | 5317 | |
| 5267 | try cg.genBody(block.body); | 5318 | try cg.genBody(block.body); |
| 5268 | try cg.endBlock(); | 5319 | try cg.endBlock(); |
| | 5320 | try cg.addTag(.@"unreachable"); |
| 5269 | | 5321 | |
| 5270 | return cg.finishAir(inst, .none, &.{}); | 5322 | return cg.finishAir(inst, .none, &.{}); |
| 5271 | } | 5323 | } |
| ... | @@ -5557,11 +5609,13 @@ fn airBr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5557,11 +5609,13 @@ fn airBr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5557 | const br = cg.air.instructions.items(.data)[@backingInt(inst)].br; | 5609 | const br = cg.air.instructions.items(.data)[@backingInt(inst)].br; |
| 5558 | const block = cg.blocks.get(br.block_inst).?; | 5610 | const block = cg.blocks.get(br.block_inst).?; |
| 5559 | | 5611 | |
| 5560 | // if operand has codegen bits we should break with a value | 5612 | switch (block.value) { |
| 5561 | if (block.value != .none) { | 5613 | .none => {}, |
| 5562 | const operand = try cg.resolveInst(br.operand); | 5614 | .stack => { |
| 5563 | try cg.emitWValue(operand); | 5615 | const operand = try cg.resolveInst(br.operand); |
| 5564 | try cg.addLocal(.local_set, block.value.local); | 5616 | try cg.emitWValue(operand); |
| | 5617 | }, |
| | 5618 | else => unreachable, |
| 5565 | } | 5619 | } |
| 5566 | | 5620 | |
| 5567 | // We map every block to its block index. | 5621 | // We map every block to its block index. |
| ... | @@ -5584,7 +5638,8 @@ fn airRepeat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5584,7 +5638,8 @@ fn airRepeat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5584 | | 5638 | |
| 5585 | fn airTrap(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 5639 | fn airTrap(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5586 | try cg.addTag(.@"unreachable"); | 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 | fn airBreakpoint(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 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,7 +5651,8 @@ fn airBreakpoint(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5596 | | 5651 | |
| 5597 | fn airUnreachable(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 5652 | fn airUnreachable(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5598 | try cg.addTag(.@"unreachable"); | 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 | fn airNopCast(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 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,6 +5895,7 @@ fn airAggFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5839 | return cg.finishAir(inst, result, &.{struct_field.struct_operand}); | 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 | fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) InnerError!void { | 5899 | fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) InnerError!void { |
| 5843 | const pt = cg.pt; | 5900 | const pt = cg.pt; |
| 5844 | const zcu = pt.zcu; | 5901 | const zcu = pt.zcu; |
| ... | @@ -5850,9 +5907,9 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner | ... | @@ -5850,9 +5907,9 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner |
| 5850 | | 5907 | |
| 5851 | assert(target_ty.hasRuntimeBits(zcu)); | 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 | var owned_target: WValue = .none; | 5911 | var owned_target: WValue = .none; |
| 5855 | defer owned_target.free(cg); | 5912 | errdefer owned_target.free(cg); |
| 5856 | const target = if (is_dispatch_loop) target: { | 5913 | const target = if (is_dispatch_loop) target: { |
| 5857 | const initial_target = try cg.resolveInst(switch_br.operand); | 5914 | const initial_target = try cg.resolveInst(switch_br.operand); |
| 5858 | owned_target = try cg.allocLocal(target_ty); | 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,7 +5936,8 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner |
| 5879 | var it = switch_br.iterateCases(); | 5936 | var it = switch_br.iterateCases(); |
| 5880 | const else_body = it.elseBody(); | 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 | try cg.pushBranch(); | 5943 | try cg.pushBranch(); |
| ... | @@ -5890,6 +5948,7 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner | ... | @@ -5890,6 +5948,7 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner |
| 5890 | | 5948 | |
| 5891 | if (is_dispatch_loop) { | 5949 | if (is_dispatch_loop) { |
| 5892 | try cg.endBlock(); // dispatch loop end | 5950 | try cg.endBlock(); // dispatch loop end |
| | 5951 | try cg.addTag(.@"unreachable"); |
| 5893 | } | 5952 | } |
| 5894 | return cg.finishAir(inst, .none, &.{}); | 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,8 +5993,6 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner |
| 5934 | break :width width_bigint.toConst().toInt(u32) catch null; | 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 | for (0..branch_count) |_| { | 5996 | for (0..branch_count) |_| { |
| 5940 | try cg.startBlock(.block, .empty); | 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,7 +6067,8 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner |
| 6010 | try cg.addLabel(.br, branch_count - 1); | 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 | var cases_it = switch_br.iterateCases(); | 6073 | var cases_it = switch_br.iterateCases(); |
| 6016 | while (cases_it.next()) |case| { | 6074 | while (cases_it.next()) |case| { |
| ... | @@ -6022,8 +6080,6 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner | ... | @@ -6022,8 +6080,6 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner |
| 6022 | for (branch_liveness.deaths[case.idx]) |death| cg.processDeath(death.toRef()); | 6080 | for (branch_liveness.deaths[case.idx]) |death| cg.processDeath(death.toRef()); |
| 6023 | try cg.genBody(case.body); | 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 | try cg.endBlock(); | 6085 | try cg.endBlock(); |
| ... | @@ -6040,10 +6096,9 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner | ... | @@ -6040,10 +6096,9 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner |
| 6040 | try cg.addTag(.@"unreachable"); | 6096 | try cg.addTag(.@"unreachable"); |
| 6041 | } | 6097 | } |
| 6042 | | 6098 | |
| 6043 | try cg.endBlock(); // whole switch block end | | |
| 6044 | | | |
| 6045 | if (is_dispatch_loop) { | 6099 | if (is_dispatch_loop) { |
| 6046 | try cg.endBlock(); // dispatch loop end | 6100 | try cg.endBlock(); // dispatch loop end |
| | 6101 | try cg.addTag(.@"unreachable"); |
| 6047 | } | 6102 | } |
| 6048 | | 6103 | |
| 6049 | return cg.finishAir(inst, .none, &.{}); | 6104 | return cg.finishAir(inst, .none, &.{}); |
| ... | @@ -6547,11 +6602,6 @@ fn airMemset(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void { | ... | @@ -6547,11 +6602,6 @@ fn airMemset(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void { |
| 6547 | const ptr = try cg.resolveInst(bin_op.lhs); | 6602 | const ptr = try cg.resolveInst(bin_op.lhs); |
| 6548 | const ptr_ty = cg.typeOf(bin_op.lhs); | 6603 | const ptr_ty = cg.typeOf(bin_op.lhs); |
| 6549 | const value = try cg.resolveInst(bin_op.rhs); | 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 | const elem_ty = if (ptr_ty.ptrSize(zcu) == .one) | 6606 | const elem_ty = if (ptr_ty.ptrSize(zcu) == .one) |
| 6557 | ptr_ty.childType(zcu).childType(zcu) | 6607 | ptr_ty.childType(zcu).childType(zcu) |
| ... | @@ -6562,7 +6612,14 @@ fn airMemset(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void { | ... | @@ -6562,7 +6612,14 @@ fn airMemset(cg: *CodeGen, inst: Air.Inst.Index, safety: bool) InnerError!void { |
| 6562 | return cg.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs }); | 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 | try cg.memset(elem_ty, dst_ptr, len, value); | 6623 | try cg.memset(elem_ty, dst_ptr, len, value); |
| 6567 | | 6624 | |
| 6568 | return cg.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs }); | 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,11 +6671,13 @@ fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue) |
| 6614 | return; | 6671 | return; |
| 6615 | } | 6672 | } |
| 6616 | | 6673 | |
| | 6674 | var owned_final_len: WValue = .none; |
| | 6675 | defer owned_final_len.free(cg); |
| 6617 | const final_len: WValue = switch (len) { | 6676 | const final_len: WValue = switch (len) { |
| 6618 | .imm32 => |val| .{ .imm32 = val * abi_size }, | 6677 | .imm32 => |val| .{ .imm32 = val * abi_size }, |
| 6619 | .imm64 => |val| .{ .imm64 = val * abi_size }, | 6678 | .imm64 => |val| .{ .imm64 = val * abi_size }, |
| 6620 | else => if (abi_size != 1) blk: { | 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 | try cg.emitWValue(len); | 6681 | try cg.emitWValue(len); |
| 6623 | switch (cg.ptr_size) { | 6682 | switch (cg.ptr_size) { |
| 6624 | .wasm32 => { | 6683 | .wasm32 => { |
| ... | @@ -6630,8 +6689,8 @@ fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue) | ... | @@ -6630,8 +6689,8 @@ fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue) |
| 6630 | try cg.addTag(.i64_mul); | 6689 | try cg.addTag(.i64_mul); |
| 6631 | }, | 6690 | }, |
| 6632 | } | 6691 | } |
| 6633 | try cg.addLocal(.local_set, new_len.local); | 6692 | try cg.addLocal(.local_set, owned_final_len.local); |
| 6634 | break :blk new_len; | 6693 | break :blk owned_final_len; |
| 6635 | } else len, | 6694 | } else len, |
| 6636 | }; | 6695 | }; |
| 6637 | | 6696 | |
| ... | @@ -7179,7 +7238,7 @@ fn airMemcpy(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7179,7 +7238,7 @@ fn airMemcpy(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7179 | const ptr_elem_ty = dst_ty.childType(zcu); | 7238 | const ptr_elem_ty = dst_ty.childType(zcu); |
| 7180 | const src = try cg.resolveInst(bin_op.rhs); | 7239 | const src = try cg.resolveInst(bin_op.rhs); |
| 7181 | const src_ty = cg.typeOf(bin_op.rhs); | 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 | .slice => blk: { | 7242 | .slice => blk: { |
| 7184 | const slice_len = try cg.sliceLen(dst); | 7243 | const slice_len = try cg.sliceLen(dst); |
| 7185 | if (ptr_elem_ty.abiSize(zcu) != 1) { | 7244 | if (ptr_elem_ty.abiSize(zcu) != 1) { |
| ... | @@ -7195,8 +7254,11 @@ fn airMemcpy(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7195,8 +7254,11 @@ fn airMemcpy(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7195 | }), | 7254 | }), |
| 7196 | .c, .many => unreachable, | 7255 | .c, .many => unreachable, |
| 7197 | }; | 7256 | }; |
| 7198 | const dst_ptr = try cg.sliceOrArrayPtr(dst, dst_ty); | 7257 | defer len.free(cg); |
| 7199 | const src_ptr = try cg.sliceOrArrayPtr(src, src_ty); | 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 | try cg.memcpy(dst_ptr, src_ptr, len); | 7262 | try cg.memcpy(dst_ptr, src_ptr, len); |
| 7201 | | 7263 | |
| 7202 | return cg.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs }); | 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,7 +7272,7 @@ fn airMemmove(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7210 | const ptr_elem_ty = dst_ty.childType(zcu); | 7272 | const ptr_elem_ty = dst_ty.childType(zcu); |
| 7211 | const src = try cg.resolveInst(bin_op.rhs); | 7273 | const src = try cg.resolveInst(bin_op.rhs); |
| 7212 | const src_ty = cg.typeOf(bin_op.rhs); | 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 | .slice => blk: { | 7276 | .slice => blk: { |
| 7215 | const slice_len = try cg.sliceLen(dst); | 7277 | const slice_len = try cg.sliceLen(dst); |
| 7216 | if (ptr_elem_ty.abiSize(zcu) != 1) { | 7278 | if (ptr_elem_ty.abiSize(zcu) != 1) { |
| ... | @@ -7226,8 +7288,11 @@ fn airMemmove(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7226,8 +7288,11 @@ fn airMemmove(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7226 | }), | 7288 | }), |
| 7227 | .c, .many => unreachable, | 7289 | .c, .many => unreachable, |
| 7228 | }; | 7290 | }; |
| 7229 | const dst_ptr = try cg.sliceOrArrayPtr(dst, dst_ty); | 7291 | defer len.free(cg); |
| 7230 | const src_ptr = try cg.sliceOrArrayPtr(src, src_ty); | 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 | try cg.memmove(dst_ptr, src_ptr, len); | 7296 | try cg.memmove(dst_ptr, src_ptr, len); |
| 7232 | | 7297 | |
| 7233 | return cg.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs }); | 7298 | return cg.finishAir(inst, .none, &.{ bin_op.lhs, bin_op.rhs }); |
| ... | @@ -7295,7 +7360,8 @@ fn airDbgVar( | ... | @@ -7295,7 +7360,8 @@ fn airDbgVar( |
| 7295 | ) InnerError!void { | 7360 | ) InnerError!void { |
| 7296 | _ = is_ptr; | 7361 | _ = is_ptr; |
| 7297 | _ = local_tag; | 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 | fn airTry(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 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,9 +7621,10 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7555 | const expected_val = try cg.resolveInst(extra.expected_value); | 7621 | const expected_val = try cg.resolveInst(extra.expected_value); |
| 7556 | const new_val = try cg.resolveInst(extra.new_value); | 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 | const val_local = try cg.allocLocal(ty); | 7628 | const val_local = try cg.allocLocal(ty); |
| 7562 | try cg.emitMemBase(ptr_operand); | 7629 | try cg.emitMemBase(ptr_operand); |
| 7563 | try cg.emitWValue(expected_val); | 7630 | try cg.emitWValue(expected_val); |
| ... | @@ -7599,7 +7666,8 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7599,7 +7666,8 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7599 | try cg.addTag(.i32_xor); | 7666 | try cg.addTag(.i32_xor); |
| 7600 | try cg.addImm32(1); | 7667 | try cg.addImm32(1); |
| 7601 | try cg.addTag(.i32_and); | 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 | const result_ptr = try cg.allocStack(result_ty); | 7671 | const result_ptr = try cg.allocStack(result_ty); |
| 7604 | try cg.store(result_ptr, and_result, .bool, .{ .offset = ty.abiSize(zcu) }); | 7672 | try cg.store(result_ptr, and_result, .bool, .{ .offset = ty.abiSize(zcu) }); |
| 7605 | try cg.store(result_ptr, ptr_val, ty, .{}); | 7673 | try cg.store(result_ptr, ptr_val, ty, .{}); |
| ... | @@ -7611,6 +7679,7 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7611,6 +7679,7 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7611 | try cg.addTag(.select); | 7679 | try cg.addTag(.select); |
| 7612 | break :val .stack; | 7680 | break :val .stack; |
| 7613 | }; | 7681 | }; |
| | 7682 | defer ptr_val.free(cg); |
| 7614 | | 7683 | |
| 7615 | return cg.finishAir(inst, result, &.{ extra.ptr, extra.expected_value, extra.new_value }); | 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,7 +7764,8 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7695 | .alignment = ty.abiAlignment(zcu).toStdMem(), | 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 | try cg.addLocal(.local_tee, select_res.local); | 7769 | try cg.addLocal(.local_tee, select_res.local); |
| 7700 | _ = try cg.intCmp(int_ty, .neq, .stack, value); // leave on stack so we can use it for br_if | 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,6 +7978,11 @@ fn airAsm(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7908 | if (unwrapped_asm.source.len != 0) { | 7978 | if (unwrapped_asm.source.len != 0) { |
| 7909 | var local_map: assembly.LocalMap = .empty; | 7979 | var local_map: assembly.LocalMap = .empty; |
| 7910 | defer local_map.deinit(cg.gpa); | 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 | var it = unwrapped_asm.iterateOutputs(); | 7988 | var it = unwrapped_asm.iterateOutputs(); |
| ... | @@ -7940,6 +8015,7 @@ fn airAsm(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7940,6 +8015,7 @@ fn airAsm(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7940 | | 8015 | |
| 7941 | try cg.emitWValue(operand); | 8016 | try cg.emitWValue(operand); |
| 7942 | const op_local = try WValue.toLocal(.stack, cg, cg.typeOf(input.operand)); | 8017 | const op_local = try WValue.toLocal(.stack, cg, cg.typeOf(input.operand)); |
| | 8018 | input_locals.appendAssumeCapacity(op_local); |
| 7943 | | 8019 | |
| 7944 | const gop = try local_map.getOrPutValue(cg.gpa, name, op_local.local); | 8020 | const gop = try local_map.getOrPutValue(cg.gpa, name, op_local.local); |
| 7945 | if (gop.found_existing) { | 8021 | if (gop.found_existing) { |