| ... | @@ -271,23 +271,16 @@ const WValue = union(enum) { | ... | @@ -271,23 +271,16 @@ const WValue = union(enum) { |
| 271 | /// pointing to where the value lives. | 271 | /// pointing to where the value lives. |
| 272 | stack_offset: struct { | 272 | stack_offset: struct { |
| 273 | /// Contains the actual value of the offset | 273 | /// Contains the actual value of the offset |
| 274 | value: u32, | 274 | value: u64, |
| 275 | /// The amount of instructions referencing this `WValue` | | |
| 276 | references: u32, | | |
| 277 | }, | 275 | }, |
| 278 | | 276 | |
| 279 | /// Returns the offset from the bottom of the stack. This is useful when | 277 | /// Returns the offset from the bottom of the stack. |
| 280 | /// we use the load or store instruction to ensure we retrieve the value | 278 | fn memOffset(value: WValue) u64 { |
| 281 | /// from the correct position, rather than the value that lives at the | 279 | return switch (value) { |
| 282 | /// bottom of the stack. For instances where `WValue` is not `stack_value` | 280 | .stack_offset => |stack_offset| stack_offset.value, |
| 283 | /// this will return 0, which allows us to simply call this function for all | | |
| 284 | /// loads and stores without requiring checks everywhere. | | |
| 285 | fn offset(value: WValue) u32 { | | |
| 286 | switch (value) { | | |
| 287 | .stack_offset => |stack_offset| return stack_offset.value, | | |
| 288 | .dead => unreachable, | 281 | .dead => unreachable, |
| 289 | else => return 0, | 282 | else => 0, |
| 290 | } | 283 | }; |
| 291 | } | 284 | } |
| 292 | | 285 | |
| 293 | /// Promotes a `WValue` to a local when given value is on top of the stack. | 286 | /// Promotes a `WValue` to a local when given value is on top of the stack. |
| ... | @@ -651,6 +644,30 @@ fn genBlockType(ty: Type, zcu: *const Zcu, target: *const std.Target) std.wasm.B | ... | @@ -651,6 +644,30 @@ fn genBlockType(ty: Type, zcu: *const Zcu, target: *const std.Target) std.wasm.B |
| 651 | }; | 644 | }; |
| 652 | } | 645 | } |
| 653 | | 646 | |
| | 647 | /// Returns `ptr` with `offset` applied. |
| | 648 | fn offsetPointer(cg: *CodeGen, ptr: WValue, offset: u64) InnerError!WValue { |
| | 649 | if (offset == 0) return ptr; |
| | 650 | return switch (ptr) { |
| | 651 | .stack_offset => |stack_offset| .{ .stack_offset = .{ |
| | 652 | .value = stack_offset.value + offset, |
| | 653 | } }, |
| | 654 | else => result: { |
| | 655 | try cg.emitWValue(ptr); |
| | 656 | switch (cg.ptr_size) { |
| | 657 | .wasm32 => { |
| | 658 | try cg.addImm32(@intCast(offset)); |
| | 659 | try cg.addTag(.i32_add); |
| | 660 | }, |
| | 661 | .wasm64 => { |
| | 662 | try cg.addImm64(offset); |
| | 663 | try cg.addTag(.i64_add); |
| | 664 | }, |
| | 665 | } |
| | 666 | break :result .stack; |
| | 667 | }, |
| | 668 | }; |
| | 669 | } |
| | 670 | |
| 654 | /// Writes the bytecode depending on the given `WValue` in `val` | 671 | /// Writes the bytecode depending on the given `WValue` in `val` |
| 655 | fn emitWValue(cg: *CodeGen, value: WValue) InnerError!void { | 672 | fn emitWValue(cg: *CodeGen, value: WValue) InnerError!void { |
| 656 | switch (value) { | 673 | switch (value) { |
| ... | @@ -718,7 +735,18 @@ fn emitWValue(cg: *CodeGen, value: WValue) InnerError!void { | ... | @@ -718,7 +735,18 @@ fn emitWValue(cg: *CodeGen, value: WValue) InnerError!void { |
| 718 | }); | 735 | }); |
| 719 | } | 736 | } |
| 720 | }, | 737 | }, |
| 721 | .stack_offset => try cg.addLocal(.local_get, cg.bottom_stack_value.local.value), // caller must ensure to address the offset | 738 | .stack_offset => |stack_offset| { |
| | 739 | try cg.emitWValue(cg.bottom_stack_value); |
| | 740 | _ = try cg.offsetPointer(.stack, stack_offset.value); |
| | 741 | }, |
| | 742 | } |
| | 743 | } |
| | 744 | |
| | 745 | /// Emits the base address for a memory instruction. |
| | 746 | fn emitMemBase(cg: *CodeGen, ptr: WValue) InnerError!void { |
| | 747 | switch (ptr) { |
| | 748 | .stack_offset => try cg.addLocal(.local_get, cg.bottom_stack_value.local.value), |
| | 749 | else => try cg.emitWValue(ptr), |
| 722 | } | 750 | } |
| 723 | } | 751 | } |
| 724 | | 752 | |
| ... | @@ -989,7 +1017,7 @@ pub fn firstParamSRet( | ... | @@ -989,7 +1017,7 @@ pub fn firstParamSRet( |
| 989 | /// it matches the ABI. | 1017 | /// it matches the ABI. |
| 990 | fn lowerArg(cg: *CodeGen, cc: std.lang.CallingConvention, ty: Type, value: WValue) !void { | 1018 | fn lowerArg(cg: *CodeGen, cc: std.lang.CallingConvention, ty: Type, value: WValue) !void { |
| 991 | if (cc != .wasm_mvp) { | 1019 | if (cc != .wasm_mvp) { |
| 992 | return cg.lowerToStack(value); | 1020 | return cg.emitWValue(value); |
| 993 | } | 1021 | } |
| 994 | | 1022 | |
| 995 | const zcu = cg.pt.zcu; | 1023 | const zcu = cg.pt.zcu; |
| ... | @@ -997,7 +1025,7 @@ fn lowerArg(cg: *CodeGen, cc: std.lang.CallingConvention, ty: Type, value: WValu | ... | @@ -997,7 +1025,7 @@ fn lowerArg(cg: *CodeGen, cc: std.lang.CallingConvention, ty: Type, value: WValu |
| 997 | switch (abi.classifyType(ty, zcu, cg.target)) { | 1025 | switch (abi.classifyType(ty, zcu, cg.target)) { |
| 998 | .direct => |scalar_ty| { | 1026 | .direct => |scalar_ty| { |
| 999 | if (!isByRef(ty, zcu, cg.target)) { | 1027 | if (!isByRef(ty, zcu, cg.target)) { |
| 1000 | return cg.lowerToStack(value); | 1028 | return cg.emitWValue(value); |
| 1001 | } else { | 1029 | } else { |
| 1002 | _ = try cg.load(value, scalar_ty, .{}); | 1030 | _ = try cg.load(value, scalar_ty, .{}); |
| 1003 | } | 1031 | } |
| ... | @@ -1005,15 +1033,16 @@ fn lowerArg(cg: *CodeGen, cc: std.lang.CallingConvention, ty: Type, value: WValu | ... | @@ -1005,15 +1033,16 @@ fn lowerArg(cg: *CodeGen, cc: std.lang.CallingConvention, ty: Type, value: WValu |
| 1005 | .double_i64 => { | 1033 | .double_i64 => { |
| 1006 | assert(ty.abiSize(zcu) == 16); | 1034 | assert(ty.abiSize(zcu) == 16); |
| 1007 | // in this case we have an integer or float that must be lowered as 2 i64's. | 1035 | // in this case we have an integer or float that must be lowered as 2 i64's. |
| 1008 | try cg.emitWValue(value); | 1036 | const base_offset = value.memOffset(); |
| 1009 | try cg.addMemArg(.i64_load, .{ .offset = value.offset(), .alignment = .@"8" }); | 1037 | try cg.emitMemBase(value); |
| 1010 | try cg.emitWValue(value); | 1038 | try cg.addMemArg(.i64_load, .{ .offset = base_offset, .alignment = .@"8" }); |
| 1011 | try cg.addMemArg(.i64_load, .{ .offset = value.offset() + 8, .alignment = .@"8" }); | 1039 | try cg.emitMemBase(value); |
| | 1040 | try cg.addMemArg(.i64_load, .{ .offset = base_offset + 8, .alignment = .@"8" }); |
| 1012 | }, | 1041 | }, |
| 1013 | .indirect => { | 1042 | .indirect => { |
| 1014 | const stack_copy = try cg.allocStack(ty); | 1043 | const stack_copy = try cg.allocStack(ty); |
| 1015 | try cg.store(stack_copy, value, ty, .{}); | 1044 | try cg.store(stack_copy, value, ty, .{}); |
| 1016 | return cg.lowerToStack(stack_copy); | 1045 | return cg.emitWValue(stack_copy); |
| 1017 | }, | 1046 | }, |
| 1018 | .unrolled => |vector| { | 1047 | .unrolled => |vector| { |
| 1019 | const elem_size = vector.elem_type.abiSize(zcu); | 1048 | const elem_size = vector.elem_type.abiSize(zcu); |
| ... | @@ -1024,30 +1053,6 @@ fn lowerArg(cg: *CodeGen, cc: std.lang.CallingConvention, ty: Type, value: WValu | ... | @@ -1024,30 +1053,6 @@ fn lowerArg(cg: *CodeGen, cc: std.lang.CallingConvention, ty: Type, value: WValu |
| 1024 | } | 1053 | } |
| 1025 | } | 1054 | } |
| 1026 | | 1055 | |
| 1027 | /// Lowers a `WValue` to the stack. This means when the `value` results in | | |
| 1028 | /// `.stack_offset` we calculate the pointer of this offset and use that. | | |
| 1029 | /// The value is left on the stack, and not stored in any temporary. | | |
| 1030 | fn lowerToStack(cg: *CodeGen, value: WValue) !void { | | |
| 1031 | switch (value) { | | |
| 1032 | .stack_offset => |offset| { | | |
| 1033 | try cg.emitWValue(value); | | |
| 1034 | if (offset.value > 0) { | | |
| 1035 | switch (cg.ptr_size) { | | |
| 1036 | .wasm32 => { | | |
| 1037 | try cg.addImm32(offset.value); | | |
| 1038 | try cg.addTag(.i32_add); | | |
| 1039 | }, | | |
| 1040 | .wasm64 => { | | |
| 1041 | try cg.addImm64(offset.value); | | |
| 1042 | try cg.addTag(.i64_add); | | |
| 1043 | }, | | |
| 1044 | } | | |
| 1045 | } | | |
| 1046 | }, | | |
| 1047 | else => try cg.emitWValue(value), | | |
| 1048 | } | | |
| 1049 | } | | |
| 1050 | | | |
| 1051 | /// Creates a local for the initial stack value | 1056 | /// Creates a local for the initial stack value |
| 1052 | /// Asserts `initial_stack_value` is `.none` | 1057 | /// Asserts `initial_stack_value` is `.none` |
| 1053 | fn initializeStack(cg: *CodeGen) !void { | 1058 | fn initializeStack(cg: *CodeGen) !void { |
| ... | @@ -1113,7 +1118,7 @@ fn allocStackBytes(cg: *CodeGen, size: u32, alignment: Alignment) !WValue { | ... | @@ -1113,7 +1118,7 @@ fn allocStackBytes(cg: *CodeGen, size: u32, alignment: Alignment) !WValue { |
| 1113 | const offset: u32 = @intCast(alignment.forward(cg.stack_size)); | 1118 | const offset: u32 = @intCast(alignment.forward(cg.stack_size)); |
| 1114 | defer cg.stack_size = offset + size; | 1119 | defer cg.stack_size = offset + size; |
| 1115 | | 1120 | |
| 1116 | return .{ .stack_offset = .{ .value = offset, .references = 1 } }; | 1121 | return .{ .stack_offset = .{ .value = offset } }; |
| 1117 | } | 1122 | } |
| 1118 | | 1123 | |
| 1119 | /// From a given AIR instruction generates a pointer to the stack where | 1124 | /// From a given AIR instruction generates a pointer to the stack where |
| ... | @@ -1141,7 +1146,7 @@ fn allocStackPtr(cg: *CodeGen, inst: Air.Inst.Index) !WValue { | ... | @@ -1141,7 +1146,7 @@ fn allocStackPtr(cg: *CodeGen, inst: Air.Inst.Index) !WValue { |
| 1141 | const offset: u32 = @intCast(abi_alignment.forward(cg.stack_size)); | 1146 | const offset: u32 = @intCast(abi_alignment.forward(cg.stack_size)); |
| 1142 | defer cg.stack_size = offset + abi_size; | 1147 | defer cg.stack_size = offset + abi_size; |
| 1143 | | 1148 | |
| 1144 | return .{ .stack_offset = .{ .value = offset, .references = 1 } }; | 1149 | return .{ .stack_offset = .{ .value = offset } }; |
| 1145 | } | 1150 | } |
| 1146 | | 1151 | |
| 1147 | fn emitMemoryCopy(cg: *CodeGen, dst: WValue, src: WValue, len: WValue) !void { | 1152 | fn emitMemoryCopy(cg: *CodeGen, dst: WValue, src: WValue, len: WValue) !void { |
| ... | @@ -1171,8 +1176,8 @@ fn emitMemoryCopy(cg: *CodeGen, dst: WValue, src: WValue, len: WValue) !void { | ... | @@ -1171,8 +1176,8 @@ fn emitMemoryCopy(cg: *CodeGen, dst: WValue, src: WValue, len: WValue) !void { |
| 1171 | try cg.addLabel(.br_if, 0); | 1176 | try cg.addLabel(.br_if, 0); |
| 1172 | } | 1177 | } |
| 1173 | | 1178 | |
| 1174 | try cg.lowerToStack(dst); | 1179 | try cg.emitWValue(dst); |
| 1175 | try cg.lowerToStack(src); | 1180 | try cg.emitWValue(src); |
| 1176 | try cg.emitWValue(len); | 1181 | try cg.emitWValue(len); |
| 1177 | try cg.addExtended(.memory_copy); | 1182 | try cg.addExtended(.memory_copy); |
| 1178 | | 1183 | |
| ... | @@ -1187,8 +1192,8 @@ fn memcpy(cg: *CodeGen, dst: WValue, src: WValue, len: WValue) !void { | ... | @@ -1187,8 +1192,8 @@ fn memcpy(cg: *CodeGen, dst: WValue, src: WValue, len: WValue) !void { |
| 1187 | return; | 1192 | return; |
| 1188 | } | 1193 | } |
| 1189 | | 1194 | |
| 1190 | try cg.lowerToStack(dst); | 1195 | try cg.emitWValue(dst); |
| 1191 | try cg.lowerToStack(src); | 1196 | try cg.emitWValue(src); |
| 1192 | try cg.emitWValue(len); | 1197 | try cg.emitWValue(len); |
| 1193 | try cg.addCallIntrinsic(.memcpy); | 1198 | try cg.addCallIntrinsic(.memcpy); |
| 1194 | try cg.addTag(.drop); | 1199 | try cg.addTag(.drop); |
| ... | @@ -1200,8 +1205,8 @@ fn memmove(cg: *CodeGen, dst: WValue, src: WValue, len: WValue) !void { | ... | @@ -1200,8 +1205,8 @@ fn memmove(cg: *CodeGen, dst: WValue, src: WValue, len: WValue) !void { |
| 1200 | return; | 1205 | return; |
| 1201 | } | 1206 | } |
| 1202 | | 1207 | |
| 1203 | try cg.lowerToStack(dst); | 1208 | try cg.emitWValue(dst); |
| 1204 | try cg.lowerToStack(src); | 1209 | try cg.emitWValue(src); |
| 1205 | try cg.emitWValue(len); | 1210 | try cg.emitWValue(len); |
| 1206 | try cg.addCallIntrinsic(.memmove); | 1211 | try cg.addCallIntrinsic(.memmove); |
| 1207 | try cg.addTag(.drop); | 1212 | try cg.addTag(.drop); |
| ... | @@ -1283,34 +1288,6 @@ pub fn determineSimdStoreStrategy(ty: Type, zcu: *const Zcu, target: *const std. | ... | @@ -1283,34 +1288,6 @@ pub fn determineSimdStoreStrategy(ty: Type, zcu: *const Zcu, target: *const std. |
| 1283 | return .unrolled; | 1288 | return .unrolled; |
| 1284 | } | 1289 | } |
| 1285 | | 1290 | |
| 1286 | /// Creates a new local for a pointer that points to memory with given offset. | | |
| 1287 | /// This can be used to get a pointer to a struct field, error payload, etc. | | |
| 1288 | /// By providing `modify` as action, it will modify the given `ptr_value` instead of making a new | | |
| 1289 | /// local value to store the pointer. This allows for local re-use and improves binary size. | | |
| 1290 | fn buildPointerOffset(cg: *CodeGen, ptr_value: WValue, offset: u64, action: enum { modify, new }) InnerError!WValue { | | |
| 1291 | // do not perform arithmetic when offset is 0. | | |
| 1292 | if (offset == 0 and ptr_value.offset() == 0 and action == .modify) return ptr_value; | | |
| 1293 | const result_ptr: WValue = switch (action) { | | |
| 1294 | .new => try cg.ensureAllocLocal(Type.usize), | | |
| 1295 | .modify => ptr_value, | | |
| 1296 | }; | | |
| 1297 | try cg.emitWValue(ptr_value); | | |
| 1298 | if (offset + ptr_value.offset() > 0) { | | |
| 1299 | switch (cg.ptr_size) { | | |
| 1300 | .wasm32 => { | | |
| 1301 | try cg.addImm32(@intCast(offset + ptr_value.offset())); | | |
| 1302 | try cg.addTag(.i32_add); | | |
| 1303 | }, | | |
| 1304 | .wasm64 => { | | |
| 1305 | try cg.addImm64(offset + ptr_value.offset()); | | |
| 1306 | try cg.addTag(.i64_add); | | |
| 1307 | }, | | |
| 1308 | } | | |
| 1309 | } | | |
| 1310 | try cg.addLocal(.local_set, result_ptr.local.value); | | |
| 1311 | return result_ptr; | | |
| 1312 | } | | |
| 1313 | | | |
| 1314 | fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 1291 | fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 1315 | const zcu = cg.pt.zcu; | 1292 | const zcu = cg.pt.zcu; |
| 1316 | const air_tags = cg.air.instructions.items(.tag); | 1293 | const air_tags = cg.air.instructions.items(.tag); |
| ... | @@ -1331,7 +1308,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -1331,7 +1308,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 1331 | const elem_ty = cg.typeOf(bin_op.rhs); | 1308 | const elem_ty = cg.typeOf(bin_op.rhs); |
| 1332 | const elem_size = elem_ty.abiSize(zcu); | 1309 | const elem_size = elem_ty.abiSize(zcu); |
| 1333 | | 1310 | |
| 1334 | try cg.lowerToStack(vec_ptr); | 1311 | try cg.emitWValue(vec_ptr); |
| 1335 | try cg.emitWValue(elem_idx); | 1312 | try cg.emitWValue(elem_idx); |
| 1336 | try cg.addImm32(@intCast(elem_size)); | 1313 | try cg.addImm32(@intCast(elem_size)); |
| 1337 | try cg.addTag(.i32_mul); | 1314 | try cg.addTag(.i32_mul); |
| ... | @@ -2108,7 +2085,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) | ... | @@ -2108,7 +2085,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) |
| 2108 | } else .none; | 2085 | } else .none; |
| 2109 | | 2086 | |
| 2110 | if (first_param_sret) { | 2087 | if (first_param_sret) { |
| 2111 | try cg.lowerToStack(sret); | 2088 | try cg.emitWValue(sret); |
| 2112 | } | 2089 | } |
| 2113 | | 2090 | |
| 2114 | for (args, 0..) |arg, arg_i| { | 2091 | for (args, 0..) |arg, arg_i| { |
| ... | @@ -2122,7 +2099,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) | ... | @@ -2122,7 +2099,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) |
| 2122 | } | 2099 | } |
| 2123 | | 2100 | |
| 2124 | if (fn_info.is_var_args) { | 2101 | if (fn_info.is_var_args) { |
| 2125 | try cg.lowerToStack(varargs_buf); | 2102 | try cg.emitWValue(varargs_buf); |
| 2126 | } | 2103 | } |
| 2127 | | 2104 | |
| 2128 | if (callee) |nav_index| { | 2105 | if (callee) |nav_index| { |
| ... | @@ -2243,8 +2220,8 @@ fn airVaArg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -2243,8 +2220,8 @@ fn airVaArg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2243 | | 2220 | |
| 2244 | try cg.addLocal(.local_set, arg_ptr.local.value); | 2221 | try cg.addLocal(.local_set, arg_ptr.local.value); |
| 2245 | | 2222 | |
| 2246 | try cg.lowerToStack(operand); | 2223 | try cg.emitWValue(operand); |
| 2247 | try cg.lowerToStack(arg_ptr); | 2224 | try cg.emitWValue(arg_ptr); |
| 2248 | switch (cg.ptr_size) { | 2225 | switch (cg.ptr_size) { |
| 2249 | .wasm32 => { | 2226 | .wasm32 => { |
| 2250 | try cg.addImm32(abi_size); | 2227 | try cg.addImm32(abi_size); |
| ... | @@ -2325,28 +2302,22 @@ fn store(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, memarg: MemArg) Inner | ... | @@ -2325,28 +2302,22 @@ fn store(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, memarg: MemArg) Inner |
| 2325 | natural_alignment.minStrict(memarg.alignment); | 2302 | natural_alignment.minStrict(memarg.alignment); |
| 2326 | | 2303 | |
| 2327 | if (isByRef(ty, zcu, cg.target)) { | 2304 | if (isByRef(ty, zcu, cg.target)) { |
| 2328 | const offset_ptr: WValue = switch (memarg.offset + lhs.offset()) { | 2305 | const offset_ptr = try cg.offsetPointer(lhs, memarg.offset); |
| 2329 | 0 => lhs, | | |
| 2330 | else => |total_offset| ptr: { | | |
| 2331 | try cg.emitWValue(lhs); | | |
| 2332 | try cg.addImm32(@intCast(total_offset)); | | |
| 2333 | try cg.addTag(.i32_add); | | |
| 2334 | break :ptr .stack; | | |
| 2335 | }, | | |
| 2336 | }; | | |
| 2337 | return cg.memcpy(offset_ptr, rhs, .{ .imm32 = @intCast(abi_size) }); | 2306 | return cg.memcpy(offset_ptr, rhs, .{ .imm32 = @intCast(abi_size) }); |
| 2338 | } | 2307 | } |
| 2339 | | 2308 | |
| | 2309 | const base_offset = lhs.memOffset(); |
| | 2310 | try cg.emitMemBase(lhs); |
| | 2311 | |
| 2340 | if (ty.zigTypeTag(zcu) == .vector) { | 2312 | if (ty.zigTypeTag(zcu) == .vector) { |
| 2341 | try cg.emitWValue(lhs); | 2313 | try cg.emitWValue(rhs); |
| 2342 | try cg.lowerToStack(rhs); | | |
| 2343 | // TODO: Add helper functions for simd opcodes | 2314 | // TODO: Add helper functions for simd opcodes |
| 2344 | const extra_index: u32 = @intCast(cg.mir_extra.items.len); | 2315 | const extra_index: u32 = @intCast(cg.mir_extra.items.len); |
| 2345 | // stores as := opcode, offset, alignment (opcode::memarg) | 2316 | // stores as := opcode, offset, alignment (opcode::memarg) |
| 2346 | try cg.mir_extra.ensureUnusedCapacity(cg.gpa, 4); | 2317 | try cg.mir_extra.ensureUnusedCapacity(cg.gpa, 4); |
| 2347 | cg.mir_extra.appendAssumeCapacity(@backingInt(std.wasm.SimdOpcode.v128_store)); | 2318 | cg.mir_extra.appendAssumeCapacity(@backingInt(std.wasm.SimdOpcode.v128_store)); |
| 2348 | _ = try cg.addExtraAssumeCapacity(Mir.MemArg{ | 2319 | _ = try cg.addExtraAssumeCapacity(Mir.MemArg{ |
| 2349 | .offset = memarg.offset + lhs.offset(), | 2320 | .offset = base_offset + memarg.offset, |
| 2350 | .alignment = alignment.toStdMem(), | 2321 | .alignment = alignment.toStdMem(), |
| 2351 | }); | 2322 | }); |
| 2352 | return cg.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); | 2323 | return cg.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); |
| ... | @@ -2371,13 +2342,12 @@ fn store(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, memarg: MemArg) Inner | ... | @@ -2371,13 +2342,12 @@ fn store(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, memarg: MemArg) Inner |
| 2371 | } | 2342 | } |
| 2372 | }; | 2343 | }; |
| 2373 | | 2344 | |
| 2374 | try cg.emitWValue(lhs); | 2345 | try cg.emitWValue(rhs); |
| 2375 | try cg.lowerToStack(rhs); | | |
| 2376 | | 2346 | |
| 2377 | try cg.addMemArg( | 2347 | try cg.addMemArg( |
| 2378 | store_opcode, | 2348 | store_opcode, |
| 2379 | .{ | 2349 | .{ |
| 2380 | .offset = memarg.offset + lhs.offset(), | 2350 | .offset = base_offset + memarg.offset, |
| 2381 | .alignment = alignment.toStdMem(), | 2351 | .alignment = alignment.toStdMem(), |
| 2382 | }, | 2352 | }, |
| 2383 | ); | 2353 | ); |
| ... | @@ -2421,23 +2391,18 @@ fn load(cg: *CodeGen, operand: WValue, ty: Type, memarg: MemArg) InnerError!WVal | ... | @@ -2421,23 +2391,18 @@ fn load(cg: *CodeGen, operand: WValue, ty: Type, memarg: MemArg) InnerError!WVal |
| 2421 | natural_alignment.minStrict(memarg.alignment); | 2391 | natural_alignment.minStrict(memarg.alignment); |
| 2422 | | 2392 | |
| 2423 | if (isByRef(ty, zcu, cg.target)) { | 2393 | if (isByRef(ty, zcu, cg.target)) { |
| 2424 | const src_ptr_maybe_stack: WValue = switch (memarg.offset + operand.offset()) { | 2394 | var src_ptr = try cg.offsetPointer(operand, memarg.offset); |
| 2425 | 0 => operand, | 2395 | const owns_src_ptr = src_ptr == .stack; |
| 2426 | else => |total_offset| ptr: { | 2396 | src_ptr = try src_ptr.toLocal(cg, .usize); |
| 2427 | try cg.emitWValue(operand); | 2397 | defer if (owns_src_ptr) src_ptr.free(cg); |
| 2428 | try cg.addImm32(@intCast(total_offset)); | 2398 | |
| 2429 | try cg.addTag(.i32_add); | | |
| 2430 | break :ptr .stack; | | |
| 2431 | }, | | |
| 2432 | }; | | |
| 2433 | const src_ptr = try src_ptr_maybe_stack.toLocal(cg, .usize); | | |
| 2434 | const new_ptr = try cg.allocStack(ty); | 2399 | const new_ptr = try cg.allocStack(ty); |
| 2435 | try cg.store(new_ptr, src_ptr, ty, .{}); | 2400 | try cg.memcpy(new_ptr, src_ptr, .{ .imm32 = @intCast(ty.abiSize(zcu)) }); |
| 2436 | return new_ptr; | 2401 | return new_ptr; |
| 2437 | } | 2402 | } |
| 2438 | | 2403 | |
| 2439 | // load local's value from memory by its stack position | 2404 | const base_offset = operand.memOffset(); |
| 2440 | try cg.emitWValue(operand); | 2405 | try cg.emitMemBase(operand); |
| 2441 | | 2406 | |
| 2442 | if (ty.zigTypeTag(zcu) == .vector) { | 2407 | if (ty.zigTypeTag(zcu) == .vector) { |
| 2443 | // TODO: Add helper functions for simd opcodes | 2408 | // TODO: Add helper functions for simd opcodes |
| ... | @@ -2446,7 +2411,7 @@ fn load(cg: *CodeGen, operand: WValue, ty: Type, memarg: MemArg) InnerError!WVal | ... | @@ -2446,7 +2411,7 @@ fn load(cg: *CodeGen, operand: WValue, ty: Type, memarg: MemArg) InnerError!WVal |
| 2446 | try cg.mir_extra.ensureUnusedCapacity(cg.gpa, 4); | 2411 | try cg.mir_extra.ensureUnusedCapacity(cg.gpa, 4); |
| 2447 | cg.mir_extra.appendAssumeCapacity(@backingInt(std.wasm.SimdOpcode.v128_load)); | 2412 | cg.mir_extra.appendAssumeCapacity(@backingInt(std.wasm.SimdOpcode.v128_load)); |
| 2448 | _ = try cg.addExtraAssumeCapacity(Mir.MemArg{ | 2413 | _ = try cg.addExtraAssumeCapacity(Mir.MemArg{ |
| 2449 | .offset = memarg.offset + operand.offset(), | 2414 | .offset = base_offset + memarg.offset, |
| 2450 | .alignment = alignment.toStdMem(), | 2415 | .alignment = alignment.toStdMem(), |
| 2451 | }); | 2416 | }); |
| 2452 | try cg.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); | 2417 | try cg.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); |
| ... | @@ -2477,7 +2442,7 @@ fn load(cg: *CodeGen, operand: WValue, ty: Type, memarg: MemArg) InnerError!WVal | ... | @@ -2477,7 +2442,7 @@ fn load(cg: *CodeGen, operand: WValue, ty: Type, memarg: MemArg) InnerError!WVal |
| 2477 | try cg.addMemArg( | 2442 | try cg.addMemArg( |
| 2478 | load_opcode, | 2443 | load_opcode, |
| 2479 | .{ | 2444 | .{ |
| 2480 | .offset = memarg.offset + operand.offset(), | 2445 | .offset = base_offset + memarg.offset, |
| 2481 | .alignment = alignment.toStdMem(), | 2446 | .alignment = alignment.toStdMem(), |
| 2482 | }, | 2447 | }, |
| 2483 | ); | 2448 | ); |
| ... | @@ -2647,9 +2612,9 @@ fn intAdd(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue | ... | @@ -2647,9 +2612,9 @@ fn intAdd(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue |
| 2647 | else => { | 2612 | else => { |
| 2648 | const result = try cg.allocInt(ty); | 2613 | const result = try cg.allocInt(ty); |
| 2649 | | 2614 | |
| 2650 | try cg.lowerToStack(result); | 2615 | try cg.emitWValue(result); |
| 2651 | try cg.lowerToStack(lhs); | 2616 | try cg.emitWValue(lhs); |
| 2652 | try cg.lowerToStack(rhs); | 2617 | try cg.emitWValue(rhs); |
| 2653 | try cg.addImm32(@intFromBool(ty.is_signed)); | 2618 | try cg.addImm32(@intFromBool(ty.is_signed)); |
| 2654 | try cg.addImm32(ty.bits); | 2619 | try cg.addImm32(ty.bits); |
| 2655 | try cg.addCallIntrinsic(.__addo_limb64); | 2620 | try cg.addCallIntrinsic(.__addo_limb64); |
| ... | @@ -2700,9 +2665,9 @@ fn intSub(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue | ... | @@ -2700,9 +2665,9 @@ fn intSub(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue |
| 2700 | else => { | 2665 | else => { |
| 2701 | const result = try cg.allocInt(ty); | 2666 | const result = try cg.allocInt(ty); |
| 2702 | | 2667 | |
| 2703 | try cg.lowerToStack(result); | 2668 | try cg.emitWValue(result); |
| 2704 | try cg.lowerToStack(lhs); | 2669 | try cg.emitWValue(lhs); |
| 2705 | try cg.lowerToStack(rhs); | 2670 | try cg.emitWValue(rhs); |
| 2706 | try cg.addImm32(@intFromBool(ty.is_signed)); | 2671 | try cg.addImm32(@intFromBool(ty.is_signed)); |
| 2707 | try cg.addImm32(ty.bits); | 2672 | try cg.addImm32(ty.bits); |
| 2708 | try cg.addCallIntrinsic(.__subo_limb64); | 2673 | try cg.addCallIntrinsic(.__subo_limb64); |
| ... | @@ -2732,9 +2697,9 @@ fn intMul(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue | ... | @@ -2732,9 +2697,9 @@ fn intMul(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue |
| 2732 | else => { | 2697 | else => { |
| 2733 | const result = try cg.allocInt(ty); | 2698 | const result = try cg.allocInt(ty); |
| 2734 | | 2699 | |
| 2735 | try cg.lowerToStack(result); | 2700 | try cg.emitWValue(result); |
| 2736 | try cg.lowerToStack(lhs); | 2701 | try cg.emitWValue(lhs); |
| 2737 | try cg.lowerToStack(rhs); | 2702 | try cg.emitWValue(rhs); |
| 2738 | try cg.addImm32(@intFromBool(ty.is_signed)); | 2703 | try cg.addImm32(@intFromBool(ty.is_signed)); |
| 2739 | try cg.addImm32(ty.bits); | 2704 | try cg.addImm32(ty.bits); |
| 2740 | try cg.addCallIntrinsic(.__mulo_limb64); | 2705 | try cg.addCallIntrinsic(.__mulo_limb64); |
| ... | @@ -3041,9 +3006,9 @@ fn intAnd(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue | ... | @@ -3041,9 +3006,9 @@ fn intAnd(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue |
| 3041 | else => { | 3006 | else => { |
| 3042 | const result = try cg.allocInt(ty); | 3007 | const result = try cg.allocInt(ty); |
| 3043 | | 3008 | |
| 3044 | try cg.lowerToStack(result); | 3009 | try cg.emitWValue(result); |
| 3045 | try cg.lowerToStack(lhs); | 3010 | try cg.emitWValue(lhs); |
| 3046 | try cg.lowerToStack(rhs); | 3011 | try cg.emitWValue(rhs); |
| 3047 | try cg.addImm32(ty.bits); | 3012 | try cg.addImm32(ty.bits); |
| 3048 | try cg.addCallIntrinsic(.__and_limb64); | 3013 | try cg.addCallIntrinsic(.__and_limb64); |
| 3049 | | 3014 | |
| ... | @@ -3085,9 +3050,9 @@ fn intOr(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue | ... | @@ -3085,9 +3050,9 @@ fn intOr(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue |
| 3085 | else => { | 3050 | else => { |
| 3086 | const result = try cg.allocInt(ty); | 3051 | const result = try cg.allocInt(ty); |
| 3087 | | 3052 | |
| 3088 | try cg.lowerToStack(result); | 3053 | try cg.emitWValue(result); |
| 3089 | try cg.lowerToStack(lhs); | 3054 | try cg.emitWValue(lhs); |
| 3090 | try cg.lowerToStack(rhs); | 3055 | try cg.emitWValue(rhs); |
| 3091 | try cg.addImm32(ty.bits); | 3056 | try cg.addImm32(ty.bits); |
| 3092 | try cg.addCallIntrinsic(.__or_limb64); | 3057 | try cg.addCallIntrinsic(.__or_limb64); |
| 3093 | | 3058 | |
| ... | @@ -3129,9 +3094,9 @@ fn intXor(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue | ... | @@ -3129,9 +3094,9 @@ fn intXor(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue |
| 3129 | else => { | 3094 | else => { |
| 3130 | const result = try cg.allocInt(ty); | 3095 | const result = try cg.allocInt(ty); |
| 3131 | | 3096 | |
| 3132 | try cg.lowerToStack(result); | 3097 | try cg.emitWValue(result); |
| 3133 | try cg.lowerToStack(lhs); | 3098 | try cg.emitWValue(lhs); |
| 3134 | try cg.lowerToStack(rhs); | 3099 | try cg.emitWValue(rhs); |
| 3135 | try cg.addImm32(ty.bits); | 3100 | try cg.addImm32(ty.bits); |
| 3136 | try cg.addCallIntrinsic(.__xor_limb64); | 3101 | try cg.addCallIntrinsic(.__xor_limb64); |
| 3137 | | 3102 | |
| ... | @@ -3176,13 +3141,14 @@ fn intNot(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { | ... | @@ -3176,13 +3141,14 @@ fn intNot(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3176 | 65...128 => { | 3141 | 65...128 => { |
| 3177 | const result = try cg.allocStack(Type.u128); | 3142 | const result = try cg.allocStack(Type.u128); |
| 3178 | | 3143 | |
| 3179 | try cg.emitWValue(result); | 3144 | const result_offset = result.memOffset(); |
| | 3145 | try cg.emitMemBase(result); |
| 3180 | _ = try cg.load(operand, .u64, .{}); | 3146 | _ = try cg.load(operand, .u64, .{}); |
| 3181 | try cg.addImm64(~@as(u64, 0)); | 3147 | try cg.addImm64(~@as(u64, 0)); |
| 3182 | try cg.addTag(.i64_xor); | 3148 | try cg.addTag(.i64_xor); |
| 3183 | try cg.store(.stack, .stack, .u64, .{ .offset = result.offset() }); | 3149 | try cg.store(.stack, .stack, .u64, .{ .offset = result_offset }); |
| 3184 | | 3150 | |
| 3185 | try cg.emitWValue(result); | 3151 | try cg.emitMemBase(result); |
| 3186 | _ = try cg.load(operand, .u64, .{ .offset = 8 }); | 3152 | _ = try cg.load(operand, .u64, .{ .offset = 8 }); |
| 3187 | const high_mask: u64 = if (ty.is_signed) | 3153 | const high_mask: u64 = if (ty.is_signed) |
| 3188 | ~@as(u64, 0) | 3154 | ~@as(u64, 0) |
| ... | @@ -3190,15 +3156,15 @@ fn intNot(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { | ... | @@ -3190,15 +3156,15 @@ fn intNot(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3190 | ~@as(u64, 0) >> @intCast(128 - ty.bits); | 3156 | ~@as(u64, 0) >> @intCast(128 - ty.bits); |
| 3191 | try cg.addImm64(high_mask); | 3157 | try cg.addImm64(high_mask); |
| 3192 | try cg.addTag(.i64_xor); | 3158 | try cg.addTag(.i64_xor); |
| 3193 | try cg.store(.stack, .stack, .u64, .{ .offset = result.offset() + 8 }); | 3159 | try cg.store(.stack, .stack, .u64, .{ .offset = result_offset + 8 }); |
| 3194 | | 3160 | |
| 3195 | return result; | 3161 | return result; |
| 3196 | }, | 3162 | }, |
| 3197 | else => { | 3163 | else => { |
| 3198 | const result = try cg.allocInt(ty); | 3164 | const result = try cg.allocInt(ty); |
| 3199 | | 3165 | |
| 3200 | try cg.lowerToStack(result); | 3166 | try cg.emitWValue(result); |
| 3201 | try cg.lowerToStack(operand); | 3167 | try cg.emitWValue(operand); |
| 3202 | try cg.addImm32(@intFromBool(ty.is_signed)); | 3168 | try cg.addImm32(@intFromBool(ty.is_signed)); |
| 3203 | try cg.addImm32(ty.bits); | 3169 | try cg.addImm32(ty.bits); |
| 3204 | try cg.addCallIntrinsic(.__not_limb64); | 3170 | try cg.addCallIntrinsic(.__not_limb64); |
| ... | @@ -3230,9 +3196,9 @@ fn intShl(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue | ... | @@ -3230,9 +3196,9 @@ fn intShl(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue |
| 3230 | else => { | 3196 | else => { |
| 3231 | const result = try cg.allocInt(ty); | 3197 | const result = try cg.allocInt(ty); |
| 3232 | | 3198 | |
| 3233 | try cg.lowerToStack(result); | 3199 | try cg.emitWValue(result); |
| 3234 | try cg.lowerToStack(lhs); | 3200 | try cg.emitWValue(lhs); |
| 3235 | try cg.lowerToStack(rhs); | 3201 | try cg.emitWValue(rhs); |
| 3236 | try cg.addImm32(@intFromBool(ty.is_signed)); | 3202 | try cg.addImm32(@intFromBool(ty.is_signed)); |
| 3237 | try cg.addImm32(ty.bits); | 3203 | try cg.addImm32(ty.bits); |
| 3238 | try cg.addCallIntrinsic(.__shlo_limb64); | 3204 | try cg.addCallIntrinsic(.__shlo_limb64); |
| ... | @@ -3270,9 +3236,9 @@ fn intShr(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue | ... | @@ -3270,9 +3236,9 @@ fn intShr(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue |
| 3270 | else => { | 3236 | else => { |
| 3271 | const result = try cg.allocInt(ty); | 3237 | const result = try cg.allocInt(ty); |
| 3272 | | 3238 | |
| 3273 | try cg.lowerToStack(result); | 3239 | try cg.emitWValue(result); |
| 3274 | try cg.lowerToStack(lhs); | 3240 | try cg.emitWValue(lhs); |
| 3275 | try cg.lowerToStack(rhs); | 3241 | try cg.emitWValue(rhs); |
| 3276 | try cg.addImm32(@intFromBool(ty.is_signed)); | 3242 | try cg.addImm32(@intFromBool(ty.is_signed)); |
| 3277 | try cg.addImm32(ty.bits); | 3243 | try cg.addImm32(ty.bits); |
| 3278 | try cg.addCallIntrinsic(.__shr_limb64); | 3244 | try cg.addCallIntrinsic(.__shr_limb64); |
| ... | @@ -3320,8 +3286,9 @@ fn intAbs(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { | ... | @@ -3320,8 +3286,9 @@ fn intAbs(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3320 | const u128_ty: IntType = .{ .is_signed = false, .bits = 128 }; | 3286 | const u128_ty: IntType = .{ .is_signed = false, .bits = 128 }; |
| 3321 | | 3287 | |
| 3322 | const mask = try cg.allocStack(Type.u128); | 3288 | const mask = try cg.allocStack(Type.u128); |
| 3323 | try cg.emitWValue(mask); | 3289 | const mask_offset = mask.memOffset(); |
| 3324 | try cg.emitWValue(mask); | 3290 | try cg.emitMemBase(mask); |
| | 3291 | try cg.emitMemBase(mask); |
| 3325 | | 3292 | |
| 3326 | _ = try cg.load(operand, .u64, .{ .offset = 8 }); | 3293 | _ = try cg.load(operand, .u64, .{ .offset = 8 }); |
| 3327 | try cg.addImm64(63); | 3294 | try cg.addImm64(63); |
| ... | @@ -3330,9 +3297,9 @@ fn intAbs(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { | ... | @@ -3330,9 +3297,9 @@ fn intAbs(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3330 | var tmp = try cg.allocLocal(Type.u64); | 3297 | var tmp = try cg.allocLocal(Type.u64); |
| 3331 | defer tmp.free(cg); | 3298 | defer tmp.free(cg); |
| 3332 | try cg.addLocal(.local_tee, tmp.local.value); | 3299 | try cg.addLocal(.local_tee, tmp.local.value); |
| 3333 | try cg.store(.stack, .stack, .u64, .{ .offset = mask.offset() + 0 }); | 3300 | try cg.store(.stack, .stack, .u64, .{ .offset = mask_offset }); |
| 3334 | try cg.emitWValue(tmp); | 3301 | try cg.emitWValue(tmp); |
| 3335 | try cg.store(.stack, .stack, .u64, .{ .offset = mask.offset() + 8 }); | 3302 | try cg.store(.stack, .stack, .u64, .{ .offset = mask_offset + 8 }); |
| 3336 | | 3303 | |
| 3337 | const a = try cg.intXor(u128_ty, operand, mask); | 3304 | const a = try cg.intXor(u128_ty, operand, mask); |
| 3338 | const b = try cg.intSub(u128_ty, a, mask); | 3305 | const b = try cg.intSub(u128_ty, a, mask); |
| ... | @@ -3341,8 +3308,8 @@ fn intAbs(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { | ... | @@ -3341,8 +3308,8 @@ fn intAbs(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3341 | else => { | 3308 | else => { |
| 3342 | const result = try cg.allocInt(ty); | 3309 | const result = try cg.allocInt(ty); |
| 3343 | | 3310 | |
| 3344 | try cg.lowerToStack(result); | 3311 | try cg.emitWValue(result); |
| 3345 | try cg.lowerToStack(operand); | 3312 | try cg.emitWValue(operand); |
| 3346 | try cg.addImm32(ty.bits); | 3313 | try cg.addImm32(ty.bits); |
| 3347 | try cg.addCallIntrinsic(.__abs_limb64); | 3314 | try cg.addCallIntrinsic(.__abs_limb64); |
| 3348 | | 3315 | |
| ... | @@ -3352,16 +3319,16 @@ fn intAbs(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { | ... | @@ -3352,16 +3319,16 @@ fn intAbs(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3352 | } | 3319 | } |
| 3353 | | 3320 | |
| 3354 | fn intMax(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue { | 3321 | fn intMax(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue { |
| 3355 | try cg.lowerToStack(lhs); | 3322 | try cg.emitWValue(lhs); |
| 3356 | try cg.lowerToStack(rhs); | 3323 | try cg.emitWValue(rhs); |
| 3357 | _ = try cg.intCmp(ty, .gt, lhs, rhs); | 3324 | _ = try cg.intCmp(ty, .gt, lhs, rhs); |
| 3358 | try cg.addTag(.select); | 3325 | try cg.addTag(.select); |
| 3359 | return .stack; | 3326 | return .stack; |
| 3360 | } | 3327 | } |
| 3361 | | 3328 | |
| 3362 | fn intMin(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue { | 3329 | fn intMin(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue { |
| 3363 | try cg.lowerToStack(lhs); | 3330 | try cg.emitWValue(lhs); |
| 3364 | try cg.lowerToStack(rhs); | 3331 | try cg.emitWValue(rhs); |
| 3365 | _ = try cg.intCmp(ty, .lt, lhs, rhs); | 3332 | _ = try cg.intCmp(ty, .lt, lhs, rhs); |
| 3366 | try cg.addTag(.select); | 3333 | try cg.addTag(.select); |
| 3367 | return .stack; | 3334 | return .stack; |
| ... | @@ -3427,7 +3394,7 @@ fn intClz(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { | ... | @@ -3427,7 +3394,7 @@ fn intClz(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3427 | return .stack; | 3394 | return .stack; |
| 3428 | }, | 3395 | }, |
| 3429 | else => { | 3396 | else => { |
| 3430 | try cg.lowerToStack(operand); | 3397 | try cg.emitWValue(operand); |
| 3431 | try cg.addImm32(ty.bits); | 3398 | try cg.addImm32(ty.bits); |
| 3432 | try cg.addCallIntrinsic(.__clz_limb64); | 3399 | try cg.addCallIntrinsic(.__clz_limb64); |
| 3433 | | 3400 | |
| ... | @@ -3479,7 +3446,7 @@ fn intCtz(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { | ... | @@ -3479,7 +3446,7 @@ fn intCtz(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3479 | return .stack; | 3446 | return .stack; |
| 3480 | }, | 3447 | }, |
| 3481 | else => { | 3448 | else => { |
| 3482 | try cg.lowerToStack(operand); | 3449 | try cg.emitWValue(operand); |
| 3483 | try cg.addImm32(ty.bits); | 3450 | try cg.addImm32(ty.bits); |
| 3484 | try cg.addCallIntrinsic(.__ctz_limb64); | 3451 | try cg.addCallIntrinsic(.__ctz_limb64); |
| 3485 | | 3452 | |
| ... | @@ -3525,7 +3492,7 @@ fn intPopCount(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { | ... | @@ -3525,7 +3492,7 @@ fn intPopCount(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3525 | return .stack; | 3492 | return .stack; |
| 3526 | }, | 3493 | }, |
| 3527 | else => { | 3494 | else => { |
| 3528 | try cg.lowerToStack(operand); | 3495 | try cg.emitWValue(operand); |
| 3529 | try cg.addImm32(ty.bits); | 3496 | try cg.addImm32(ty.bits); |
| 3530 | try cg.addCallIntrinsic(.__popcount_limb64); | 3497 | try cg.addCallIntrinsic(.__popcount_limb64); |
| 3531 | | 3498 | |
| ... | @@ -3560,7 +3527,8 @@ fn intBitReverse(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { | ... | @@ -3560,7 +3527,8 @@ fn intBitReverse(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3560 | 65...128 => { | 3527 | 65...128 => { |
| 3561 | const tmp = try cg.allocStack(Type.u128); | 3528 | const tmp = try cg.allocStack(Type.u128); |
| 3562 | | 3529 | |
| 3563 | try cg.emitWValue(tmp); | 3530 | const tmp_offset = tmp.memOffset(); |
| | 3531 | try cg.emitMemBase(tmp); |
| 3564 | const hi = try cg.load(operand, .u64, .{ .offset = 8 }); | 3532 | const hi = try cg.load(operand, .u64, .{ .offset = 8 }); |
| 3565 | const hi_rev = try cg.callIntrinsic( | 3533 | const hi_rev = try cg.callIntrinsic( |
| 3566 | .__bitreversedi2, | 3534 | .__bitreversedi2, |
| ... | @@ -3569,9 +3537,9 @@ fn intBitReverse(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { | ... | @@ -3569,9 +3537,9 @@ fn intBitReverse(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3569 | &.{hi}, | 3537 | &.{hi}, |
| 3570 | ); | 3538 | ); |
| 3571 | try cg.emitWValue(hi_rev); | 3539 | try cg.emitWValue(hi_rev); |
| 3572 | try cg.store(.stack, .stack, .u64, .{ .offset = tmp.offset() }); | 3540 | try cg.store(.stack, .stack, .u64, .{ .offset = tmp_offset }); |
| 3573 | | 3541 | |
| 3574 | try cg.emitWValue(tmp); | 3542 | try cg.emitMemBase(tmp); |
| 3575 | const lo = try cg.load(operand, .u64, .{}); | 3543 | const lo = try cg.load(operand, .u64, .{}); |
| 3576 | const lo_rev = try cg.callIntrinsic( | 3544 | const lo_rev = try cg.callIntrinsic( |
| 3577 | .__bitreversedi2, | 3545 | .__bitreversedi2, |
| ... | @@ -3580,7 +3548,7 @@ fn intBitReverse(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { | ... | @@ -3580,7 +3548,7 @@ fn intBitReverse(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3580 | &.{lo}, | 3548 | &.{lo}, |
| 3581 | ); | 3549 | ); |
| 3582 | try cg.emitWValue(lo_rev); | 3550 | try cg.emitWValue(lo_rev); |
| 3583 | try cg.store(.stack, .stack, .u64, .{ .offset = tmp.offset() + 8 }); | 3551 | try cg.store(.stack, .stack, .u64, .{ .offset = tmp_offset + 8 }); |
| 3584 | | 3552 | |
| 3585 | if (ty.bits < 128) { | 3553 | if (ty.bits < 128) { |
| 3586 | const shift_ty: IntType = .{ .is_signed = ty.is_signed, .bits = 128 }; | 3554 | const shift_ty: IntType = .{ .is_signed = ty.is_signed, .bits = 128 }; |
| ... | @@ -3592,8 +3560,8 @@ fn intBitReverse(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { | ... | @@ -3592,8 +3560,8 @@ fn intBitReverse(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3592 | else => { | 3560 | else => { |
| 3593 | const result = try cg.allocInt(ty); | 3561 | const result = try cg.allocInt(ty); |
| 3594 | | 3562 | |
| 3595 | try cg.lowerToStack(result); | 3563 | try cg.emitWValue(result); |
| 3596 | try cg.lowerToStack(operand); | 3564 | try cg.emitWValue(operand); |
| 3597 | try cg.addImm32(@intFromBool(ty.is_signed)); | 3565 | try cg.addImm32(@intFromBool(ty.is_signed)); |
| 3598 | try cg.addImm32(ty.bits); | 3566 | try cg.addImm32(ty.bits); |
| 3599 | try cg.addCallIntrinsic(.__bitreverse_limb64); | 3567 | try cg.addCallIntrinsic(.__bitreverse_limb64); |
| ... | @@ -3629,7 +3597,8 @@ fn intByteSwap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { | ... | @@ -3629,7 +3597,8 @@ fn intByteSwap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3629 | 65...128 => { | 3597 | 65...128 => { |
| 3630 | const result = try cg.allocStack(Type.u128); | 3598 | const result = try cg.allocStack(Type.u128); |
| 3631 | | 3599 | |
| 3632 | try cg.emitWValue(result); | 3600 | const result_offset = result.memOffset(); |
| | 3601 | try cg.emitMemBase(result); |
| 3633 | | 3602 | |
| 3634 | const low = try cg.load(operand, .u64, .{}); | 3603 | const low = try cg.load(operand, .u64, .{}); |
| 3635 | const swap_low = try cg.callIntrinsic( | 3604 | const swap_low = try cg.callIntrinsic( |
| ... | @@ -3638,9 +3607,9 @@ fn intByteSwap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { | ... | @@ -3638,9 +3607,9 @@ fn intByteSwap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3638 | Type.u64, | 3607 | Type.u64, |
| 3639 | &.{low}, | 3608 | &.{low}, |
| 3640 | ); | 3609 | ); |
| 3641 | try cg.store(.stack, swap_low, .u64, .{ .offset = result.offset() + 8 }); | 3610 | try cg.store(.stack, swap_low, .u64, .{ .offset = result_offset + 8 }); |
| 3642 | | 3611 | |
| 3643 | try cg.emitWValue(result); | 3612 | try cg.emitMemBase(result); |
| 3644 | | 3613 | |
| 3645 | const high = try cg.load(operand, .u64, .{ .offset = 8 }); | 3614 | const high = try cg.load(operand, .u64, .{ .offset = 8 }); |
| 3646 | const swap_high = try cg.callIntrinsic( | 3615 | const swap_high = try cg.callIntrinsic( |
| ... | @@ -3649,7 +3618,7 @@ fn intByteSwap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { | ... | @@ -3649,7 +3618,7 @@ fn intByteSwap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3649 | Type.u64, | 3618 | Type.u64, |
| 3650 | &.{high}, | 3619 | &.{high}, |
| 3651 | ); | 3620 | ); |
| 3652 | try cg.store(.stack, swap_high, .u64, .{ .offset = result.offset() }); | 3621 | try cg.store(.stack, swap_high, .u64, .{ .offset = result_offset }); |
| 3653 | | 3622 | |
| 3654 | if (ty.bits < 128) { | 3623 | if (ty.bits < 128) { |
| 3655 | const shift_ty: IntType = .{ .is_signed = ty.is_signed, .bits = 128 }; | 3624 | const shift_ty: IntType = .{ .is_signed = ty.is_signed, .bits = 128 }; |
| ... | @@ -3661,8 +3630,8 @@ fn intByteSwap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { | ... | @@ -3661,8 +3630,8 @@ fn intByteSwap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3661 | else => { | 3630 | else => { |
| 3662 | const result = try cg.allocInt(ty); | 3631 | const result = try cg.allocInt(ty); |
| 3663 | | 3632 | |
| 3664 | try cg.lowerToStack(result); | 3633 | try cg.emitWValue(result); |
| 3665 | try cg.lowerToStack(operand); | 3634 | try cg.emitWValue(operand); |
| 3666 | try cg.addImm32(@intFromBool(ty.is_signed)); | 3635 | try cg.addImm32(@intFromBool(ty.is_signed)); |
| 3667 | try cg.addImm32(ty.bits); | 3636 | try cg.addImm32(ty.bits); |
| 3668 | try cg.addCallIntrinsic(.__byteswap_limb64); | 3637 | try cg.addCallIntrinsic(.__byteswap_limb64); |
| ... | @@ -3706,11 +3675,12 @@ fn intWrap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { | ... | @@ -3706,11 +3675,12 @@ fn intWrap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3706 | 65...127 => { | 3675 | 65...127 => { |
| 3707 | const result = try cg.allocStack(Type.u128); | 3676 | const result = try cg.allocStack(Type.u128); |
| 3708 | | 3677 | |
| 3709 | try cg.emitWValue(result); | 3678 | const result_offset = result.memOffset(); |
| | 3679 | try cg.emitMemBase(result); |
| 3710 | _ = try cg.load(operand, .u64, .{}); | 3680 | _ = try cg.load(operand, .u64, .{}); |
| 3711 | try cg.store(.stack, .stack, .u64, .{ .offset = result.offset() }); | 3681 | try cg.store(.stack, .stack, .u64, .{ .offset = result_offset }); |
| 3712 | | 3682 | |
| 3713 | try cg.emitWValue(result); | 3683 | try cg.emitMemBase(result); |
| 3714 | _ = try cg.load(operand, .u64, .{ .offset = 8 }); | 3684 | _ = try cg.load(operand, .u64, .{ .offset = 8 }); |
| 3715 | if (ty.is_signed) { | 3685 | if (ty.is_signed) { |
| 3716 | try cg.addImm64(128 - ty.bits); | 3686 | try cg.addImm64(128 - ty.bits); |
| ... | @@ -3721,7 +3691,7 @@ fn intWrap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { | ... | @@ -3721,7 +3691,7 @@ fn intWrap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3721 | try cg.addImm64(~@as(u64, 0) >> @intCast(128 - ty.bits)); | 3691 | try cg.addImm64(~@as(u64, 0) >> @intCast(128 - ty.bits)); |
| 3722 | try cg.addTag(.i64_and); | 3692 | try cg.addTag(.i64_and); |
| 3723 | } | 3693 | } |
| 3724 | try cg.store(.stack, .stack, .u64, .{ .offset = result.offset() + 8 }); | 3694 | try cg.store(.stack, .stack, .u64, .{ .offset = result_offset + 8 }); |
| 3725 | | 3695 | |
| 3726 | return result; | 3696 | return result; |
| 3727 | }, | 3697 | }, |
| ... | @@ -3738,7 +3708,7 @@ fn intWrap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { | ... | @@ -3738,7 +3708,7 @@ fn intWrap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3738 | try cg.memcpy(result, operand, .{ .imm32 = used_len - 8 }); | 3708 | try cg.memcpy(result, operand, .{ .imm32 = used_len - 8 }); |
| 3739 | const pad = 64 - ty.bits % 64; | 3709 | const pad = 64 - ty.bits % 64; |
| 3740 | | 3710 | |
| 3741 | try cg.emitWValue(result); | 3711 | try cg.emitMemBase(result); |
| 3742 | _ = try cg.load(operand, .u64, .{ .offset = used_len - 8 }); | 3712 | _ = try cg.load(operand, .u64, .{ .offset = used_len - 8 }); |
| 3743 | if (ty.is_signed) { | 3713 | if (ty.is_signed) { |
| 3744 | try cg.addImm64(pad); | 3714 | try cg.addImm64(pad); |
| ... | @@ -3749,14 +3719,14 @@ fn intWrap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { | ... | @@ -3749,14 +3719,14 @@ fn intWrap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3749 | try cg.addImm64(~@as(u64, 0) >> @intCast(pad)); | 3719 | try cg.addImm64(~@as(u64, 0) >> @intCast(pad)); |
| 3750 | try cg.addTag(.i64_and); | 3720 | try cg.addTag(.i64_and); |
| 3751 | } | 3721 | } |
| 3752 | try cg.store(.stack, .stack, .u64, .{ .offset = result.offset() + used_len - 8 }); | 3722 | try cg.store(.stack, .stack, .u64, .{ .offset = result.memOffset() + used_len - 8 }); |
| 3753 | } else { | 3723 | } else { |
| 3754 | try cg.memcpy(result, operand, .{ .imm32 = used_len }); | 3724 | try cg.memcpy(result, operand, .{ .imm32 = used_len }); |
| 3755 | } | 3725 | } |
| 3756 | | 3726 | |
| 3757 | const full_len = @divExact(bits, 8); | 3727 | const full_len = @divExact(bits, 8); |
| 3758 | if (used_len + 8 == full_len) { // last limb needs sign extended | 3728 | if (used_len + 8 == full_len) { // last limb needs sign extended |
| 3759 | try cg.emitWValue(result); | 3729 | try cg.emitMemBase(result); |
| 3760 | if (ty.is_signed) { | 3730 | if (ty.is_signed) { |
| 3761 | _ = try cg.load(result, .u64, .{ .offset = used_len - 8 }); | 3731 | _ = try cg.load(result, .u64, .{ .offset = used_len - 8 }); |
| 3762 | try cg.addImm64(63); | 3732 | try cg.addImm64(63); |
| ... | @@ -3764,7 +3734,7 @@ fn intWrap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { | ... | @@ -3764,7 +3734,7 @@ fn intWrap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3764 | } else { | 3734 | } else { |
| 3765 | try cg.addImm64(0); | 3735 | try cg.addImm64(0); |
| 3766 | } | 3736 | } |
| 3767 | try cg.store(.stack, .stack, .u64, .{ .offset = result.offset() + used_len }); | 3737 | try cg.store(.stack, .stack, .u64, .{ .offset = result.memOffset() + used_len }); |
| 3768 | } | 3738 | } |
| 3769 | | 3739 | |
| 3770 | return result; | 3740 | return result; |
| ... | @@ -3858,20 +3828,20 @@ fn intAddSat(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError | ... | @@ -3858,20 +3828,20 @@ fn intAddSat(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError |
| 3858 | defer rhs_is_neg.free(cg); | 3828 | defer rhs_is_neg.free(cg); |
| 3859 | const min_val = try cg.intMinValue(int_ty); | 3829 | const min_val = try cg.intMinValue(int_ty); |
| 3860 | | 3830 | |
| 3861 | try cg.lowerToStack(min_val); | 3831 | try cg.emitWValue(min_val); |
| 3862 | try cg.lowerToStack(max_val); | 3832 | try cg.emitWValue(max_val); |
| 3863 | try cg.emitWValue(rhs_is_neg); | 3833 | try cg.emitWValue(rhs_is_neg); |
| 3864 | try cg.addTag(.select); | 3834 | try cg.addTag(.select); |
| 3865 | | 3835 | |
| 3866 | try cg.lowerToStack(op_val); | 3836 | try cg.emitWValue(op_val); |
| 3867 | const overflow_cmp = try cg.intCmp(int_ty, .lt, op_val, lhs); | 3837 | const overflow_cmp = try cg.intCmp(int_ty, .lt, op_val, lhs); |
| 3868 | const is_overflow = try cg.intCmp(.u32, .neq, rhs_is_neg, overflow_cmp); | 3838 | const is_overflow = try cg.intCmp(.u32, .neq, rhs_is_neg, overflow_cmp); |
| 3869 | try cg.emitWValue(is_overflow); | 3839 | try cg.emitWValue(is_overflow); |
| 3870 | try cg.addTag(.select); | 3840 | try cg.addTag(.select); |
| 3871 | return .stack; | 3841 | return .stack; |
| 3872 | } else { | 3842 | } else { |
| 3873 | try cg.lowerToStack(max_val); | 3843 | try cg.emitWValue(max_val); |
| 3874 | try cg.lowerToStack(op_val); | 3844 | try cg.emitWValue(op_val); |
| 3875 | | 3845 | |
| 3876 | const is_overflow = try cg.intCmp(int_ty, .lt, op_val, lhs); | 3846 | const is_overflow = try cg.intCmp(int_ty, .lt, op_val, lhs); |
| 3877 | try cg.emitWValue(is_overflow); | 3847 | try cg.emitWValue(is_overflow); |
| ... | @@ -3892,12 +3862,12 @@ fn intSubSat(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError | ... | @@ -3892,12 +3862,12 @@ fn intSubSat(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError |
| 3892 | const max_val = try cg.intMaxValue(int_ty); | 3862 | const max_val = try cg.intMaxValue(int_ty); |
| 3893 | const min_val = try cg.intMinValue(int_ty); | 3863 | const min_val = try cg.intMinValue(int_ty); |
| 3894 | | 3864 | |
| 3895 | try cg.lowerToStack(max_val); | 3865 | try cg.emitWValue(max_val); |
| 3896 | try cg.lowerToStack(min_val); | 3866 | try cg.emitWValue(min_val); |
| 3897 | try cg.emitWValue(rhs_is_neg); | 3867 | try cg.emitWValue(rhs_is_neg); |
| 3898 | try cg.addTag(.select); | 3868 | try cg.addTag(.select); |
| 3899 | | 3869 | |
| 3900 | try cg.lowerToStack(op_val); | 3870 | try cg.emitWValue(op_val); |
| 3901 | const overflow_cmp = try cg.intCmp(int_ty, .gt, op_val, lhs); | 3871 | const overflow_cmp = try cg.intCmp(int_ty, .gt, op_val, lhs); |
| 3902 | const is_overflow = try cg.intCmp(.u32, .neq, rhs_is_neg, overflow_cmp); | 3872 | const is_overflow = try cg.intCmp(.u32, .neq, rhs_is_neg, overflow_cmp); |
| 3903 | try cg.emitWValue(is_overflow); | 3873 | try cg.emitWValue(is_overflow); |
| ... | @@ -3906,8 +3876,8 @@ fn intSubSat(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError | ... | @@ -3906,8 +3876,8 @@ fn intSubSat(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError |
| 3906 | } else { | 3876 | } else { |
| 3907 | const zero = try cg.intZeroValue(int_ty); | 3877 | const zero = try cg.intZeroValue(int_ty); |
| 3908 | | 3878 | |
| 3909 | try cg.lowerToStack(zero); | 3879 | try cg.emitWValue(zero); |
| 3910 | try cg.lowerToStack(op_val); | 3880 | try cg.emitWValue(op_val); |
| 3911 | const is_overflow = try cg.intCmp(int_ty, .lt, lhs, rhs); | 3881 | const is_overflow = try cg.intCmp(int_ty, .lt, lhs, rhs); |
| 3912 | try cg.emitWValue(is_overflow); | 3882 | try cg.emitWValue(is_overflow); |
| 3913 | try cg.addTag(.select); | 3883 | try cg.addTag(.select); |
| ... | @@ -3931,10 +3901,10 @@ fn intMulSat(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError | ... | @@ -3931,10 +3901,10 @@ fn intMulSat(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError |
| 3931 | if (int_ty.is_signed) { | 3901 | if (int_ty.is_signed) { |
| 3932 | const min_val = try cg.intMinValue(int_ty); | 3902 | const min_val = try cg.intMinValue(int_ty); |
| 3933 | | 3903 | |
| 3934 | try cg.lowerToStack(min_val); | 3904 | try cg.emitWValue(min_val); |
| 3935 | | 3905 | |
| 3936 | try cg.lowerToStack(max_val); | 3906 | try cg.emitWValue(max_val); |
| 3937 | try cg.lowerToStack(op_val); | 3907 | try cg.emitWValue(op_val); |
| 3938 | const max_ext = try cg.intCast(ext_ty, int_ty, max_val); | 3908 | const max_ext = try cg.intCast(ext_ty, int_ty, max_val); |
| 3939 | const ov_pos = try cg.intCmp(ext_ty, .lt, max_ext, mul_ext); | 3909 | const ov_pos = try cg.intCmp(ext_ty, .lt, max_ext, mul_ext); |
| 3940 | try cg.emitWValue(ov_pos); | 3910 | try cg.emitWValue(ov_pos); |
| ... | @@ -3942,12 +3912,12 @@ fn intMulSat(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError | ... | @@ -3942,12 +3912,12 @@ fn intMulSat(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError |
| 3942 | | 3912 | |
| 3943 | const min_ext = try cg.intCast(ext_ty, int_ty, min_val); | 3913 | const min_ext = try cg.intCast(ext_ty, int_ty, min_val); |
| 3944 | const ov_neg = try cg.intCmp(ext_ty, .gt, min_ext, mul_ext); | 3914 | const ov_neg = try cg.intCmp(ext_ty, .gt, min_ext, mul_ext); |
| 3945 | try cg.lowerToStack(ov_neg); | 3915 | try cg.emitWValue(ov_neg); |
| 3946 | try cg.addTag(.select); | 3916 | try cg.addTag(.select); |
| 3947 | return .stack; | 3917 | return .stack; |
| 3948 | } else { | 3918 | } else { |
| 3949 | try cg.lowerToStack(max_val); | 3919 | try cg.emitWValue(max_val); |
| 3950 | try cg.lowerToStack(op_val); | 3920 | try cg.emitWValue(op_val); |
| 3951 | const max_ext = try cg.intCast(ext_ty, int_ty, max_val); | 3921 | const max_ext = try cg.intCast(ext_ty, int_ty, max_val); |
| 3952 | const is_overflow = try cg.intCmp(ext_ty, .lt, max_ext, mul_ext); | 3922 | const is_overflow = try cg.intCmp(ext_ty, .lt, max_ext, mul_ext); |
| 3953 | try cg.emitWValue(is_overflow); | 3923 | try cg.emitWValue(is_overflow); |
| ... | @@ -3970,20 +3940,20 @@ fn intShlSat(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError | ... | @@ -3970,20 +3940,20 @@ fn intShlSat(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError |
| 3970 | const zero = try cg.intZeroValue(int_ty); | 3940 | const zero = try cg.intZeroValue(int_ty); |
| 3971 | const min_val = try cg.intMinValue(int_ty); | 3941 | const min_val = try cg.intMinValue(int_ty); |
| 3972 | | 3942 | |
| 3973 | try cg.lowerToStack(min_val); | 3943 | try cg.emitWValue(min_val); |
| 3974 | try cg.lowerToStack(max_val); | 3944 | try cg.emitWValue(max_val); |
| 3975 | const lhs_is_neg = try cg.intCmp(int_ty, .lt, lhs, zero); | 3945 | const lhs_is_neg = try cg.intCmp(int_ty, .lt, lhs, zero); |
| 3976 | try cg.emitWValue(lhs_is_neg); | 3946 | try cg.emitWValue(lhs_is_neg); |
| 3977 | try cg.addTag(.select); | 3947 | try cg.addTag(.select); |
| 3978 | | 3948 | |
| 3979 | try cg.lowerToStack(op_val); | 3949 | try cg.emitWValue(op_val); |
| 3980 | const is_overflow = try cg.intCmp(int_ty, .neq, check_val, lhs); | 3950 | const is_overflow = try cg.intCmp(int_ty, .neq, check_val, lhs); |
| 3981 | try cg.emitWValue(is_overflow); | 3951 | try cg.emitWValue(is_overflow); |
| 3982 | try cg.addTag(.select); | 3952 | try cg.addTag(.select); |
| 3983 | return .stack; | 3953 | return .stack; |
| 3984 | } else { | 3954 | } else { |
| 3985 | try cg.lowerToStack(max_val); | 3955 | try cg.emitWValue(max_val); |
| 3986 | try cg.lowerToStack(op_val); | 3956 | try cg.emitWValue(op_val); |
| 3987 | const is_overflow = try cg.intCmp(int_ty, .neq, check_val, lhs); | 3957 | const is_overflow = try cg.intCmp(int_ty, .neq, check_val, lhs); |
| 3988 | try cg.emitWValue(is_overflow); | 3958 | try cg.emitWValue(is_overflow); |
| 3989 | try cg.addTag(.select); | 3959 | try cg.addTag(.select); |
| ... | @@ -4055,9 +4025,9 @@ fn intAddOverflow(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerErro | ... | @@ -4055,9 +4025,9 @@ fn intAddOverflow(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerErro |
| 4055 | else => { | 4025 | else => { |
| 4056 | const result = try cg.allocInt(ty); | 4026 | const result = try cg.allocInt(ty); |
| 4057 | | 4027 | |
| 4058 | try cg.lowerToStack(result); | 4028 | try cg.emitWValue(result); |
| 4059 | try cg.lowerToStack(lhs); | 4029 | try cg.emitWValue(lhs); |
| 4060 | try cg.lowerToStack(rhs); | 4030 | try cg.emitWValue(rhs); |
| 4061 | try cg.addImm32(@intFromBool(ty.is_signed)); | 4031 | try cg.addImm32(@intFromBool(ty.is_signed)); |
| 4062 | try cg.addImm32(ty.bits); | 4032 | try cg.addImm32(ty.bits); |
| 4063 | try cg.addCallIntrinsic(.__addo_limb64); | 4033 | try cg.addCallIntrinsic(.__addo_limb64); |
| ... | @@ -4087,9 +4057,9 @@ fn intSubOverflow(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerErro | ... | @@ -4087,9 +4057,9 @@ fn intSubOverflow(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerErro |
| 4087 | else => { | 4057 | else => { |
| 4088 | const result = try cg.allocInt(ty); | 4058 | const result = try cg.allocInt(ty); |
| 4089 | | 4059 | |
| 4090 | try cg.lowerToStack(result); | 4060 | try cg.emitWValue(result); |
| 4091 | try cg.lowerToStack(lhs); | 4061 | try cg.emitWValue(lhs); |
| 4092 | try cg.lowerToStack(rhs); | 4062 | try cg.emitWValue(rhs); |
| 4093 | try cg.addImm32(@intFromBool(ty.is_signed)); | 4063 | try cg.addImm32(@intFromBool(ty.is_signed)); |
| 4094 | try cg.addImm32(ty.bits); | 4064 | try cg.addImm32(ty.bits); |
| 4095 | try cg.addCallIntrinsic(.__subo_limb64); | 4065 | try cg.addCallIntrinsic(.__subo_limb64); |
| ... | @@ -4145,9 +4115,9 @@ fn intMulOverflow(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) Inner | ... | @@ -4145,9 +4115,9 @@ fn intMulOverflow(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) Inner |
| 4145 | } else { | 4115 | } else { |
| 4146 | const result = try cg.allocInt(int_ty); | 4116 | const result = try cg.allocInt(int_ty); |
| 4147 | | 4117 | |
| 4148 | try cg.lowerToStack(result); | 4118 | try cg.emitWValue(result); |
| 4149 | try cg.lowerToStack(lhs); | 4119 | try cg.emitWValue(lhs); |
| 4150 | try cg.lowerToStack(rhs); | 4120 | try cg.emitWValue(rhs); |
| 4151 | try cg.addImm32(@intFromBool(int_ty.is_signed)); | 4121 | try cg.addImm32(@intFromBool(int_ty.is_signed)); |
| 4152 | try cg.addImm32(int_ty.bits); | 4122 | try cg.addImm32(int_ty.bits); |
| 4153 | try cg.addCallIntrinsic(.__mulo_limb64); | 4123 | try cg.addCallIntrinsic(.__mulo_limb64); |
| ... | @@ -4174,9 +4144,9 @@ fn intShlOverflow(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerErro | ... | @@ -4174,9 +4144,9 @@ fn intShlOverflow(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerErro |
| 4174 | else => { | 4144 | else => { |
| 4175 | const result = try cg.allocInt(ty); | 4145 | const result = try cg.allocInt(ty); |
| 4176 | | 4146 | |
| 4177 | try cg.lowerToStack(result); | 4147 | try cg.emitWValue(result); |
| 4178 | try cg.lowerToStack(lhs); | 4148 | try cg.emitWValue(lhs); |
| 4179 | try cg.lowerToStack(rhs); | 4149 | try cg.emitWValue(rhs); |
| 4180 | try cg.addImm32(@intFromBool(ty.is_signed)); | 4150 | try cg.addImm32(@intFromBool(ty.is_signed)); |
| 4181 | try cg.addImm32(ty.bits); | 4151 | try cg.addImm32(ty.bits); |
| 4182 | try cg.addCallIntrinsic(.__shlo_limb64); | 4152 | try cg.addCallIntrinsic(.__shlo_limb64); |
| ... | @@ -4213,15 +4183,15 @@ fn intCast(cg: *CodeGen, dest_ty: IntType, src_ty: IntType, operand: WValue) Inn | ... | @@ -4213,15 +4183,15 @@ fn intCast(cg: *CodeGen, dest_ty: IntType, src_ty: IntType, operand: WValue) Inn |
| 4213 | } else { | 4183 | } else { |
| 4214 | var src_len: u32 = undefined; | 4184 | var src_len: u32 = undefined; |
| 4215 | if (src_bits == 32) { | 4185 | if (src_bits == 32) { |
| 4216 | try cg.emitWValue(result); | 4186 | try cg.emitMemBase(result); |
| 4217 | try cg.emitWValue(operand); | 4187 | try cg.emitWValue(operand); |
| 4218 | try cg.addTag(if (src_ty.is_signed) .i64_extend_i32_s else .i64_extend_i32_u); | 4188 | try cg.addTag(if (src_ty.is_signed) .i64_extend_i32_s else .i64_extend_i32_u); |
| 4219 | try cg.store(.stack, .stack, .u64, .{ .offset = result.offset() }); | 4189 | try cg.store(.stack, .stack, .u64, .{ .offset = result.memOffset() }); |
| 4220 | src_len = 8; | 4190 | src_len = 8; |
| 4221 | } else if (src_bits == 64) { | 4191 | } else if (src_bits == 64) { |
| 4222 | try cg.emitWValue(result); | 4192 | try cg.emitMemBase(result); |
| 4223 | try cg.emitWValue(operand); | 4193 | try cg.emitWValue(operand); |
| 4224 | try cg.store(.stack, .stack, .u64, .{ .offset = result.offset() }); | 4194 | try cg.store(.stack, .stack, .u64, .{ .offset = result.memOffset() }); |
| 4225 | src_len = 8; | 4195 | src_len = 8; |
| 4226 | } else { | 4196 | } else { |
| 4227 | src_len = src_bits / 8; | 4197 | src_len = src_bits / 8; |
| ... | @@ -4230,7 +4200,7 @@ fn intCast(cg: *CodeGen, dest_ty: IntType, src_ty: IntType, operand: WValue) Inn | ... | @@ -4230,7 +4200,7 @@ fn intCast(cg: *CodeGen, dest_ty: IntType, src_ty: IntType, operand: WValue) Inn |
| 4230 | | 4200 | |
| 4231 | if (dest_bits == 128) { | 4201 | if (dest_bits == 128) { |
| 4232 | if (src_ty.is_signed) { | 4202 | if (src_ty.is_signed) { |
| 4233 | try cg.emitWValue(result); | 4203 | try cg.emitMemBase(result); |
| 4234 | if (src_bits == 32) { | 4204 | if (src_bits == 32) { |
| 4235 | try cg.emitWValue(operand); | 4205 | try cg.emitWValue(operand); |
| 4236 | try cg.addTag(if (dest_ty.is_signed) .i64_extend_i32_s else .i64_extend_i32_u); | 4206 | try cg.addTag(if (dest_ty.is_signed) .i64_extend_i32_s else .i64_extend_i32_u); |
| ... | @@ -4238,7 +4208,7 @@ fn intCast(cg: *CodeGen, dest_ty: IntType, src_ty: IntType, operand: WValue) Inn | ... | @@ -4238,7 +4208,7 @@ fn intCast(cg: *CodeGen, dest_ty: IntType, src_ty: IntType, operand: WValue) Inn |
| 4238 | try cg.emitWValue(operand); | 4208 | try cg.emitWValue(operand); |
| 4239 | } else unreachable; | 4209 | } else unreachable; |
| 4240 | const shr = try cg.intShr(IntType.i64, .stack, .{ .imm32 = 63 }); | 4210 | const shr = try cg.intShr(IntType.i64, .stack, .{ .imm32 = 63 }); |
| 4241 | try cg.store(.stack, shr, .u64, .{ .offset = 8 + result.offset() }); | 4211 | try cg.store(.stack, shr, .u64, .{ .offset = result.memOffset() + 8 }); |
| 4242 | } else { | 4212 | } else { |
| 4243 | try cg.store(result, .{ .imm64 = 0 }, .u64, .{ .offset = 8 }); | 4213 | try cg.store(result, .{ .imm64 = 0 }, .u64, .{ .offset = 8 }); |
| 4244 | } | 4214 | } |
| ... | @@ -4642,20 +4612,22 @@ fn floatNeg(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { | ... | @@ -4642,20 +4612,22 @@ fn floatNeg(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { |
| 4642 | }, | 4612 | }, |
| 4643 | .f80, .f128 => { | 4613 | .f80, .f128 => { |
| 4644 | const result = try cg.allocStack(Type.f128); | 4614 | const result = try cg.allocStack(Type.f128); |
| 4645 | try cg.emitWValue(result); | 4615 | const result_offset = result.memOffset(); |
| 4646 | try cg.emitWValue(arg); | 4616 | const arg_offset = arg.memOffset(); |
| 4647 | try cg.addMemArg(.i64_load, .{ .offset = 0 + arg.offset(), .alignment = .@"2" }); | 4617 | try cg.emitMemBase(result); |
| 4648 | try cg.addMemArg(.i64_store, .{ .offset = 0 + result.offset(), .alignment = .@"2" }); | 4618 | try cg.emitMemBase(arg); |
| 4649 | try cg.emitWValue(result); | 4619 | try cg.addMemArg(.i64_load, .{ .offset = arg_offset, .alignment = .@"2" }); |
| 4650 | try cg.emitWValue(arg); | 4620 | try cg.addMemArg(.i64_store, .{ .offset = result_offset, .alignment = .@"2" }); |
| 4651 | try cg.addMemArg(.i64_load, .{ .offset = 8 + arg.offset(), .alignment = .@"2" }); | 4621 | try cg.emitMemBase(result); |
| | 4622 | try cg.emitMemBase(arg); |
| | 4623 | try cg.addMemArg(.i64_load, .{ .offset = arg_offset + 8, .alignment = .@"2" }); |
| 4652 | if (ty == .f80) { | 4624 | if (ty == .f80) { |
| 4653 | try cg.addImm64(0x8000); | 4625 | try cg.addImm64(0x8000); |
| 4654 | } else { | 4626 | } else { |
| 4655 | try cg.addImm64(0x8000000000000000); | 4627 | try cg.addImm64(0x8000000000000000); |
| 4656 | } | 4628 | } |
| 4657 | try cg.addTag(.i64_xor); | 4629 | try cg.addTag(.i64_xor); |
| 4658 | try cg.addMemArg(.i64_store, .{ .offset = 8 + result.offset(), .alignment = .@"2" }); | 4630 | try cg.addMemArg(.i64_store, .{ .offset = result_offset + 8, .alignment = .@"2" }); |
| 4659 | return result; | 4631 | return result; |
| 4660 | }, | 4632 | }, |
| 4661 | } | 4633 | } |
| ... | @@ -4681,20 +4653,22 @@ fn floatAbs(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { | ... | @@ -4681,20 +4653,22 @@ fn floatAbs(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { |
| 4681 | }, | 4653 | }, |
| 4682 | .f80, .f128 => { | 4654 | .f80, .f128 => { |
| 4683 | const result = try cg.allocStack(Type.f128); | 4655 | const result = try cg.allocStack(Type.f128); |
| 4684 | try cg.emitWValue(result); | 4656 | const result_offset = result.memOffset(); |
| 4685 | try cg.emitWValue(arg); | 4657 | const arg_offset = arg.memOffset(); |
| 4686 | try cg.addMemArg(.i64_load, .{ .offset = 0 + arg.offset(), .alignment = .@"2" }); | 4658 | try cg.emitMemBase(result); |
| 4687 | try cg.addMemArg(.i64_store, .{ .offset = 0 + result.offset(), .alignment = .@"2" }); | 4659 | try cg.emitMemBase(arg); |
| 4688 | try cg.emitWValue(result); | 4660 | try cg.addMemArg(.i64_load, .{ .offset = arg_offset, .alignment = .@"2" }); |
| 4689 | try cg.emitWValue(arg); | 4661 | try cg.addMemArg(.i64_store, .{ .offset = result_offset, .alignment = .@"2" }); |
| 4690 | try cg.addMemArg(.i64_load, .{ .offset = 8 + arg.offset(), .alignment = .@"2" }); | 4662 | try cg.emitMemBase(result); |
| | 4663 | try cg.emitMemBase(arg); |
| | 4664 | try cg.addMemArg(.i64_load, .{ .offset = arg_offset + 8, .alignment = .@"2" }); |
| 4691 | if (ty == .f80) { | 4665 | if (ty == .f80) { |
| 4692 | try cg.addImm64(0x7FFF); | 4666 | try cg.addImm64(0x7FFF); |
| 4693 | } else { | 4667 | } else { |
| 4694 | try cg.addImm64(0x7FFFFFFFFFFFFFFF); | 4668 | try cg.addImm64(0x7FFFFFFFFFFFFFFF); |
| 4695 | } | 4669 | } |
| 4696 | try cg.addTag(.i64_and); | 4670 | try cg.addTag(.i64_and); |
| 4697 | try cg.addMemArg(.i64_store, .{ .offset = 8 + result.offset(), .alignment = .@"2" }); | 4671 | try cg.addMemArg(.i64_store, .{ .offset = result_offset + 8, .alignment = .@"2" }); |
| 4698 | return result; | 4672 | return result; |
| 4699 | }, | 4673 | }, |
| 4700 | } | 4674 | } |
| ... | @@ -5377,8 +5351,8 @@ fn intCmp(cg: *CodeGen, ty: IntType, op: std.math.CompareOperator, lhs: WValue, | ... | @@ -5377,8 +5351,8 @@ fn intCmp(cg: *CodeGen, ty: IntType, op: std.math.CompareOperator, lhs: WValue, |
| 5377 | 0 => unreachable, | 5351 | 0 => unreachable, |
| 5378 | 1...32 => { | 5352 | 1...32 => { |
| 5379 | // lhs or rhs could be stack pointers | 5353 | // lhs or rhs could be stack pointers |
| 5380 | try cg.lowerToStack(lhs); | 5354 | try cg.emitWValue(lhs); |
| 5381 | try cg.lowerToStack(rhs); | 5355 | try cg.emitWValue(rhs); |
| 5382 | const opcode: Mir.Inst.Tag = switch (op) { | 5356 | const opcode: Mir.Inst.Tag = switch (op) { |
| 5383 | .eq => .i32_eq, | 5357 | .eq => .i32_eq, |
| 5384 | .neq => .i32_ne, | 5358 | .neq => .i32_ne, |
| ... | @@ -5392,8 +5366,8 @@ fn intCmp(cg: *CodeGen, ty: IntType, op: std.math.CompareOperator, lhs: WValue, | ... | @@ -5392,8 +5366,8 @@ fn intCmp(cg: *CodeGen, ty: IntType, op: std.math.CompareOperator, lhs: WValue, |
| 5392 | }, | 5366 | }, |
| 5393 | 33...64 => { | 5367 | 33...64 => { |
| 5394 | // lhs or rhs could be stack pointers | 5368 | // lhs or rhs could be stack pointers |
| 5395 | try cg.lowerToStack(lhs); | 5369 | try cg.emitWValue(lhs); |
| 5396 | try cg.lowerToStack(rhs); | 5370 | try cg.emitWValue(rhs); |
| 5397 | const opcode: Mir.Inst.Tag = switch (op) { | 5371 | const opcode: Mir.Inst.Tag = switch (op) { |
| 5398 | .eq => .i64_eq, | 5372 | .eq => .i64_eq, |
| 5399 | .neq => .i64_ne, | 5373 | .neq => .i64_ne, |
| ... | @@ -5442,8 +5416,8 @@ fn intCmp(cg: *CodeGen, ty: IntType, op: std.math.CompareOperator, lhs: WValue, | ... | @@ -5442,8 +5416,8 @@ fn intCmp(cg: *CodeGen, ty: IntType, op: std.math.CompareOperator, lhs: WValue, |
| 5442 | return .stack; | 5416 | return .stack; |
| 5443 | }, | 5417 | }, |
| 5444 | else => { | 5418 | else => { |
| 5445 | try cg.lowerToStack(lhs); | 5419 | try cg.emitWValue(lhs); |
| 5446 | try cg.lowerToStack(rhs); | 5420 | try cg.emitWValue(rhs); |
| 5447 | try cg.addImm32(@intFromBool(ty.is_signed)); | 5421 | try cg.addImm32(@intFromBool(ty.is_signed)); |
| 5448 | try cg.addImm32(ty.bits); | 5422 | try cg.addImm32(ty.bits); |
| 5449 | try cg.addCallIntrinsic(.__cmp_limb64); | 5423 | try cg.addCallIntrinsic(.__cmp_limb64); |
| ... | @@ -5554,7 +5528,7 @@ fn airBr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5554,7 +5528,7 @@ fn airBr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5554 | // if operand has codegen bits we should break with a value | 5528 | // if operand has codegen bits we should break with a value |
| 5555 | if (block.value != .none) { | 5529 | if (block.value != .none) { |
| 5556 | const operand = try cg.resolveInst(br.operand); | 5530 | const operand = try cg.resolveInst(br.operand); |
| 5557 | try cg.lowerToStack(operand); | 5531 | try cg.emitWValue(operand); |
| 5558 | try cg.addLocal(.local_set, block.value.local.value); | 5532 | try cg.addLocal(.local_set, block.value.local.value); |
| 5559 | } | 5533 | } |
| 5560 | | 5534 | |
| ... | @@ -5618,11 +5592,12 @@ fn airIntFromPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5618,11 +5592,12 @@ fn airIntFromPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5618 | assert(operand_ty.abiAlignment(zcu) == dest_ty.abiAlignment(zcu)); | 5592 | assert(operand_ty.abiAlignment(zcu) == dest_ty.abiAlignment(zcu)); |
| 5619 | | 5593 | |
| 5620 | const operand = try cg.resolveInst(ty_op.operand); | 5594 | const operand = try cg.resolveInst(ty_op.operand); |
| 5621 | const result = switch (operand) { | 5595 | if (operand == .stack_offset) { |
| 5622 | .stack_offset => try cg.buildPointerOffset(operand, 0, .new), | 5596 | // materialize operand, we assume precomputed value is more efficient |
| 5623 | else => operand, | 5597 | try cg.emitWValue(operand); |
| 5624 | }; | 5598 | return cg.finishAir(inst, .stack, &.{ty_op.operand}); |
| 5625 | return cg.finishAir(inst, result, &.{ty_op.operand}); | 5599 | } |
| | 5600 | return cg.finishAir(inst, operand, &.{ty_op.operand}); |
| 5626 | } | 5601 | } |
| 5627 | | 5602 | |
| 5628 | fn airUnionFromEnum(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 5603 | fn airUnionFromEnum(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| ... | @@ -5801,16 +5776,7 @@ fn structFieldPtr( | ... | @@ -5801,16 +5776,7 @@ fn structFieldPtr( |
| 5801 | }, | 5776 | }, |
| 5802 | else => struct_ty.structFieldOffset(index, zcu), | 5777 | else => struct_ty.structFieldOffset(index, zcu), |
| 5803 | }; | 5778 | }; |
| 5804 | // save a load and store when we can simply reuse the operand | 5779 | return cg.offsetPointer(struct_ptr, offset); |
| 5805 | if (offset == 0) { | | |
| 5806 | return struct_ptr; | | |
| 5807 | } | | |
| 5808 | switch (struct_ptr) { | | |
| 5809 | .stack_offset => |stack_offset| { | | |
| 5810 | return .{ .stack_offset = .{ .value = stack_offset.value + @as(u32, @intCast(offset)), .references = 1 } }; | | |
| 5811 | }, | | |
| 5812 | else => return cg.buildPointerOffset(struct_ptr, offset, .new), | | |
| 5813 | } | | |
| 5814 | } | 5780 | } |
| 5815 | | 5781 | |
| 5816 | fn airAggFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 5782 | fn airAggFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| ... | @@ -5832,12 +5798,7 @@ fn airAggFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -5832,12 +5798,7 @@ fn airAggFieldVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5832 | return cg.fail("Field type '{f}' too big to fit into stack frame", .{field_ty.fmt(pt)}); | 5798 | return cg.fail("Field type '{f}' too big to fit into stack frame", .{field_ty.fmt(pt)}); |
| 5833 | }; | 5799 | }; |
| 5834 | if (isByRef(field_ty, zcu, cg.target)) { | 5800 | if (isByRef(field_ty, zcu, cg.target)) { |
| 5835 | switch (operand) { | 5801 | break :result try cg.offsetPointer(operand, offset); |
| 5836 | .stack_offset => |stack_offset| { | | |
| 5837 | break :result .{ .stack_offset = .{ .value = stack_offset.value + offset, .references = 1 } }; | | |
| 5838 | }, | | |
| 5839 | else => break :result try cg.buildPointerOffset(operand, offset, .new), | | |
| 5840 | } | | |
| 5841 | } | 5802 | } |
| 5842 | break :result try cg.load(operand, field_ty, .{ .offset = offset }); | 5803 | break :result try cg.load(operand, field_ty, .{ .offset = offset }); |
| 5843 | }, | 5804 | }, |
| ... | @@ -5859,7 +5820,7 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner | ... | @@ -5859,7 +5820,7 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index, is_dispatch_loop: bool) Inner |
| 5859 | const target = if (is_dispatch_loop) target: { | 5820 | const target = if (is_dispatch_loop) target: { |
| 5860 | const initial_target = try cg.resolveInst(switch_br.operand); | 5821 | const initial_target = try cg.resolveInst(switch_br.operand); |
| 5861 | const target: WValue = try cg.allocLocal(target_ty); | 5822 | const target: WValue = try cg.allocLocal(target_ty); |
| 5862 | try cg.lowerToStack(initial_target); | 5823 | try cg.emitWValue(initial_target); |
| 5863 | try cg.addLocal(.local_set, target.local.value); | 5824 | try cg.addLocal(.local_set, target.local.value); |
| 5864 | | 5825 | |
| 5865 | try cg.startBlock(.loop, .empty); // dispatch loop start | 5826 | try cg.startBlock(.loop, .empty); // dispatch loop start |
| ... | @@ -6052,7 +6013,7 @@ fn airSwitchDispatch(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6052,7 +6013,7 @@ fn airSwitchDispatch(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6052 | const switch_loop = cg.blocks.get(br.block_inst).?; | 6013 | const switch_loop = cg.blocks.get(br.block_inst).?; |
| 6053 | | 6014 | |
| 6054 | const operand = try cg.resolveInst(br.operand); | 6015 | const operand = try cg.resolveInst(br.operand); |
| 6055 | try cg.lowerToStack(operand); | 6016 | try cg.emitWValue(operand); |
| 6056 | try cg.addLocal(.local_set, switch_loop.value.local.value); | 6017 | try cg.addLocal(.local_set, switch_loop.value.local.value); |
| 6057 | | 6018 | |
| 6058 | const idx: u32 = cg.block_depth - switch_loop.label; | 6019 | const idx: u32 = cg.block_depth - switch_loop.label; |
| ... | @@ -6080,12 +6041,14 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode, op_kind | ... | @@ -6080,12 +6041,14 @@ fn airIsErr(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode, op_kind |
| 6080 | } | 6041 | } |
| 6081 | } | 6042 | } |
| 6082 | | 6043 | |
| 6083 | try cg.emitWValue(operand); | | |
| 6084 | if (op_kind == .ptr or pl_ty.hasRuntimeBits(zcu)) { | 6044 | if (op_kind == .ptr or pl_ty.hasRuntimeBits(zcu)) { |
| | 6045 | try cg.emitMemBase(operand); |
| 6085 | try cg.addMemArg(.i32_load16_u, .{ | 6046 | try cg.addMemArg(.i32_load16_u, .{ |
| 6086 | .offset = operand.offset() + @as(u32, @intCast(errUnionErrorOffset(pl_ty, zcu))), | 6047 | .offset = operand.memOffset() + errUnionErrorOffset(pl_ty, zcu), |
| 6087 | .alignment = Type.anyerror.abiAlignment(zcu).toStdMem(), | 6048 | .alignment = Type.anyerror.abiAlignment(zcu).toStdMem(), |
| 6088 | }); | 6049 | }); |
| | 6050 | } else { |
| | 6051 | try cg.emitWValue(operand); |
| 6089 | } | 6052 | } |
| 6090 | | 6053 | |
| 6091 | // Compare the error value with '0' | 6054 | // Compare the error value with '0' |
| ... | @@ -6116,9 +6079,9 @@ fn airUnwrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) | ... | @@ -6116,9 +6079,9 @@ fn airUnwrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index, op_is_ptr: bool) |
| 6116 | } | 6079 | } |
| 6117 | } | 6080 | } |
| 6118 | | 6081 | |
| 6119 | const pl_offset: u32 = @intCast(errUnionPayloadOffset(payload_ty, zcu)); | 6082 | const pl_offset = errUnionPayloadOffset(payload_ty, zcu); |
| 6120 | if (op_is_ptr or isByRef(payload_ty, zcu, cg.target)) { | 6083 | if (op_is_ptr or isByRef(payload_ty, zcu, cg.target)) { |
| 6121 | break :result try cg.buildPointerOffset(operand, pl_offset, .new); | 6084 | break :result try cg.offsetPointer(operand, pl_offset); |
| 6122 | } else { | 6085 | } else { |
| 6123 | assert(isByRef(eu_ty, zcu, cg.target)); | 6086 | assert(isByRef(eu_ty, zcu, cg.target)); |
| 6124 | break :result try cg.load(operand, payload_ty, .{ .offset = pl_offset }); | 6087 | break :result try cg.load(operand, payload_ty, .{ .offset = pl_offset }); |
| ... | @@ -6169,15 +6132,14 @@ fn airWrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6169,15 +6132,14 @@ fn airWrapErrUnionPayload(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6169 | } | 6132 | } |
| 6170 | | 6133 | |
| 6171 | const err_union = try cg.allocStack(err_ty); | 6134 | const err_union = try cg.allocStack(err_ty); |
| 6172 | const payload_ptr = try cg.buildPointerOffset(err_union, @as(u32, @intCast(errUnionPayloadOffset(pl_ty, zcu))), .new); | 6135 | try cg.store(err_union, operand, pl_ty, .{ .offset = errUnionPayloadOffset(pl_ty, zcu) }); |
| 6173 | try cg.store(payload_ptr, operand, pl_ty, .{}); | | |
| 6174 | | 6136 | |
| 6175 | // ensure we also write '0' to the error part, so any present stack value gets overwritten by it. | 6137 | // ensure we also write '0' to the error part, so any present stack value gets overwritten by it. |
| 6176 | try cg.emitWValue(err_union); | 6138 | try cg.emitMemBase(err_union); |
| 6177 | try cg.addImm32(0); | 6139 | try cg.addImm32(0); |
| 6178 | const err_val_offset: u32 = @intCast(errUnionErrorOffset(pl_ty, zcu)); | 6140 | const err_val_offset = errUnionErrorOffset(pl_ty, zcu); |
| 6179 | try cg.addMemArg(.i32_store16, .{ | 6141 | try cg.addMemArg(.i32_store16, .{ |
| 6180 | .offset = err_union.offset() + err_val_offset, | 6142 | .offset = err_union.memOffset() + err_val_offset, |
| 6181 | .alignment = .@"2", | 6143 | .alignment = .@"2", |
| 6182 | }); | 6144 | }); |
| 6183 | break :result err_union; | 6145 | break :result err_union; |
| ... | @@ -6203,7 +6165,7 @@ fn airWrapErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6203,7 +6165,7 @@ fn airWrapErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6203 | try cg.store(err_union, operand, .anyerror, .{ .offset = errUnionErrorOffset(pl_ty, zcu) }); | 6165 | try cg.store(err_union, operand, .anyerror, .{ .offset = errUnionErrorOffset(pl_ty, zcu) }); |
| 6204 | | 6166 | |
| 6205 | // write 'undefined' to the payload | 6167 | // write 'undefined' to the payload |
| 6206 | const payload_ptr = try cg.buildPointerOffset(err_union, @as(u32, @intCast(errUnionPayloadOffset(pl_ty, zcu))), .new); | 6168 | const payload_ptr = try cg.offsetPointer(err_union, errUnionPayloadOffset(pl_ty, zcu)); |
| 6207 | const len = @as(u32, @intCast(err_ty.errorUnionPayload(zcu).abiSize(zcu))); | 6169 | const len = @as(u32, @intCast(err_ty.errorUnionPayload(zcu).abiSize(zcu))); |
| 6208 | try cg.memset(Type.u8, payload_ptr, .{ .imm32 = len }, .{ .imm32 = 0xaa }); | 6170 | try cg.memset(Type.u8, payload_ptr, .{ .imm32 = len }, .{ .imm32 = 0xaa }); |
| 6209 | | 6171 | |
| ... | @@ -6228,7 +6190,6 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode, op_kin | ... | @@ -6228,7 +6190,6 @@ fn airIsNull(cg: *CodeGen, inst: Air.Inst.Index, opcode: std.wasm.Opcode, op_kin |
| 6228 | fn isNull(cg: *CodeGen, operand: WValue, op_ty: Type, opcode: std.wasm.Opcode, op_kind: OpKind) InnerError!WValue { | 6190 | fn isNull(cg: *CodeGen, operand: WValue, op_ty: Type, opcode: std.wasm.Opcode, op_kind: OpKind) InnerError!WValue { |
| 6229 | const pt = cg.pt; | 6191 | const pt = cg.pt; |
| 6230 | const zcu = pt.zcu; | 6192 | const zcu = pt.zcu; |
| 6231 | try cg.emitWValue(operand); | | |
| 6232 | const optional_ty = switch (op_kind) { | 6193 | const optional_ty = switch (op_kind) { |
| 6233 | .value => op_ty, | 6194 | .value => op_ty, |
| 6234 | .ptr => op_ty.childType(zcu), | 6195 | .ptr => op_ty.childType(zcu), |
| ... | @@ -6241,19 +6202,27 @@ fn isNull(cg: *CodeGen, operand: WValue, op_ty: Type, opcode: std.wasm.Opcode, o | ... | @@ -6241,19 +6202,27 @@ fn isNull(cg: *CodeGen, operand: WValue, op_ty: Type, opcode: std.wasm.Opcode, o |
| 6241 | const offset = std.math.cast(u32, payload_ty.abiSize(zcu)) orelse { | 6202 | const offset = std.math.cast(u32, payload_ty.abiSize(zcu)) orelse { |
| 6242 | return cg.fail("Optional type {f} too big to fit into stack frame", .{optional_ty.fmt(pt)}); | 6203 | return cg.fail("Optional type {f} too big to fit into stack frame", .{optional_ty.fmt(pt)}); |
| 6243 | }; | 6204 | }; |
| 6244 | try cg.addMemArg(.i32_load8_u, .{ .offset = operand.offset() + offset, .alignment = .@"1" }); | 6205 | try cg.emitMemBase(operand); |
| | 6206 | try cg.addMemArg(.i32_load8_u, .{ .offset = operand.memOffset() + offset, .alignment = .@"1" }); |
| | 6207 | } else { |
| | 6208 | try cg.emitWValue(operand); |
| 6245 | } | 6209 | } |
| 6246 | } else if (payload_ty.isSlice(zcu)) { | 6210 | } else if (payload_ty.isSlice(zcu)) { |
| | 6211 | const base_offset = operand.memOffset(); |
| | 6212 | try cg.emitMemBase(operand); |
| 6247 | switch (cg.ptr_size) { | 6213 | switch (cg.ptr_size) { |
| 6248 | .wasm32 => try cg.addMemArg(.i32_load, .{ .offset = operand.offset(), .alignment = .@"4" }), | 6214 | .wasm32 => try cg.addMemArg(.i32_load, .{ .offset = base_offset, .alignment = .@"4" }), |
| 6249 | .wasm64 => try cg.addMemArg(.i64_load, .{ .offset = operand.offset(), .alignment = .@"8" }), | 6215 | .wasm64 => try cg.addMemArg(.i64_load, .{ .offset = base_offset, .alignment = .@"8" }), |
| 6250 | } | 6216 | } |
| 6251 | } else { | 6217 | } else { |
| 6252 | if (op_kind == .ptr) { | 6218 | if (op_kind == .ptr) { |
| | 6219 | try cg.emitMemBase(operand); |
| 6253 | try cg.addMemArg(.i32_load, .{ | 6220 | try cg.addMemArg(.i32_load, .{ |
| 6254 | .offset = operand.offset(), | 6221 | .offset = operand.memOffset(), |
| 6255 | .alignment = .@"4", | 6222 | .alignment = .@"4", |
| 6256 | }); | 6223 | }); |
| | 6224 | } else { |
| | 6225 | try cg.emitWValue(operand); |
| 6257 | } | 6226 | } |
| 6258 | } | 6227 | } |
| 6259 | | 6228 | |
| ... | @@ -6278,7 +6247,7 @@ fn airOptionalPayload(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6278,7 +6247,7 @@ fn airOptionalPayload(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6278 | if (opt_ty.optionalReprIsPayload(zcu)) break :result operand; | 6247 | if (opt_ty.optionalReprIsPayload(zcu)) break :result operand; |
| 6279 | | 6248 | |
| 6280 | if (isByRef(payload_ty, zcu, cg.target)) { | 6249 | if (isByRef(payload_ty, zcu, cg.target)) { |
| 6281 | break :result try cg.buildPointerOffset(operand, 0, .new); | 6250 | break :result operand; |
| 6282 | } | 6251 | } |
| 6283 | | 6252 | |
| 6284 | break :result try cg.load(operand, payload_ty, .{}); | 6253 | break :result try cg.load(operand, payload_ty, .{}); |
| ... | @@ -6298,7 +6267,7 @@ fn airOptionalPayloadPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6298,7 +6267,7 @@ fn airOptionalPayloadPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6298 | break :result operand; | 6267 | break :result operand; |
| 6299 | } | 6268 | } |
| 6300 | | 6269 | |
| 6301 | break :result try cg.buildPointerOffset(operand, 0, .new); | 6270 | break :result operand; |
| 6302 | }; | 6271 | }; |
| 6303 | return cg.finishAir(inst, result, &.{ty_op.operand}); | 6272 | return cg.finishAir(inst, result, &.{ty_op.operand}); |
| 6304 | } | 6273 | } |
| ... | @@ -6319,12 +6288,11 @@ fn airOptionalPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void | ... | @@ -6319,12 +6288,11 @@ fn airOptionalPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void |
| 6319 | return cg.fail("Optional type {f} too big to fit into stack frame", .{opt_ty.fmt(pt)}); | 6288 | return cg.fail("Optional type {f} too big to fit into stack frame", .{opt_ty.fmt(pt)}); |
| 6320 | }; | 6289 | }; |
| 6321 | | 6290 | |
| 6322 | try cg.emitWValue(operand); | 6291 | try cg.emitMemBase(operand); |
| 6323 | try cg.addImm32(1); | 6292 | try cg.addImm32(1); |
| 6324 | try cg.addMemArg(.i32_store8, .{ .offset = operand.offset() + offset, .alignment = .@"1" }); | 6293 | try cg.addMemArg(.i32_store8, .{ .offset = operand.memOffset() + offset, .alignment = .@"1" }); |
| 6325 | | 6294 | |
| 6326 | const result = try cg.buildPointerOffset(operand, 0, .new); | 6295 | return cg.finishAir(inst, operand, &.{ty_op.operand}); |
| 6327 | return cg.finishAir(inst, result, &.{ty_op.operand}); | | |
| 6328 | } | 6296 | } |
| 6329 | | 6297 | |
| 6330 | fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | 6298 | fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| ... | @@ -6336,9 +6304,9 @@ fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6336,9 +6304,9 @@ fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6336 | const result = result: { | 6304 | const result = result: { |
| 6337 | if (!payload_ty.hasRuntimeBits(zcu)) { | 6305 | if (!payload_ty.hasRuntimeBits(zcu)) { |
| 6338 | const non_null_bit = try cg.allocStack(Type.u1); | 6306 | const non_null_bit = try cg.allocStack(Type.u1); |
| 6339 | try cg.emitWValue(non_null_bit); | 6307 | try cg.emitMemBase(non_null_bit); |
| 6340 | try cg.addImm32(1); | 6308 | try cg.addImm32(1); |
| 6341 | try cg.addMemArg(.i32_store8, .{ .offset = non_null_bit.offset(), .alignment = .@"1" }); | 6309 | try cg.addMemArg(.i32_store8, .{ .offset = non_null_bit.memOffset(), .alignment = .@"1" }); |
| 6342 | break :result non_null_bit; | 6310 | break :result non_null_bit; |
| 6343 | } | 6311 | } |
| 6344 | | 6312 | |
| ... | @@ -6353,12 +6321,11 @@ fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6353,12 +6321,11 @@ fn airWrapOptional(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6353 | | 6321 | |
| 6354 | // Create optional type, set the non-null bit, and store the operand inside the optional type | 6322 | // Create optional type, set the non-null bit, and store the operand inside the optional type |
| 6355 | const result_ptr = try cg.allocStack(op_ty); | 6323 | const result_ptr = try cg.allocStack(op_ty); |
| 6356 | try cg.emitWValue(result_ptr); | 6324 | try cg.emitMemBase(result_ptr); |
| 6357 | try cg.addImm32(1); | 6325 | try cg.addImm32(1); |
| 6358 | try cg.addMemArg(.i32_store8, .{ .offset = result_ptr.offset() + offset, .alignment = .@"1" }); | 6326 | try cg.addMemArg(.i32_store8, .{ .offset = result_ptr.memOffset() + offset, .alignment = .@"1" }); |
| 6359 | | 6327 | |
| 6360 | const payload_ptr = try cg.buildPointerOffset(result_ptr, 0, .new); | 6328 | try cg.store(result_ptr, operand, payload_ty, .{}); |
| 6361 | try cg.store(payload_ptr, operand, payload_ty, .{}); | | |
| 6362 | break :result result_ptr; | 6329 | break :result result_ptr; |
| 6363 | }; | 6330 | }; |
| 6364 | | 6331 | |
| ... | @@ -6483,7 +6450,7 @@ fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6483,7 +6450,7 @@ fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6483 | if (ptr_ty.isSlice(zcu)) { | 6450 | if (ptr_ty.isSlice(zcu)) { |
| 6484 | _ = try cg.load(ptr, .usize, .{}); | 6451 | _ = try cg.load(ptr, .usize, .{}); |
| 6485 | } else { | 6452 | } else { |
| 6486 | try cg.lowerToStack(ptr); | 6453 | try cg.emitWValue(ptr); |
| 6487 | } | 6454 | } |
| 6488 | | 6455 | |
| 6489 | // calculate index into slice | 6456 | // calculate index into slice |
| ... | @@ -6513,7 +6480,7 @@ fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6513,7 +6480,7 @@ fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6513 | if (ptr_ty.isSlice(zcu)) { | 6480 | if (ptr_ty.isSlice(zcu)) { |
| 6514 | _ = try cg.load(ptr, .usize, .{}); | 6481 | _ = try cg.load(ptr, .usize, .{}); |
| 6515 | } else { | 6482 | } else { |
| 6516 | try cg.lowerToStack(ptr); | 6483 | try cg.emitWValue(ptr); |
| 6517 | } | 6484 | } |
| 6518 | | 6485 | |
| 6519 | // calculate index into ptr | 6486 | // calculate index into ptr |
| ... | @@ -6538,7 +6505,7 @@ fn airPtrBinOp(cg: *CodeGen, inst: Air.Inst.Index, op: enum { add, sub }) InnerE | ... | @@ -6538,7 +6505,7 @@ fn airPtrBinOp(cg: *CodeGen, inst: Air.Inst.Index, op: enum { add, sub }) InnerE |
| 6538 | else => ptr_ty.childType(zcu), | 6505 | else => ptr_ty.childType(zcu), |
| 6539 | }; | 6506 | }; |
| 6540 | | 6507 | |
| 6541 | try cg.lowerToStack(ptr); | 6508 | try cg.emitWValue(ptr); |
| 6542 | try cg.emitWValue(offset); | 6509 | try cg.emitWValue(offset); |
| 6543 | | 6510 | |
| 6544 | switch (cg.ptr_size) { | 6511 | switch (cg.ptr_size) { |
| ... | @@ -6620,7 +6587,7 @@ fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue) | ... | @@ -6620,7 +6587,7 @@ fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue) |
| 6620 | try cg.addLabel(.br_if, 0); | 6587 | try cg.addLabel(.br_if, 0); |
| 6621 | } | 6588 | } |
| 6622 | | 6589 | |
| 6623 | try cg.lowerToStack(ptr); | 6590 | try cg.emitWValue(ptr); |
| 6624 | try cg.emitWValue(value); | 6591 | try cg.emitWValue(value); |
| 6625 | try cg.emitWValue(len); | 6592 | try cg.emitWValue(len); |
| 6626 | try cg.addExtended(.memory_fill); | 6593 | try cg.addExtended(.memory_fill); |
| ... | @@ -6655,11 +6622,13 @@ fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue) | ... | @@ -6655,11 +6622,13 @@ fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue) |
| 6655 | | 6622 | |
| 6656 | var end_ptr = try cg.allocLocal(Type.usize); | 6623 | var end_ptr = try cg.allocLocal(Type.usize); |
| 6657 | defer end_ptr.free(cg); | 6624 | defer end_ptr.free(cg); |
| 6658 | var new_ptr = try cg.buildPointerOffset(ptr, 0, .new); | 6625 | var new_ptr = try cg.allocLocal(Type.usize); |
| 6659 | defer new_ptr.free(cg); | 6626 | defer new_ptr.free(cg); |
| | 6627 | try cg.emitWValue(ptr); |
| | 6628 | try cg.addLocal(.local_set, new_ptr.local.value); |
| 6660 | | 6629 | |
| 6661 | // get the loop conditional: if current pointer address equals final pointer's address | 6630 | // get the loop conditional: if current pointer address equals final pointer's address |
| 6662 | try cg.lowerToStack(ptr); | 6631 | try cg.emitWValue(ptr); |
| 6663 | try cg.emitWValue(final_len); | 6632 | try cg.emitWValue(final_len); |
| 6664 | switch (cg.ptr_size) { | 6633 | switch (cg.ptr_size) { |
| 6665 | .wasm32 => try cg.addTag(.i32_add), | 6634 | .wasm32 => try cg.addTag(.i32_add), |
| ... | @@ -6714,7 +6683,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6714,7 +6683,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6714 | const elem_size = elem_ty.abiSize(zcu); | 6683 | const elem_size = elem_ty.abiSize(zcu); |
| 6715 | | 6684 | |
| 6716 | if (isByRef(array_ty, zcu, cg.target)) { | 6685 | if (isByRef(array_ty, zcu, cg.target)) { |
| 6717 | try cg.lowerToStack(array); | 6686 | try cg.emitWValue(array); |
| 6718 | try cg.emitWValue(index); | 6687 | try cg.emitWValue(index); |
| 6719 | try cg.addImm32(@intCast(elem_size)); | 6688 | try cg.addImm32(@intCast(elem_size)); |
| 6720 | try cg.addTag(.i32_mul); | 6689 | try cg.addTag(.i32_mul); |
| ... | @@ -6747,7 +6716,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6747,7 +6716,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6747 | try cg.store(stack_vec, array, array_ty, .{}); | 6716 | try cg.store(stack_vec, array, array_ty, .{}); |
| 6748 | | 6717 | |
| 6749 | // Is a non-unrolled vector (v128) | 6718 | // Is a non-unrolled vector (v128) |
| 6750 | try cg.lowerToStack(stack_vec); | 6719 | try cg.emitWValue(stack_vec); |
| 6751 | try cg.emitWValue(index); | 6720 | try cg.emitWValue(index); |
| 6752 | try cg.addImm32(@intCast(elem_size)); | 6721 | try cg.addImm32(@intCast(elem_size)); |
| 6753 | try cg.addTag(.i32_mul); | 6722 | try cg.addTag(.i32_mul); |
| ... | @@ -6783,13 +6752,13 @@ fn airSplat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6783,13 +6752,13 @@ fn airSplat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6783 | 64 => @backingInt(std.wasm.SimdOpcode.v128_load64_splat), | 6752 | 64 => @backingInt(std.wasm.SimdOpcode.v128_load64_splat), |
| 6784 | else => break :blk, // Cannot make use of simd-instructions | 6753 | else => break :blk, // Cannot make use of simd-instructions |
| 6785 | }; | 6754 | }; |
| 6786 | try cg.emitWValue(operand); | 6755 | try cg.emitMemBase(operand); |
| 6787 | const extra_index: u32 = @intCast(cg.mir_extra.items.len); | 6756 | const extra_index: u32 = @intCast(cg.mir_extra.items.len); |
| 6788 | // stores as := opcode, offset, alignment (opcode::memarg) | 6757 | // stores as := opcode, offset, alignment (opcode::memarg) |
| 6789 | try cg.mir_extra.ensureUnusedCapacity(cg.gpa, 4); | 6758 | try cg.mir_extra.ensureUnusedCapacity(cg.gpa, 4); |
| 6790 | cg.mir_extra.appendAssumeCapacity(opcode); | 6759 | cg.mir_extra.appendAssumeCapacity(opcode); |
| 6791 | _ = try cg.addExtraAssumeCapacity(Mir.MemArg{ | 6760 | _ = try cg.addExtraAssumeCapacity(Mir.MemArg{ |
| 6792 | .offset = operand.offset(), | 6761 | .offset = operand.memOffset(), |
| 6793 | .alignment = elem_ty.abiAlignment(zcu).toStdMem(), | 6762 | .alignment = elem_ty.abiAlignment(zcu).toStdMem(), |
| 6794 | }); | 6763 | }); |
| 6795 | try cg.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); | 6764 | try cg.addInst(.{ .tag = .simd_prefix, .data = .{ .payload = extra_index } }); |
| ... | @@ -6856,12 +6825,12 @@ fn airShuffleOne(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6856,12 +6825,12 @@ fn airShuffleOne(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6856 | | 6825 | |
| 6857 | const dest_alloc = try cg.allocStack(result_ty); | 6826 | const dest_alloc = try cg.allocStack(result_ty); |
| 6858 | for (mask, 0..) |mask_elem, out_idx| { | 6827 | for (mask, 0..) |mask_elem, out_idx| { |
| 6859 | try cg.emitWValue(dest_alloc); | 6828 | try cg.emitMemBase(dest_alloc); |
| 6860 | const elem_val = switch (mask_elem.unwrap()) { | 6829 | const elem_val = switch (mask_elem.unwrap()) { |
| 6861 | .elem => |idx| try cg.load(operand, elem_ty, .{ .offset = elem_size * idx }), | 6830 | .elem => |idx| try cg.load(operand, elem_ty, .{ .offset = elem_size * idx }), |
| 6862 | .value => |val| try cg.lowerConstant(.fromInterned(val)), | 6831 | .value => |val| try cg.lowerConstant(.fromInterned(val)), |
| 6863 | }; | 6832 | }; |
| 6864 | try cg.store(.stack, elem_val, elem_ty, .{ .offset = dest_alloc.offset() + elem_size * out_idx }); | 6833 | try cg.store(.stack, elem_val, elem_ty, .{ .offset = dest_alloc.memOffset() + elem_size * out_idx }); |
| 6865 | } | 6834 | } |
| 6866 | return cg.finishAir(inst, dest_alloc, &.{unwrapped.operand}); | 6835 | return cg.finishAir(inst, dest_alloc, &.{unwrapped.operand}); |
| 6867 | } | 6836 | } |
| ... | @@ -6924,13 +6893,13 @@ fn airShuffleTwo(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6924,13 +6893,13 @@ fn airShuffleTwo(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6924 | | 6893 | |
| 6925 | const dest_alloc = try cg.allocStack(result_ty); | 6894 | const dest_alloc = try cg.allocStack(result_ty); |
| 6926 | for (mask, 0..) |mask_elem, out_idx| { | 6895 | for (mask, 0..) |mask_elem, out_idx| { |
| 6927 | try cg.emitWValue(dest_alloc); | 6896 | try cg.emitMemBase(dest_alloc); |
| 6928 | const elem_val = switch (mask_elem.unwrap()) { | 6897 | const elem_val = switch (mask_elem.unwrap()) { |
| 6929 | .a_elem => |idx| try cg.load(operand_a, elem_ty, .{ .offset = elem_size * idx }), | 6898 | .a_elem => |idx| try cg.load(operand_a, elem_ty, .{ .offset = elem_size * idx }), |
| 6930 | .b_elem => |idx| try cg.load(operand_b, elem_ty, .{ .offset = elem_size * idx }), | 6899 | .b_elem => |idx| try cg.load(operand_b, elem_ty, .{ .offset = elem_size * idx }), |
| 6931 | .undef => try cg.emitUndefined(elem_ty), | 6900 | .undef => try cg.emitUndefined(elem_ty), |
| 6932 | }; | 6901 | }; |
| 6933 | try cg.store(.stack, elem_val, elem_ty, .{ .offset = dest_alloc.offset() + elem_size * out_idx }); | 6902 | try cg.store(.stack, elem_val, elem_ty, .{ .offset = dest_alloc.memOffset() + elem_size * out_idx }); |
| 6934 | } | 6903 | } |
| 6935 | return cg.finishAir(inst, dest_alloc, &.{ unwrapped.operand_a, unwrapped.operand_b }); | 6904 | return cg.finishAir(inst, dest_alloc, &.{ unwrapped.operand_a, unwrapped.operand_b }); |
| 6936 | } | 6905 | } |
| ... | @@ -6956,39 +6925,18 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -6956,39 +6925,18 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6956 | .array, .vector => { | 6925 | .array, .vector => { |
| 6957 | const result = try cg.allocStack(result_ty); | 6926 | const result = try cg.allocStack(result_ty); |
| 6958 | const elem_ty = result_ty.childType(zcu); | 6927 | const elem_ty = result_ty.childType(zcu); |
| 6959 | const elem_size = @as(u32, @intCast(elem_ty.abiSize(zcu))); | 6928 | const elem_size = elem_ty.abiSize(zcu); |
| 6960 | const sentinel = result_ty.sentinel(zcu); | 6929 | const sentinel = result_ty.sentinel(zcu); |
| 6961 | | 6930 | |
| 6962 | // When the element type is by reference, we must copy the entire | 6931 | var offset: u64 = 0; |
| 6963 | // value. It is therefore safer to move the offset pointer and store | 6932 | for (elements) |elem| { |
| 6964 | // each value individually, instead of using store offsets. | 6933 | const elem_val = try cg.resolveInst(elem); |
| 6965 | if (isByRef(elem_ty, zcu, cg.target)) { | 6934 | try cg.store(result, elem_val, elem_ty, .{ .offset = offset }); |
| 6966 | // copy stack pointer into a temporary local, which is | 6935 | offset += elem_size; |
| 6967 | // moved for each element to store each value in the right position. | 6936 | } |
| 6968 | const offset = try cg.buildPointerOffset(result, 0, .new); | 6937 | if (sentinel) |s| { |
| 6969 | for (elements, 0..) |elem, elem_index| { | 6938 | const val = try cg.resolveValue(s); |
| 6970 | const elem_val = try cg.resolveInst(elem); | 6939 | try cg.store(result, val, elem_ty, .{ .offset = offset }); |
| 6971 | try cg.store(offset, elem_val, elem_ty, .{}); | | |
| 6972 | | | |
| 6973 | if (elem_index < elements.len - 1 or sentinel != null) { | | |
| 6974 | _ = try cg.buildPointerOffset(offset, elem_size, .modify); | | |
| 6975 | } | | |
| 6976 | } | | |
| 6977 | if (sentinel) |s| { | | |
| 6978 | const val = try cg.resolveValue(s); | | |
| 6979 | try cg.store(offset, val, elem_ty, .{}); | | |
| 6980 | } | | |
| 6981 | } else { | | |
| 6982 | var offset: u32 = 0; | | |
| 6983 | for (elements) |elem| { | | |
| 6984 | const elem_val = try cg.resolveInst(elem); | | |
| 6985 | try cg.store(result, elem_val, elem_ty, .{ .offset = offset }); | | |
| 6986 | offset += elem_size; | | |
| 6987 | } | | |
| 6988 | if (sentinel) |s| { | | |
| 6989 | const val = try cg.resolveValue(s); | | |
| 6990 | try cg.store(result, val, elem_ty, .{ .offset = offset }); | | |
| 6991 | } | | |
| 6992 | } | 6940 | } |
| 6993 | break :result_value result; | 6941 | break :result_value result; |
| 6994 | }, | 6942 | }, |
| ... | @@ -7001,10 +6949,9 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7001,10 +6949,9 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7001 | | 6949 | |
| 7002 | const elem_ty = result_ty.fieldType(elem_index, zcu); | 6950 | const elem_ty = result_ty.fieldType(elem_index, zcu); |
| 7003 | const field_offset = result_ty.structFieldOffset(elem_index, zcu); | 6951 | const field_offset = result_ty.structFieldOffset(elem_index, zcu); |
| 7004 | const offset = try cg.buildPointerOffset(result, field_offset, .new); | | |
| 7005 | | 6952 | |
| 7006 | const value = try cg.resolveInst(elem); | 6953 | const value = try cg.resolveInst(elem); |
| 7007 | try cg.store(offset, value, elem_ty, .{}); | 6954 | try cg.store(result, value, elem_ty, .{ .offset = field_offset }); |
| 7008 | } | 6955 | } |
| 7009 | | 6956 | |
| 7010 | break :result_value result; | 6957 | break :result_value result; |
| ... | @@ -7051,12 +6998,7 @@ fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7051,12 +6998,7 @@ fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7051 | const result_ptr = try cg.allocStack(union_ty); | 6998 | const result_ptr = try cg.allocStack(union_ty); |
| 7052 | const payload = try cg.resolveInst(extra.init); | 6999 | const payload = try cg.resolveInst(extra.init); |
| 7053 | if (layout.tag_align.compare(.gte, layout.payload_align)) { | 7000 | if (layout.tag_align.compare(.gte, layout.payload_align)) { |
| 7054 | if (isByRef(field_ty, zcu, cg.target)) { | 7001 | try cg.store(result_ptr, payload, field_ty, .{ .offset = layout.tag_size }); |
| 7055 | const payload_ptr = try cg.buildPointerOffset(result_ptr, layout.tag_size, .new); | | |
| 7056 | try cg.store(payload_ptr, payload, field_ty, .{}); | | |
| 7057 | } else { | | |
| 7058 | try cg.store(result_ptr, payload, field_ty, .{ .offset = layout.tag_size }); | | |
| 7059 | } | | |
| 7060 | | 7002 | |
| 7061 | if (layout.tag_size > 0) { | 7003 | if (layout.tag_size > 0) { |
| 7062 | try cg.store(result_ptr, tag_int, .fromInterned(union_obj.enum_tag_type), .{}); | 7004 | try cg.store(result_ptr, tag_int, .fromInterned(union_obj.enum_tag_type), .{}); |
| ... | @@ -7163,13 +7105,11 @@ fn airErrUnionPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void | ... | @@ -7163,13 +7105,11 @@ fn airErrUnionPayloadPtrSet(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void |
| 7163 | .{ .offset = errUnionErrorOffset(payload_ty, zcu) }, | 7105 | .{ .offset = errUnionErrorOffset(payload_ty, zcu) }, |
| 7164 | ); | 7106 | ); |
| 7165 | | 7107 | |
| 7166 | const result = result: { | 7108 | if (!payload_ty.hasRuntimeBits(zcu)) { |
| 7167 | if (!payload_ty.hasRuntimeBits(zcu)) { | 7109 | return cg.finishAir(inst, operand, &.{ty_op.operand}); |
| 7168 | break :result operand; | 7110 | } |
| 7169 | } | | |
| 7170 | | 7111 | |
| 7171 | break :result try cg.buildPointerOffset(operand, @as(u32, @intCast(errUnionPayloadOffset(payload_ty, zcu))), .new); | 7112 | const result = try cg.offsetPointer(operand, errUnionPayloadOffset(payload_ty, zcu)); |
| 7172 | }; | | |
| 7173 | return cg.finishAir(inst, result, &.{ty_op.operand}); | 7113 | return cg.finishAir(inst, result, &.{ty_op.operand}); |
| 7174 | } | 7114 | } |
| 7175 | | 7115 | |
| ... | @@ -7194,16 +7134,23 @@ fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7194,16 +7134,23 @@ fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7194 | }, | 7134 | }, |
| 7195 | }; | 7135 | }; |
| 7196 | | 7136 | |
| 7197 | const result = if (field_offset != 0) result: { | 7137 | if (field_offset == 0) { |
| 7198 | const base = try cg.buildPointerOffset(field_ptr, 0, .new); | 7138 | return cg.finishAir(inst, field_ptr, &.{extra.field_ptr}); |
| 7199 | try cg.addLocal(.local_get, base.local.value); | 7139 | } |
| 7200 | try cg.addImm32(@intCast(field_offset)); | | |
| 7201 | try cg.addTag(.i32_sub); | | |
| 7202 | try cg.addLocal(.local_set, base.local.value); | | |
| 7203 | break :result base; | | |
| 7204 | } else field_ptr; | | |
| 7205 | | 7140 | |
| 7206 | return cg.finishAir(inst, result, &.{extra.field_ptr}); | 7141 | // maybe use offsetPointer? sub looks better in disasm |
| | 7142 | try cg.emitWValue(field_ptr); |
| | 7143 | switch (cg.ptr_size) { |
| | 7144 | .wasm32 => { |
| | 7145 | try cg.addImm32(@intCast(field_offset)); |
| | 7146 | try cg.addTag(.i32_sub); |
| | 7147 | }, |
| | 7148 | .wasm64 => { |
| | 7149 | try cg.addImm64(field_offset); |
| | 7150 | try cg.addTag(.i64_sub); |
| | 7151 | }, |
| | 7152 | } |
| | 7153 | return cg.finishAir(inst, .stack, &.{extra.field_ptr}); |
| 7207 | } | 7154 | } |
| 7208 | | 7155 | |
| 7209 | fn sliceOrArrayPtr(cg: *CodeGen, ptr: WValue, ptr_ty: Type) InnerError!WValue { | 7156 | fn sliceOrArrayPtr(cg: *CodeGen, ptr: WValue, ptr_ty: Type) InnerError!WValue { |
| ... | @@ -7322,7 +7269,7 @@ fn airErrorName(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7322,7 +7269,7 @@ fn airErrorName(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7322 | fn airPtrSliceFieldPtr(cg: *CodeGen, inst: Air.Inst.Index, offset: u32) InnerError!void { | 7269 | fn airPtrSliceFieldPtr(cg: *CodeGen, inst: Air.Inst.Index, offset: u32) InnerError!void { |
| 7323 | const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op; | 7270 | const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op; |
| 7324 | const slice_ptr = try cg.resolveInst(ty_op.operand); | 7271 | const slice_ptr = try cg.resolveInst(ty_op.operand); |
| 7325 | const result = try cg.buildPointerOffset(slice_ptr, offset, .new); | 7272 | const result = try cg.offsetPointer(slice_ptr, offset); |
| 7326 | return cg.finishAir(inst, result, &.{ty_op.operand}); | 7273 | return cg.finishAir(inst, result, &.{ty_op.operand}); |
| 7327 | } | 7274 | } |
| 7328 | | 7275 | |
| ... | @@ -7392,13 +7339,15 @@ fn lowerTry( | ... | @@ -7392,13 +7339,15 @@ fn lowerTry( |
| 7392 | try cg.startBlock(.block, .empty); | 7339 | try cg.startBlock(.block, .empty); |
| 7393 | | 7340 | |
| 7394 | // check if the error tag is set for the error union. | 7341 | // check if the error tag is set for the error union. |
| 7395 | try cg.emitWValue(err_union); | | |
| 7396 | if (pl_has_bits or operand_is_ptr) { | 7342 | if (pl_has_bits or operand_is_ptr) { |
| 7397 | const err_offset: u32 = @intCast(errUnionErrorOffset(pl_ty, zcu)); | 7343 | try cg.emitMemBase(err_union); |
| | 7344 | const err_offset = errUnionErrorOffset(pl_ty, zcu); |
| 7398 | try cg.addMemArg(.i32_load16_u, .{ | 7345 | try cg.addMemArg(.i32_load16_u, .{ |
| 7399 | .offset = err_union.offset() + err_offset, | 7346 | .offset = err_union.memOffset() + err_offset, |
| 7400 | .alignment = Type.anyerror.abiAlignment(zcu).toStdMem(), | 7347 | .alignment = Type.anyerror.abiAlignment(zcu).toStdMem(), |
| 7401 | }); | 7348 | }); |
| | 7349 | } else { |
| | 7350 | try cg.emitWValue(err_union); |
| 7402 | } | 7351 | } |
| 7403 | try cg.addTag(.i32_eqz); | 7352 | try cg.addTag(.i32_eqz); |
| 7404 | try cg.addLabel(.br_if, 0); // jump out of block when error is '0' | 7353 | try cg.addLabel(.br_if, 0); // jump out of block when error is '0' |
| ... | @@ -7417,9 +7366,9 @@ fn lowerTry( | ... | @@ -7417,9 +7366,9 @@ fn lowerTry( |
| 7417 | return .none; | 7366 | return .none; |
| 7418 | } | 7367 | } |
| 7419 | | 7368 | |
| 7420 | const pl_offset: u32 = @intCast(errUnionPayloadOffset(pl_ty, zcu)); | 7369 | const pl_offset = errUnionPayloadOffset(pl_ty, zcu); |
| 7421 | if (operand_is_ptr or isByRef(pl_ty, zcu, cg.target)) { | 7370 | if (operand_is_ptr or isByRef(pl_ty, zcu, cg.target)) { |
| 7422 | return buildPointerOffset(cg, err_union, pl_offset, .new); | 7371 | return cg.offsetPointer(err_union, pl_offset); |
| 7423 | } | 7372 | } |
| 7424 | const payload = try cg.load(err_union, pl_ty, .{ .offset = pl_offset }); | 7373 | const payload = try cg.load(err_union, pl_ty, .{ .offset = pl_offset }); |
| 7425 | return payload.toLocal(cg, pl_ty); | 7374 | return payload.toLocal(cg, pl_ty); |
| ... | @@ -7448,7 +7397,7 @@ fn callIntrinsic( | ... | @@ -7448,7 +7397,7 @@ fn callIntrinsic( |
| 7448 | // and emit it as our first argument | 7397 | // and emit it as our first argument |
| 7449 | const sret = if (want_sret_param) blk: { | 7398 | const sret = if (want_sret_param) blk: { |
| 7450 | const sret_local = try cg.allocStack(return_type); | 7399 | const sret_local = try cg.allocStack(return_type); |
| 7451 | try cg.lowerToStack(sret_local); | 7400 | try cg.emitWValue(sret_local); |
| 7452 | break :blk sret_local; | 7401 | break :blk sret_local; |
| 7453 | } else .none; | 7402 | } else .none; |
| 7454 | | 7403 | |
| ... | @@ -7476,7 +7425,7 @@ fn airTagName(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7476,7 +7425,7 @@ fn airTagName(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7476 | const enum_ty = cg.typeOf(un_op); | 7425 | const enum_ty = cg.typeOf(un_op); |
| 7477 | | 7426 | |
| 7478 | try cg.addInst(.{ .tag = .enum_tag_name_table_ref, .data = .{ .ip_index = enum_ty.toIntern() } }); | 7427 | try cg.addInst(.{ .tag = .enum_tag_name_table_ref, .data = .{ .ip_index = enum_ty.toIntern() } }); |
| 7479 | try cg.lowerToStack(operand); | 7428 | try cg.emitWValue(operand); |
| 7480 | try cg.addInst(.{ .tag = .call_tag_index, .data = .{ .ip_index = enum_ty.toIntern() } }); | 7429 | try cg.addInst(.{ .tag = .call_tag_index, .data = .{ .ip_index = enum_ty.toIntern() } }); |
| 7481 | | 7430 | |
| 7482 | switch (cg.ptr_size) { | 7431 | switch (cg.ptr_size) { |
| ... | @@ -7500,7 +7449,7 @@ fn airIsNamedEnumValue(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7500,7 +7449,7 @@ fn airIsNamedEnumValue(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7500 | const operand = try cg.resolveInst(un_op); | 7449 | const operand = try cg.resolveInst(un_op); |
| 7501 | const enum_ty = cg.typeOf(un_op); | 7450 | const enum_ty = cg.typeOf(un_op); |
| 7502 | | 7451 | |
| 7503 | try cg.lowerToStack(operand); | 7452 | try cg.emitWValue(operand); |
| 7504 | try cg.addInst(.{ .tag = .call_tag_index, .data = .{ .ip_index = enum_ty.toIntern() } }); | 7453 | try cg.addInst(.{ .tag = .call_tag_index, .data = .{ .ip_index = enum_ty.toIntern() } }); |
| 7505 | try cg.addImm32(~@as(u32, 0)); | 7454 | try cg.addImm32(~@as(u32, 0)); |
| 7506 | try cg.addTag(.i32_ne); | 7455 | try cg.addTag(.i32_ne); |
| ... | @@ -7614,9 +7563,9 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7614,9 +7563,9 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7614 | | 7563 | |
| 7615 | const ptr_val = if (cg.useAtomicFeature()) val: { | 7564 | const ptr_val = if (cg.useAtomicFeature()) val: { |
| 7616 | const val_local = try cg.allocLocal(ty); | 7565 | const val_local = try cg.allocLocal(ty); |
| 7617 | try cg.emitWValue(ptr_operand); | 7566 | try cg.emitMemBase(ptr_operand); |
| 7618 | try cg.lowerToStack(expected_val); | 7567 | try cg.emitWValue(expected_val); |
| 7619 | try cg.lowerToStack(new_val); | 7568 | try cg.emitWValue(new_val); |
| 7620 | try cg.addAtomicMemArg(switch (ty.abiSize(zcu)) { | 7569 | try cg.addAtomicMemArg(switch (ty.abiSize(zcu)) { |
| 7621 | 1 => .i32_atomic_rmw8_cmpxchg_u, | 7570 | 1 => .i32_atomic_rmw8_cmpxchg_u, |
| 7622 | 2 => .i32_atomic_rmw16_cmpxchg_u, | 7571 | 2 => .i32_atomic_rmw16_cmpxchg_u, |
| ... | @@ -7624,7 +7573,7 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7624,7 +7573,7 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7624 | 8 => .i32_atomic_rmw_cmpxchg, | 7573 | 8 => .i32_atomic_rmw_cmpxchg, |
| 7625 | else => |size| return cg.fail("TODO: implement `@cmpxchg` for types with abi size '{d}'", .{size}), | 7574 | else => |size| return cg.fail("TODO: implement `@cmpxchg` for types with abi size '{d}'", .{size}), |
| 7626 | }, .{ | 7575 | }, .{ |
| 7627 | .offset = ptr_operand.offset(), | 7576 | .offset = ptr_operand.memOffset(), |
| 7628 | .alignment = ty.abiAlignment(zcu).toStdMem(), | 7577 | .alignment = ty.abiAlignment(zcu).toStdMem(), |
| 7629 | }); | 7578 | }); |
| 7630 | try cg.addLocal(.local_tee, val_local.local.value); | 7579 | try cg.addLocal(.local_tee, val_local.local.value); |
| ... | @@ -7637,13 +7586,13 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7637,13 +7586,13 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7637 | } | 7586 | } |
| 7638 | const ptr_val = try WValue.toLocal(try cg.load(ptr_operand, ty, .{}), cg, ty); | 7587 | const ptr_val = try WValue.toLocal(try cg.load(ptr_operand, ty, .{}), cg, ty); |
| 7639 | | 7588 | |
| 7640 | try cg.lowerToStack(ptr_operand); | 7589 | try cg.emitMemBase(ptr_operand); |
| 7641 | try cg.lowerToStack(new_val); | 7590 | try cg.emitWValue(new_val); |
| 7642 | try cg.emitWValue(ptr_val); | 7591 | try cg.emitWValue(ptr_val); |
| 7643 | _ = try cg.intCmp(int_ty, .eq, ptr_val, expected_val); | 7592 | _ = try cg.intCmp(int_ty, .eq, ptr_val, expected_val); |
| 7644 | try cg.addLocal(.local_tee, cmp_result.local.value); | 7593 | try cg.addLocal(.local_tee, cmp_result.local.value); |
| 7645 | try cg.addTag(.select); | 7594 | try cg.addTag(.select); |
| 7646 | try cg.store(.stack, .stack, ty, .{}); | 7595 | try cg.store(.stack, .stack, ty, .{ .offset = ptr_operand.memOffset() }); |
| 7647 | | 7596 | |
| 7648 | break :val ptr_val; | 7597 | break :val ptr_val; |
| 7649 | }; | 7598 | }; |
| ... | @@ -7684,9 +7633,9 @@ fn airAtomicLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7684,9 +7633,9 @@ fn airAtomicLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7684 | 8 => .i64_atomic_load, | 7633 | 8 => .i64_atomic_load, |
| 7685 | else => |size| return cg.fail("TODO: @atomicLoad for types with abi size {d}", .{size}), | 7634 | else => |size| return cg.fail("TODO: @atomicLoad for types with abi size {d}", .{size}), |
| 7686 | }; | 7635 | }; |
| 7687 | try cg.emitWValue(ptr); | 7636 | try cg.emitMemBase(ptr); |
| 7688 | try cg.addAtomicMemArg(tag, .{ | 7637 | try cg.addAtomicMemArg(tag, .{ |
| 7689 | .offset = ptr.offset(), | 7638 | .offset = ptr.memOffset(), |
| 7690 | .alignment = ty.abiAlignment(zcu).toStdMem(), | 7639 | .alignment = ty.abiAlignment(zcu).toStdMem(), |
| 7691 | }); | 7640 | }); |
| 7692 | } else { | 7641 | } else { |
| ... | @@ -7719,7 +7668,7 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7719,7 +7668,7 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7719 | // create a loop to cmpxchg the new value | 7668 | // create a loop to cmpxchg the new value |
| 7720 | try cg.startBlock(.loop, .empty); | 7669 | try cg.startBlock(.loop, .empty); |
| 7721 | | 7670 | |
| 7722 | try cg.emitWValue(ptr); | 7671 | try cg.emitMemBase(ptr); |
| 7723 | try cg.emitWValue(value); | 7672 | try cg.emitWValue(value); |
| 7724 | if (op == .Nand) { | 7673 | if (op == .Nand) { |
| 7725 | const and_res = try cg.intAnd(int_ty, value, operand); | 7674 | const and_res = try cg.intAnd(int_ty, value, operand); |
| ... | @@ -7746,7 +7695,7 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7746,7 +7695,7 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7746 | else => return cg.fail("TODO: implement `@atomicRmw` with operation `{s}` for types larger than 64 bits", .{@tagName(op)}), | 7695 | else => return cg.fail("TODO: implement `@atomicRmw` with operation `{s}` for types larger than 64 bits", .{@tagName(op)}), |
| 7747 | }, | 7696 | }, |
| 7748 | .{ | 7697 | .{ |
| 7749 | .offset = ptr.offset(), | 7698 | .offset = ptr.memOffset(), |
| 7750 | .alignment = ty.abiAlignment(zcu).toStdMem(), | 7699 | .alignment = ty.abiAlignment(zcu).toStdMem(), |
| 7751 | }, | 7700 | }, |
| 7752 | ); | 7701 | ); |
| ... | @@ -7764,7 +7713,7 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7764,7 +7713,7 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7764 | | 7713 | |
| 7765 | // the other operations have their own instructions for Wasm. | 7714 | // the other operations have their own instructions for Wasm. |
| 7766 | else => { | 7715 | else => { |
| 7767 | try cg.emitWValue(ptr); | 7716 | try cg.emitMemBase(ptr); |
| 7768 | try cg.emitWValue(operand); | 7717 | try cg.emitWValue(operand); |
| 7769 | const tag: std.wasm.AtomicsOpcode = switch (ty.abiSize(zcu)) { | 7718 | const tag: std.wasm.AtomicsOpcode = switch (ty.abiSize(zcu)) { |
| 7770 | 1 => switch (op) { | 7719 | 1 => switch (op) { |
| ... | @@ -7806,7 +7755,7 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7806,7 +7755,7 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7806 | else => |size| return cg.fail("TODO: Implement `@atomicRmw` for types with abi size {d}", .{size}), | 7755 | else => |size| return cg.fail("TODO: Implement `@atomicRmw` for types with abi size {d}", .{size}), |
| 7807 | }; | 7756 | }; |
| 7808 | try cg.addAtomicMemArg(tag, .{ | 7757 | try cg.addAtomicMemArg(tag, .{ |
| 7809 | .offset = ptr.offset(), | 7758 | .offset = ptr.memOffset(), |
| 7810 | .alignment = ty.abiAlignment(zcu).toStdMem(), | 7759 | .alignment = ty.abiAlignment(zcu).toStdMem(), |
| 7811 | }); | 7760 | }); |
| 7812 | return cg.finishAir(inst, .stack, &.{ pl_op.operand, extra.operand }); | 7761 | return cg.finishAir(inst, .stack, &.{ pl_op.operand, extra.operand }); |
| ... | @@ -7825,23 +7774,23 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7825,23 +7774,23 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7825 | => { | 7774 | => { |
| 7826 | if (ty.isAnyFloat()) { | 7775 | if (ty.isAnyFloat()) { |
| 7827 | const float_ty: FloatType = .fromType(cg, ty); | 7776 | const float_ty: FloatType = .fromType(cg, ty); |
| 7828 | try cg.emitWValue(ptr); | 7777 | try cg.emitMemBase(ptr); |
| 7829 | _ = switch (op) { | 7778 | _ = switch (op) { |
| 7830 | .Add => try cg.floatAdd(float_ty, result, operand), | 7779 | .Add => try cg.floatAdd(float_ty, result, operand), |
| 7831 | .Sub => try cg.floatSub(float_ty, result, operand), | 7780 | .Sub => try cg.floatSub(float_ty, result, operand), |
| 7832 | else => unreachable, | 7781 | else => unreachable, |
| 7833 | }; | 7782 | }; |
| 7834 | try cg.store(.stack, .stack, ty, .{ .offset = ptr.offset() }); | 7783 | try cg.store(.stack, .stack, ty, .{ .offset = ptr.memOffset() }); |
| 7835 | } else { | 7784 | } else { |
| 7836 | const int_ty: IntType = .fromType(cg, ty); | 7785 | const int_ty: IntType = .fromType(cg, ty); |
| 7837 | try cg.emitWValue(ptr); | 7786 | try cg.emitMemBase(ptr); |
| 7838 | _ = switch (op) { | 7787 | _ = switch (op) { |
| 7839 | .Add => try cg.intAdd(int_ty, result, operand), | 7788 | .Add => try cg.intAdd(int_ty, result, operand), |
| 7840 | .Sub => try cg.intSub(int_ty, result, operand), | 7789 | .Sub => try cg.intSub(int_ty, result, operand), |
| 7841 | else => unreachable, | 7790 | else => unreachable, |
| 7842 | }; | 7791 | }; |
| 7843 | _ = try cg.intWrap(int_ty, .stack); | 7792 | _ = try cg.intWrap(int_ty, .stack); |
| 7844 | try cg.store(.stack, .stack, ty, .{ .offset = ptr.offset() }); | 7793 | try cg.store(.stack, .stack, ty, .{ .offset = ptr.memOffset() }); |
| 7845 | } | 7794 | } |
| 7846 | }, | 7795 | }, |
| 7847 | .And, | 7796 | .And, |
| ... | @@ -7849,39 +7798,39 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7849,39 +7798,39 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7849 | .Xor, | 7798 | .Xor, |
| 7850 | => { | 7799 | => { |
| 7851 | const int_ty: IntType = .fromType(cg, ty); | 7800 | const int_ty: IntType = .fromType(cg, ty); |
| 7852 | try cg.emitWValue(ptr); | 7801 | try cg.emitMemBase(ptr); |
| 7853 | _ = switch (op) { | 7802 | _ = switch (op) { |
| 7854 | .And => try cg.intAnd(int_ty, result, operand), | 7803 | .And => try cg.intAnd(int_ty, result, operand), |
| 7855 | .Or => try cg.intOr(int_ty, result, operand), | 7804 | .Or => try cg.intOr(int_ty, result, operand), |
| 7856 | .Xor => try cg.intXor(int_ty, result, operand), | 7805 | .Xor => try cg.intXor(int_ty, result, operand), |
| 7857 | else => unreachable, | 7806 | else => unreachable, |
| 7858 | }; | 7807 | }; |
| 7859 | try cg.store(.stack, .stack, ty, .{ .offset = ptr.offset() }); | 7808 | try cg.store(.stack, .stack, ty, .{ .offset = ptr.memOffset() }); |
| 7860 | }, | 7809 | }, |
| 7861 | .Max, | 7810 | .Max, |
| 7862 | .Min, | 7811 | .Min, |
| 7863 | => { | 7812 | => { |
| 7864 | if (ty.isAnyFloat()) { | 7813 | if (ty.isAnyFloat()) { |
| 7865 | const float_ty: FloatType = .fromType(cg, ty); | 7814 | const float_ty: FloatType = .fromType(cg, ty); |
| 7866 | try cg.emitWValue(ptr); | 7815 | try cg.emitMemBase(ptr); |
| 7867 | try cg.emitWValue(result); | 7816 | try cg.emitWValue(result); |
| 7868 | try cg.emitWValue(operand); | 7817 | try cg.emitWValue(operand); |
| 7869 | _ = try cg.floatCmp(float_ty, if (op == .Max) .gt else .lt, result, operand); | 7818 | _ = try cg.floatCmp(float_ty, if (op == .Max) .gt else .lt, result, operand); |
| 7870 | try cg.addTag(.select); | 7819 | try cg.addTag(.select); |
| 7871 | try cg.store(.stack, .stack, ty, .{ .offset = ptr.offset() }); | 7820 | try cg.store(.stack, .stack, ty, .{ .offset = ptr.memOffset() }); |
| 7872 | } else { | 7821 | } else { |
| 7873 | const int_ty: IntType = .fromType(cg, ty); | 7822 | const int_ty: IntType = .fromType(cg, ty); |
| 7874 | try cg.emitWValue(ptr); | 7823 | try cg.emitMemBase(ptr); |
| 7875 | try cg.emitWValue(result); | 7824 | try cg.emitWValue(result); |
| 7876 | try cg.emitWValue(operand); | 7825 | try cg.emitWValue(operand); |
| 7877 | _ = try cg.intCmp(int_ty, if (op == .Max) .gt else .lt, result, operand); | 7826 | _ = try cg.intCmp(int_ty, if (op == .Max) .gt else .lt, result, operand); |
| 7878 | try cg.addTag(.select); | 7827 | try cg.addTag(.select); |
| 7879 | try cg.store(.stack, .stack, ty, .{ .offset = ptr.offset() }); | 7828 | try cg.store(.stack, .stack, ty, .{ .offset = ptr.memOffset() }); |
| 7880 | } | 7829 | } |
| 7881 | }, | 7830 | }, |
| 7882 | .Nand => { | 7831 | .Nand => { |
| 7883 | const int_ty: IntType = .fromType(cg, ty); | 7832 | const int_ty: IntType = .fromType(cg, ty); |
| 7884 | try cg.emitWValue(ptr); | 7833 | try cg.emitMemBase(ptr); |
| 7885 | const and_res = try cg.intAnd(int_ty, result, operand); | 7834 | const and_res = try cg.intAnd(int_ty, result, operand); |
| 7886 | if (int_ty.bits <= 32) { | 7835 | if (int_ty.bits <= 32) { |
| 7887 | try cg.addImm32(~@as(u32, 0)); | 7836 | try cg.addImm32(~@as(u32, 0)); |
| ... | @@ -7891,7 +7840,7 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7891,7 +7840,7 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7891 | return cg.fail("TODO: `@atomicRmw` with operator `Nand` for types larger than 64 bits", .{}); | 7840 | return cg.fail("TODO: `@atomicRmw` with operator `Nand` for types larger than 64 bits", .{}); |
| 7892 | } | 7841 | } |
| 7893 | _ = try cg.intXor(int_ty, and_res, .stack); | 7842 | _ = try cg.intXor(int_ty, and_res, .stack); |
| 7894 | try cg.store(.stack, .stack, ty, .{ .offset = ptr.offset() }); | 7843 | try cg.store(.stack, .stack, ty, .{ .offset = ptr.memOffset() }); |
| 7895 | }, | 7844 | }, |
| 7896 | } | 7845 | } |
| 7897 | | 7846 | |
| ... | @@ -7916,10 +7865,10 @@ fn airAtomicStore(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7916,10 +7865,10 @@ fn airAtomicStore(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7916 | 8 => .i64_atomic_store, | 7865 | 8 => .i64_atomic_store, |
| 7917 | else => |size| return cg.fail("TODO: @atomicLoad for types with abi size {d}", .{size}), | 7866 | else => |size| return cg.fail("TODO: @atomicLoad for types with abi size {d}", .{size}), |
| 7918 | }; | 7867 | }; |
| 7919 | try cg.emitWValue(ptr); | 7868 | try cg.emitMemBase(ptr); |
| 7920 | try cg.lowerToStack(operand); | 7869 | try cg.emitWValue(operand); |
| 7921 | try cg.addAtomicMemArg(tag, .{ | 7870 | try cg.addAtomicMemArg(tag, .{ |
| 7922 | .offset = ptr.offset(), | 7871 | .offset = ptr.memOffset(), |
| 7923 | .alignment = ty.abiAlignment(zcu).toStdMem(), | 7872 | .alignment = ty.abiAlignment(zcu).toStdMem(), |
| 7924 | }); | 7873 | }); |
| 7925 | } else { | 7874 | } else { |
| ... | @@ -7996,7 +7945,7 @@ fn airAsm(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { | ... | @@ -7996,7 +7945,7 @@ fn airAsm(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7996 | return cg.fail("Self-hosted wasm backend requires input constraint to be equal \"r\"", .{}); | 7945 | return cg.fail("Self-hosted wasm backend requires input constraint to be equal \"r\"", .{}); |
| 7997 | } | 7946 | } |
| 7998 | | 7947 | |
| 7999 | try cg.lowerToStack(operand); | 7948 | try cg.emitWValue(operand); |
| 8000 | const op_local = try WValue.toLocal(.stack, cg, cg.typeOf(input.operand)); | 7949 | const op_local = try WValue.toLocal(.stack, cg, cg.typeOf(input.operand)); |
| 8001 | | 7950 | |
| 8002 | const gop = try local_map.getOrPutValue(cg.gpa, name, op_local.local.value); | 7951 | const gop = try local_map.getOrPutValue(cg.gpa, name, op_local.local.value); |