| ... | ... | @@ -271,23 +271,16 @@ const WValue = union(enum) { |
| 271 | 271 | /// pointing to where the value lives. |
| 272 | 272 | stack_offset: struct { |
| 273 | 273 | /// Contains the actual value of the offset |
| 274 | | value: u32, |
| 275 | | /// The amount of instructions referencing this `WValue` |
| 276 | | references: u32, |
| 274 | value: u64, |
| 277 | 275 | }, |
| 278 | 276 | |
| 279 | | /// Returns the offset from the bottom of the stack. This is useful when |
| 280 | | /// we use the load or store instruction to ensure we retrieve the value |
| 281 | | /// from the correct position, rather than the value that lives at the |
| 282 | | /// bottom of the stack. For instances where `WValue` is not `stack_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, |
| 277 | /// Returns the offset from the bottom of the stack. |
| 278 | fn memOffset(value: WValue) u64 { |
| 279 | return switch (value) { |
| 280 | .stack_offset => |stack_offset| stack_offset.value, |
| 288 | 281 | .dead => unreachable, |
| 289 | | else => return 0, |
| 290 | | } |
| 282 | else => 0, |
| 283 | }; |
| 291 | 284 | } |
| 292 | 285 | |
| 293 | 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 | 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 | 671 | /// Writes the bytecode depending on the given `WValue` in `val` |
| 655 | 672 | fn emitWValue(cg: *CodeGen, value: WValue) InnerError!void { |
| 656 | 673 | switch (value) { |
| ... | ... | @@ -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 | 1017 | /// it matches the ABI. |
| 990 | 1018 | fn lowerArg(cg: *CodeGen, cc: std.lang.CallingConvention, ty: Type, value: WValue) !void { |
| 991 | 1019 | if (cc != .wasm_mvp) { |
| 992 | | return cg.lowerToStack(value); |
| 1020 | return cg.emitWValue(value); |
| 993 | 1021 | } |
| 994 | 1022 | |
| 995 | 1023 | const zcu = cg.pt.zcu; |
| ... | ... | @@ -997,7 +1025,7 @@ fn lowerArg(cg: *CodeGen, cc: std.lang.CallingConvention, ty: Type, value: WValu |
| 997 | 1025 | switch (abi.classifyType(ty, zcu, cg.target)) { |
| 998 | 1026 | .direct => |scalar_ty| { |
| 999 | 1027 | if (!isByRef(ty, zcu, cg.target)) { |
| 1000 | | return cg.lowerToStack(value); |
| 1028 | return cg.emitWValue(value); |
| 1001 | 1029 | } else { |
| 1002 | 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 | 1033 | .double_i64 => { |
| 1006 | 1034 | assert(ty.abiSize(zcu) == 16); |
| 1007 | 1035 | // in this case we have an integer or float that must be lowered as 2 i64's. |
| 1008 | | try cg.emitWValue(value); |
| 1009 | | try cg.addMemArg(.i64_load, .{ .offset = value.offset(), .alignment = .@"8" }); |
| 1010 | | try cg.emitWValue(value); |
| 1011 | | try cg.addMemArg(.i64_load, .{ .offset = value.offset() + 8, .alignment = .@"8" }); |
| 1036 | const base_offset = value.memOffset(); |
| 1037 | try cg.emitMemBase(value); |
| 1038 | try cg.addMemArg(.i64_load, .{ .offset = base_offset, .alignment = .@"8" }); |
| 1039 | try cg.emitMemBase(value); |
| 1040 | try cg.addMemArg(.i64_load, .{ .offset = base_offset + 8, .alignment = .@"8" }); |
| 1012 | 1041 | }, |
| 1013 | 1042 | .indirect => { |
| 1014 | 1043 | const stack_copy = try cg.allocStack(ty); |
| 1015 | 1044 | try cg.store(stack_copy, value, ty, .{}); |
| 1016 | | return cg.lowerToStack(stack_copy); |
| 1045 | return cg.emitWValue(stack_copy); |
| 1017 | 1046 | }, |
| 1018 | 1047 | .unrolled => |vector| { |
| 1019 | 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 | 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 | 1056 | /// Creates a local for the initial stack value |
| 1052 | 1057 | /// Asserts `initial_stack_value` is `.none` |
| 1053 | 1058 | fn initializeStack(cg: *CodeGen) !void { |
| ... | ... | @@ -1113,7 +1118,7 @@ fn allocStackBytes(cg: *CodeGen, size: u32, alignment: Alignment) !WValue { |
| 1113 | 1118 | const offset: u32 = @intCast(alignment.forward(cg.stack_size)); |
| 1114 | 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 | 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 | 1146 | const offset: u32 = @intCast(abi_alignment.forward(cg.stack_size)); |
| 1142 | 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 | 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 | 1176 | try cg.addLabel(.br_if, 0); |
| 1172 | 1177 | } |
| 1173 | 1178 | |
| 1174 | | try cg.lowerToStack(dst); |
| 1175 | | try cg.lowerToStack(src); |
| 1179 | try cg.emitWValue(dst); |
| 1180 | try cg.emitWValue(src); |
| 1176 | 1181 | try cg.emitWValue(len); |
| 1177 | 1182 | try cg.addExtended(.memory_copy); |
| 1178 | 1183 | |
| ... | ... | @@ -1187,8 +1192,8 @@ fn memcpy(cg: *CodeGen, dst: WValue, src: WValue, len: WValue) !void { |
| 1187 | 1192 | return; |
| 1188 | 1193 | } |
| 1189 | 1194 | |
| 1190 | | try cg.lowerToStack(dst); |
| 1191 | | try cg.lowerToStack(src); |
| 1195 | try cg.emitWValue(dst); |
| 1196 | try cg.emitWValue(src); |
| 1192 | 1197 | try cg.emitWValue(len); |
| 1193 | 1198 | try cg.addCallIntrinsic(.memcpy); |
| 1194 | 1199 | try cg.addTag(.drop); |
| ... | ... | @@ -1200,8 +1205,8 @@ fn memmove(cg: *CodeGen, dst: WValue, src: WValue, len: WValue) !void { |
| 1200 | 1205 | return; |
| 1201 | 1206 | } |
| 1202 | 1207 | |
| 1203 | | try cg.lowerToStack(dst); |
| 1204 | | try cg.lowerToStack(src); |
| 1208 | try cg.emitWValue(dst); |
| 1209 | try cg.emitWValue(src); |
| 1205 | 1210 | try cg.emitWValue(len); |
| 1206 | 1211 | try cg.addCallIntrinsic(.memmove); |
| 1207 | 1212 | try cg.addTag(.drop); |
| ... | ... | @@ -1283,34 +1288,6 @@ pub fn determineSimdStoreStrategy(ty: Type, zcu: *const Zcu, target: *const std. |
| 1283 | 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 | 1291 | fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 1315 | 1292 | const zcu = cg.pt.zcu; |
| 1316 | 1293 | const air_tags = cg.air.instructions.items(.tag); |
| ... | ... | @@ -1331,7 +1308,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 1331 | 1308 | const elem_ty = cg.typeOf(bin_op.rhs); |
| 1332 | 1309 | const elem_size = elem_ty.abiSize(zcu); |
| 1333 | 1310 | |
| 1334 | | try cg.lowerToStack(vec_ptr); |
| 1311 | try cg.emitWValue(vec_ptr); |
| 1335 | 1312 | try cg.emitWValue(elem_idx); |
| 1336 | 1313 | try cg.addImm32(@intCast(elem_size)); |
| 1337 | 1314 | try cg.addTag(.i32_mul); |
| ... | ... | @@ -2108,7 +2085,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) |
| 2108 | 2085 | } else .none; |
| 2109 | 2086 | |
| 2110 | 2087 | if (first_param_sret) { |
| 2111 | | try cg.lowerToStack(sret); |
| 2088 | try cg.emitWValue(sret); |
| 2112 | 2089 | } |
| 2113 | 2090 | |
| 2114 | 2091 | for (args, 0..) |arg, arg_i| { |
| ... | ... | @@ -2122,7 +2099,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) |
| 2122 | 2099 | } |
| 2123 | 2100 | |
| 2124 | 2101 | if (fn_info.is_var_args) { |
| 2125 | | try cg.lowerToStack(varargs_buf); |
| 2102 | try cg.emitWValue(varargs_buf); |
| 2126 | 2103 | } |
| 2127 | 2104 | |
| 2128 | 2105 | if (callee) |nav_index| { |
| ... | ... | @@ -2243,8 +2220,8 @@ fn airVaArg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 2243 | 2220 | |
| 2244 | 2221 | try cg.addLocal(.local_set, arg_ptr.local.value); |
| 2245 | 2222 | |
| 2246 | | try cg.lowerToStack(operand); |
| 2247 | | try cg.lowerToStack(arg_ptr); |
| 2223 | try cg.emitWValue(operand); |
| 2224 | try cg.emitWValue(arg_ptr); |
| 2248 | 2225 | switch (cg.ptr_size) { |
| 2249 | 2226 | .wasm32 => { |
| 2250 | 2227 | try cg.addImm32(abi_size); |
| ... | ... | @@ -2325,28 +2302,22 @@ fn store(cg: *CodeGen, lhs: WValue, rhs: WValue, ty: Type, memarg: MemArg) Inner |
| 2325 | 2302 | natural_alignment.minStrict(memarg.alignment); |
| 2326 | 2303 | |
| 2327 | 2304 | if (isByRef(ty, zcu, cg.target)) { |
| 2328 | | const offset_ptr: WValue = switch (memarg.offset + lhs.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 | | }; |
| 2305 | const offset_ptr = try cg.offsetPointer(lhs, memarg.offset); |
| 2337 | 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 | 2312 | if (ty.zigTypeTag(zcu) == .vector) { |
| 2341 | | try cg.emitWValue(lhs); |
| 2342 | | try cg.lowerToStack(rhs); |
| 2313 | try cg.emitWValue(rhs); |
| 2343 | 2314 | // TODO: Add helper functions for simd opcodes |
| 2344 | 2315 | const extra_index: u32 = @intCast(cg.mir_extra.items.len); |
| 2345 | 2316 | // stores as := opcode, offset, alignment (opcode::memarg) |
| 2346 | 2317 | try cg.mir_extra.ensureUnusedCapacity(cg.gpa, 4); |
| 2347 | 2318 | cg.mir_extra.appendAssumeCapacity(@backingInt(std.wasm.SimdOpcode.v128_store)); |
| 2348 | 2319 | _ = try cg.addExtraAssumeCapacity(Mir.MemArg{ |
| 2349 | | .offset = memarg.offset + lhs.offset(), |
| 2320 | .offset = base_offset + memarg.offset, |
| 2350 | 2321 | .alignment = alignment.toStdMem(), |
| 2351 | 2322 | }); |
| 2352 | 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 | 2342 | } |
| 2372 | 2343 | }; |
| 2373 | 2344 | |
| 2374 | | try cg.emitWValue(lhs); |
| 2375 | | try cg.lowerToStack(rhs); |
| 2345 | try cg.emitWValue(rhs); |
| 2376 | 2346 | |
| 2377 | 2347 | try cg.addMemArg( |
| 2378 | 2348 | store_opcode, |
| 2379 | 2349 | .{ |
| 2380 | | .offset = memarg.offset + lhs.offset(), |
| 2350 | .offset = base_offset + memarg.offset, |
| 2381 | 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 | 2391 | natural_alignment.minStrict(memarg.alignment); |
| 2422 | 2392 | |
| 2423 | 2393 | if (isByRef(ty, zcu, cg.target)) { |
| 2424 | | const src_ptr_maybe_stack: WValue = switch (memarg.offset + operand.offset()) { |
| 2425 | | 0 => operand, |
| 2426 | | else => |total_offset| ptr: { |
| 2427 | | try cg.emitWValue(operand); |
| 2428 | | try cg.addImm32(@intCast(total_offset)); |
| 2429 | | try cg.addTag(.i32_add); |
| 2430 | | break :ptr .stack; |
| 2431 | | }, |
| 2432 | | }; |
| 2433 | | const src_ptr = try src_ptr_maybe_stack.toLocal(cg, .usize); |
| 2394 | var src_ptr = try cg.offsetPointer(operand, memarg.offset); |
| 2395 | const owns_src_ptr = src_ptr == .stack; |
| 2396 | src_ptr = try src_ptr.toLocal(cg, .usize); |
| 2397 | defer if (owns_src_ptr) src_ptr.free(cg); |
| 2398 | |
| 2434 | 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 | 2401 | return new_ptr; |
| 2437 | 2402 | } |
| 2438 | 2403 | |
| 2439 | | // load local's value from memory by its stack position |
| 2440 | | try cg.emitWValue(operand); |
| 2404 | const base_offset = operand.memOffset(); |
| 2405 | try cg.emitMemBase(operand); |
| 2441 | 2406 | |
| 2442 | 2407 | if (ty.zigTypeTag(zcu) == .vector) { |
| 2443 | 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 | 2411 | try cg.mir_extra.ensureUnusedCapacity(cg.gpa, 4); |
| 2447 | 2412 | cg.mir_extra.appendAssumeCapacity(@backingInt(std.wasm.SimdOpcode.v128_load)); |
| 2448 | 2413 | _ = try cg.addExtraAssumeCapacity(Mir.MemArg{ |
| 2449 | | .offset = memarg.offset + operand.offset(), |
| 2414 | .offset = base_offset + memarg.offset, |
| 2450 | 2415 | .alignment = alignment.toStdMem(), |
| 2451 | 2416 | }); |
| 2452 | 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 | 2442 | try cg.addMemArg( |
| 2478 | 2443 | load_opcode, |
| 2479 | 2444 | .{ |
| 2480 | | .offset = memarg.offset + operand.offset(), |
| 2445 | .offset = base_offset + memarg.offset, |
| 2481 | 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 | 2612 | else => { |
| 2648 | 2613 | const result = try cg.allocInt(ty); |
| 2649 | 2614 | |
| 2650 | | try cg.lowerToStack(result); |
| 2651 | | try cg.lowerToStack(lhs); |
| 2652 | | try cg.lowerToStack(rhs); |
| 2615 | try cg.emitWValue(result); |
| 2616 | try cg.emitWValue(lhs); |
| 2617 | try cg.emitWValue(rhs); |
| 2653 | 2618 | try cg.addImm32(@intFromBool(ty.is_signed)); |
| 2654 | 2619 | try cg.addImm32(ty.bits); |
| 2655 | 2620 | try cg.addCallIntrinsic(.__addo_limb64); |
| ... | ... | @@ -2700,9 +2665,9 @@ fn intSub(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue |
| 2700 | 2665 | else => { |
| 2701 | 2666 | const result = try cg.allocInt(ty); |
| 2702 | 2667 | |
| 2703 | | try cg.lowerToStack(result); |
| 2704 | | try cg.lowerToStack(lhs); |
| 2705 | | try cg.lowerToStack(rhs); |
| 2668 | try cg.emitWValue(result); |
| 2669 | try cg.emitWValue(lhs); |
| 2670 | try cg.emitWValue(rhs); |
| 2706 | 2671 | try cg.addImm32(@intFromBool(ty.is_signed)); |
| 2707 | 2672 | try cg.addImm32(ty.bits); |
| 2708 | 2673 | try cg.addCallIntrinsic(.__subo_limb64); |
| ... | ... | @@ -2732,9 +2697,9 @@ fn intMul(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue |
| 2732 | 2697 | else => { |
| 2733 | 2698 | const result = try cg.allocInt(ty); |
| 2734 | 2699 | |
| 2735 | | try cg.lowerToStack(result); |
| 2736 | | try cg.lowerToStack(lhs); |
| 2737 | | try cg.lowerToStack(rhs); |
| 2700 | try cg.emitWValue(result); |
| 2701 | try cg.emitWValue(lhs); |
| 2702 | try cg.emitWValue(rhs); |
| 2738 | 2703 | try cg.addImm32(@intFromBool(ty.is_signed)); |
| 2739 | 2704 | try cg.addImm32(ty.bits); |
| 2740 | 2705 | try cg.addCallIntrinsic(.__mulo_limb64); |
| ... | ... | @@ -3041,9 +3006,9 @@ fn intAnd(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue |
| 3041 | 3006 | else => { |
| 3042 | 3007 | const result = try cg.allocInt(ty); |
| 3043 | 3008 | |
| 3044 | | try cg.lowerToStack(result); |
| 3045 | | try cg.lowerToStack(lhs); |
| 3046 | | try cg.lowerToStack(rhs); |
| 3009 | try cg.emitWValue(result); |
| 3010 | try cg.emitWValue(lhs); |
| 3011 | try cg.emitWValue(rhs); |
| 3047 | 3012 | try cg.addImm32(ty.bits); |
| 3048 | 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 | 3050 | else => { |
| 3086 | 3051 | const result = try cg.allocInt(ty); |
| 3087 | 3052 | |
| 3088 | | try cg.lowerToStack(result); |
| 3089 | | try cg.lowerToStack(lhs); |
| 3090 | | try cg.lowerToStack(rhs); |
| 3053 | try cg.emitWValue(result); |
| 3054 | try cg.emitWValue(lhs); |
| 3055 | try cg.emitWValue(rhs); |
| 3091 | 3056 | try cg.addImm32(ty.bits); |
| 3092 | 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 | 3094 | else => { |
| 3130 | 3095 | const result = try cg.allocInt(ty); |
| 3131 | 3096 | |
| 3132 | | try cg.lowerToStack(result); |
| 3133 | | try cg.lowerToStack(lhs); |
| 3134 | | try cg.lowerToStack(rhs); |
| 3097 | try cg.emitWValue(result); |
| 3098 | try cg.emitWValue(lhs); |
| 3099 | try cg.emitWValue(rhs); |
| 3135 | 3100 | try cg.addImm32(ty.bits); |
| 3136 | 3101 | try cg.addCallIntrinsic(.__xor_limb64); |
| 3137 | 3102 | |
| ... | ... | @@ -3176,13 +3141,14 @@ fn intNot(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3176 | 3141 | 65...128 => { |
| 3177 | 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 | 3146 | _ = try cg.load(operand, .u64, .{}); |
| 3181 | 3147 | try cg.addImm64(~@as(u64, 0)); |
| 3182 | 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 | 3152 | _ = try cg.load(operand, .u64, .{ .offset = 8 }); |
| 3187 | 3153 | const high_mask: u64 = if (ty.is_signed) |
| 3188 | 3154 | ~@as(u64, 0) |
| ... | ... | @@ -3190,15 +3156,15 @@ fn intNot(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3190 | 3156 | ~@as(u64, 0) >> @intCast(128 - ty.bits); |
| 3191 | 3157 | try cg.addImm64(high_mask); |
| 3192 | 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 | 3161 | return result; |
| 3196 | 3162 | }, |
| 3197 | 3163 | else => { |
| 3198 | 3164 | const result = try cg.allocInt(ty); |
| 3199 | 3165 | |
| 3200 | | try cg.lowerToStack(result); |
| 3201 | | try cg.lowerToStack(operand); |
| 3166 | try cg.emitWValue(result); |
| 3167 | try cg.emitWValue(operand); |
| 3202 | 3168 | try cg.addImm32(@intFromBool(ty.is_signed)); |
| 3203 | 3169 | try cg.addImm32(ty.bits); |
| 3204 | 3170 | try cg.addCallIntrinsic(.__not_limb64); |
| ... | ... | @@ -3230,9 +3196,9 @@ fn intShl(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue |
| 3230 | 3196 | else => { |
| 3231 | 3197 | const result = try cg.allocInt(ty); |
| 3232 | 3198 | |
| 3233 | | try cg.lowerToStack(result); |
| 3234 | | try cg.lowerToStack(lhs); |
| 3235 | | try cg.lowerToStack(rhs); |
| 3199 | try cg.emitWValue(result); |
| 3200 | try cg.emitWValue(lhs); |
| 3201 | try cg.emitWValue(rhs); |
| 3236 | 3202 | try cg.addImm32(@intFromBool(ty.is_signed)); |
| 3237 | 3203 | try cg.addImm32(ty.bits); |
| 3238 | 3204 | try cg.addCallIntrinsic(.__shlo_limb64); |
| ... | ... | @@ -3270,9 +3236,9 @@ fn intShr(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue |
| 3270 | 3236 | else => { |
| 3271 | 3237 | const result = try cg.allocInt(ty); |
| 3272 | 3238 | |
| 3273 | | try cg.lowerToStack(result); |
| 3274 | | try cg.lowerToStack(lhs); |
| 3275 | | try cg.lowerToStack(rhs); |
| 3239 | try cg.emitWValue(result); |
| 3240 | try cg.emitWValue(lhs); |
| 3241 | try cg.emitWValue(rhs); |
| 3276 | 3242 | try cg.addImm32(@intFromBool(ty.is_signed)); |
| 3277 | 3243 | try cg.addImm32(ty.bits); |
| 3278 | 3244 | try cg.addCallIntrinsic(.__shr_limb64); |
| ... | ... | @@ -3320,8 +3286,9 @@ fn intAbs(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3320 | 3286 | const u128_ty: IntType = .{ .is_signed = false, .bits = 128 }; |
| 3321 | 3287 | |
| 3322 | 3288 | const mask = try cg.allocStack(Type.u128); |
| 3323 | | try cg.emitWValue(mask); |
| 3324 | | try cg.emitWValue(mask); |
| 3289 | const mask_offset = mask.memOffset(); |
| 3290 | try cg.emitMemBase(mask); |
| 3291 | try cg.emitMemBase(mask); |
| 3325 | 3292 | |
| 3326 | 3293 | _ = try cg.load(operand, .u64, .{ .offset = 8 }); |
| 3327 | 3294 | try cg.addImm64(63); |
| ... | ... | @@ -3330,9 +3297,9 @@ fn intAbs(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3330 | 3297 | var tmp = try cg.allocLocal(Type.u64); |
| 3331 | 3298 | defer tmp.free(cg); |
| 3332 | 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 | 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 | 3304 | const a = try cg.intXor(u128_ty, operand, mask); |
| 3338 | 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 | 3308 | else => { |
| 3342 | 3309 | const result = try cg.allocInt(ty); |
| 3343 | 3310 | |
| 3344 | | try cg.lowerToStack(result); |
| 3345 | | try cg.lowerToStack(operand); |
| 3311 | try cg.emitWValue(result); |
| 3312 | try cg.emitWValue(operand); |
| 3346 | 3313 | try cg.addImm32(ty.bits); |
| 3347 | 3314 | try cg.addCallIntrinsic(.__abs_limb64); |
| 3348 | 3315 | |
| ... | ... | @@ -3352,16 +3319,16 @@ fn intAbs(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3352 | 3319 | } |
| 3353 | 3320 | |
| 3354 | 3321 | fn intMax(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue { |
| 3355 | | try cg.lowerToStack(lhs); |
| 3356 | | try cg.lowerToStack(rhs); |
| 3322 | try cg.emitWValue(lhs); |
| 3323 | try cg.emitWValue(rhs); |
| 3357 | 3324 | _ = try cg.intCmp(ty, .gt, lhs, rhs); |
| 3358 | 3325 | try cg.addTag(.select); |
| 3359 | 3326 | return .stack; |
| 3360 | 3327 | } |
| 3361 | 3328 | |
| 3362 | 3329 | fn intMin(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerError!WValue { |
| 3363 | | try cg.lowerToStack(lhs); |
| 3364 | | try cg.lowerToStack(rhs); |
| 3330 | try cg.emitWValue(lhs); |
| 3331 | try cg.emitWValue(rhs); |
| 3365 | 3332 | _ = try cg.intCmp(ty, .lt, lhs, rhs); |
| 3366 | 3333 | try cg.addTag(.select); |
| 3367 | 3334 | return .stack; |
| ... | ... | @@ -3427,7 +3394,7 @@ fn intClz(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3427 | 3394 | return .stack; |
| 3428 | 3395 | }, |
| 3429 | 3396 | else => { |
| 3430 | | try cg.lowerToStack(operand); |
| 3397 | try cg.emitWValue(operand); |
| 3431 | 3398 | try cg.addImm32(ty.bits); |
| 3432 | 3399 | try cg.addCallIntrinsic(.__clz_limb64); |
| 3433 | 3400 | |
| ... | ... | @@ -3479,7 +3446,7 @@ fn intCtz(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3479 | 3446 | return .stack; |
| 3480 | 3447 | }, |
| 3481 | 3448 | else => { |
| 3482 | | try cg.lowerToStack(operand); |
| 3449 | try cg.emitWValue(operand); |
| 3483 | 3450 | try cg.addImm32(ty.bits); |
| 3484 | 3451 | try cg.addCallIntrinsic(.__ctz_limb64); |
| 3485 | 3452 | |
| ... | ... | @@ -3525,7 +3492,7 @@ fn intPopCount(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3525 | 3492 | return .stack; |
| 3526 | 3493 | }, |
| 3527 | 3494 | else => { |
| 3528 | | try cg.lowerToStack(operand); |
| 3495 | try cg.emitWValue(operand); |
| 3529 | 3496 | try cg.addImm32(ty.bits); |
| 3530 | 3497 | try cg.addCallIntrinsic(.__popcount_limb64); |
| 3531 | 3498 | |
| ... | ... | @@ -3560,7 +3527,8 @@ fn intBitReverse(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3560 | 3527 | 65...128 => { |
| 3561 | 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 | 3532 | const hi = try cg.load(operand, .u64, .{ .offset = 8 }); |
| 3565 | 3533 | const hi_rev = try cg.callIntrinsic( |
| 3566 | 3534 | .__bitreversedi2, |
| ... | ... | @@ -3569,9 +3537,9 @@ fn intBitReverse(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3569 | 3537 | &.{hi}, |
| 3570 | 3538 | ); |
| 3571 | 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 | 3543 | const lo = try cg.load(operand, .u64, .{}); |
| 3576 | 3544 | const lo_rev = try cg.callIntrinsic( |
| 3577 | 3545 | .__bitreversedi2, |
| ... | ... | @@ -3580,7 +3548,7 @@ fn intBitReverse(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3580 | 3548 | &.{lo}, |
| 3581 | 3549 | ); |
| 3582 | 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 | 3553 | if (ty.bits < 128) { |
| 3586 | 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 | 3560 | else => { |
| 3593 | 3561 | const result = try cg.allocInt(ty); |
| 3594 | 3562 | |
| 3595 | | try cg.lowerToStack(result); |
| 3596 | | try cg.lowerToStack(operand); |
| 3563 | try cg.emitWValue(result); |
| 3564 | try cg.emitWValue(operand); |
| 3597 | 3565 | try cg.addImm32(@intFromBool(ty.is_signed)); |
| 3598 | 3566 | try cg.addImm32(ty.bits); |
| 3599 | 3567 | try cg.addCallIntrinsic(.__bitreverse_limb64); |
| ... | ... | @@ -3629,7 +3597,8 @@ fn intByteSwap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3629 | 3597 | 65...128 => { |
| 3630 | 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 | 3603 | const low = try cg.load(operand, .u64, .{}); |
| 3635 | 3604 | const swap_low = try cg.callIntrinsic( |
| ... | ... | @@ -3638,9 +3607,9 @@ fn intByteSwap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3638 | 3607 | Type.u64, |
| 3639 | 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 | 3614 | const high = try cg.load(operand, .u64, .{ .offset = 8 }); |
| 3646 | 3615 | const swap_high = try cg.callIntrinsic( |
| ... | ... | @@ -3649,7 +3618,7 @@ fn intByteSwap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3649 | 3618 | Type.u64, |
| 3650 | 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 | 3623 | if (ty.bits < 128) { |
| 3655 | 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 | 3630 | else => { |
| 3662 | 3631 | const result = try cg.allocInt(ty); |
| 3663 | 3632 | |
| 3664 | | try cg.lowerToStack(result); |
| 3665 | | try cg.lowerToStack(operand); |
| 3633 | try cg.emitWValue(result); |
| 3634 | try cg.emitWValue(operand); |
| 3666 | 3635 | try cg.addImm32(@intFromBool(ty.is_signed)); |
| 3667 | 3636 | try cg.addImm32(ty.bits); |
| 3668 | 3637 | try cg.addCallIntrinsic(.__byteswap_limb64); |
| ... | ... | @@ -3706,11 +3675,12 @@ fn intWrap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3706 | 3675 | 65...127 => { |
| 3707 | 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 | 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 | 3684 | _ = try cg.load(operand, .u64, .{ .offset = 8 }); |
| 3715 | 3685 | if (ty.is_signed) { |
| 3716 | 3686 | try cg.addImm64(128 - ty.bits); |
| ... | ... | @@ -3721,7 +3691,7 @@ fn intWrap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3721 | 3691 | try cg.addImm64(~@as(u64, 0) >> @intCast(128 - ty.bits)); |
| 3722 | 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 | 3696 | return result; |
| 3727 | 3697 | }, |
| ... | ... | @@ -3738,7 +3708,7 @@ fn intWrap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3738 | 3708 | try cg.memcpy(result, operand, .{ .imm32 = used_len - 8 }); |
| 3739 | 3709 | const pad = 64 - ty.bits % 64; |
| 3740 | 3710 | |
| 3741 | | try cg.emitWValue(result); |
| 3711 | try cg.emitMemBase(result); |
| 3742 | 3712 | _ = try cg.load(operand, .u64, .{ .offset = used_len - 8 }); |
| 3743 | 3713 | if (ty.is_signed) { |
| 3744 | 3714 | try cg.addImm64(pad); |
| ... | ... | @@ -3749,14 +3719,14 @@ fn intWrap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3749 | 3719 | try cg.addImm64(~@as(u64, 0) >> @intCast(pad)); |
| 3750 | 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 | 3723 | } else { |
| 3754 | 3724 | try cg.memcpy(result, operand, .{ .imm32 = used_len }); |
| 3755 | 3725 | } |
| 3756 | 3726 | |
| 3757 | 3727 | const full_len = @divExact(bits, 8); |
| 3758 | 3728 | if (used_len + 8 == full_len) { // last limb needs sign extended |
| 3759 | | try cg.emitWValue(result); |
| 3729 | try cg.emitMemBase(result); |
| 3760 | 3730 | if (ty.is_signed) { |
| 3761 | 3731 | _ = try cg.load(result, .u64, .{ .offset = used_len - 8 }); |
| 3762 | 3732 | try cg.addImm64(63); |
| ... | ... | @@ -3764,7 +3734,7 @@ fn intWrap(cg: *CodeGen, ty: IntType, operand: WValue) InnerError!WValue { |
| 3764 | 3734 | } else { |
| 3765 | 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 | 3740 | return result; |
| ... | ... | @@ -3858,20 +3828,20 @@ fn intAddSat(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError |
| 3858 | 3828 | defer rhs_is_neg.free(cg); |
| 3859 | 3829 | const min_val = try cg.intMinValue(int_ty); |
| 3860 | 3830 | |
| 3861 | | try cg.lowerToStack(min_val); |
| 3862 | | try cg.lowerToStack(max_val); |
| 3831 | try cg.emitWValue(min_val); |
| 3832 | try cg.emitWValue(max_val); |
| 3863 | 3833 | try cg.emitWValue(rhs_is_neg); |
| 3864 | 3834 | try cg.addTag(.select); |
| 3865 | 3835 | |
| 3866 | | try cg.lowerToStack(op_val); |
| 3836 | try cg.emitWValue(op_val); |
| 3867 | 3837 | const overflow_cmp = try cg.intCmp(int_ty, .lt, op_val, lhs); |
| 3868 | 3838 | const is_overflow = try cg.intCmp(.u32, .neq, rhs_is_neg, overflow_cmp); |
| 3869 | 3839 | try cg.emitWValue(is_overflow); |
| 3870 | 3840 | try cg.addTag(.select); |
| 3871 | 3841 | return .stack; |
| 3872 | 3842 | } else { |
| 3873 | | try cg.lowerToStack(max_val); |
| 3874 | | try cg.lowerToStack(op_val); |
| 3843 | try cg.emitWValue(max_val); |
| 3844 | try cg.emitWValue(op_val); |
| 3875 | 3845 | |
| 3876 | 3846 | const is_overflow = try cg.intCmp(int_ty, .lt, op_val, lhs); |
| 3877 | 3847 | try cg.emitWValue(is_overflow); |
| ... | ... | @@ -3892,12 +3862,12 @@ fn intSubSat(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError |
| 3892 | 3862 | const max_val = try cg.intMaxValue(int_ty); |
| 3893 | 3863 | const min_val = try cg.intMinValue(int_ty); |
| 3894 | 3864 | |
| 3895 | | try cg.lowerToStack(max_val); |
| 3896 | | try cg.lowerToStack(min_val); |
| 3865 | try cg.emitWValue(max_val); |
| 3866 | try cg.emitWValue(min_val); |
| 3897 | 3867 | try cg.emitWValue(rhs_is_neg); |
| 3898 | 3868 | try cg.addTag(.select); |
| 3899 | 3869 | |
| 3900 | | try cg.lowerToStack(op_val); |
| 3870 | try cg.emitWValue(op_val); |
| 3901 | 3871 | const overflow_cmp = try cg.intCmp(int_ty, .gt, op_val, lhs); |
| 3902 | 3872 | const is_overflow = try cg.intCmp(.u32, .neq, rhs_is_neg, overflow_cmp); |
| 3903 | 3873 | try cg.emitWValue(is_overflow); |
| ... | ... | @@ -3906,8 +3876,8 @@ fn intSubSat(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError |
| 3906 | 3876 | } else { |
| 3907 | 3877 | const zero = try cg.intZeroValue(int_ty); |
| 3908 | 3878 | |
| 3909 | | try cg.lowerToStack(zero); |
| 3910 | | try cg.lowerToStack(op_val); |
| 3879 | try cg.emitWValue(zero); |
| 3880 | try cg.emitWValue(op_val); |
| 3911 | 3881 | const is_overflow = try cg.intCmp(int_ty, .lt, lhs, rhs); |
| 3912 | 3882 | try cg.emitWValue(is_overflow); |
| 3913 | 3883 | try cg.addTag(.select); |
| ... | ... | @@ -3931,10 +3901,10 @@ fn intMulSat(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError |
| 3931 | 3901 | if (int_ty.is_signed) { |
| 3932 | 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); |
| 3937 | | try cg.lowerToStack(op_val); |
| 3906 | try cg.emitWValue(max_val); |
| 3907 | try cg.emitWValue(op_val); |
| 3938 | 3908 | const max_ext = try cg.intCast(ext_ty, int_ty, max_val); |
| 3939 | 3909 | const ov_pos = try cg.intCmp(ext_ty, .lt, max_ext, mul_ext); |
| 3940 | 3910 | try cg.emitWValue(ov_pos); |
| ... | ... | @@ -3942,12 +3912,12 @@ fn intMulSat(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError |
| 3942 | 3912 | |
| 3943 | 3913 | const min_ext = try cg.intCast(ext_ty, int_ty, min_val); |
| 3944 | 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 | 3916 | try cg.addTag(.select); |
| 3947 | 3917 | return .stack; |
| 3948 | 3918 | } else { |
| 3949 | | try cg.lowerToStack(max_val); |
| 3950 | | try cg.lowerToStack(op_val); |
| 3919 | try cg.emitWValue(max_val); |
| 3920 | try cg.emitWValue(op_val); |
| 3951 | 3921 | const max_ext = try cg.intCast(ext_ty, int_ty, max_val); |
| 3952 | 3922 | const is_overflow = try cg.intCmp(ext_ty, .lt, max_ext, mul_ext); |
| 3953 | 3923 | try cg.emitWValue(is_overflow); |
| ... | ... | @@ -3970,20 +3940,20 @@ fn intShlSat(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) InnerError |
| 3970 | 3940 | const zero = try cg.intZeroValue(int_ty); |
| 3971 | 3941 | const min_val = try cg.intMinValue(int_ty); |
| 3972 | 3942 | |
| 3973 | | try cg.lowerToStack(min_val); |
| 3974 | | try cg.lowerToStack(max_val); |
| 3943 | try cg.emitWValue(min_val); |
| 3944 | try cg.emitWValue(max_val); |
| 3975 | 3945 | const lhs_is_neg = try cg.intCmp(int_ty, .lt, lhs, zero); |
| 3976 | 3946 | try cg.emitWValue(lhs_is_neg); |
| 3977 | 3947 | try cg.addTag(.select); |
| 3978 | 3948 | |
| 3979 | | try cg.lowerToStack(op_val); |
| 3949 | try cg.emitWValue(op_val); |
| 3980 | 3950 | const is_overflow = try cg.intCmp(int_ty, .neq, check_val, lhs); |
| 3981 | 3951 | try cg.emitWValue(is_overflow); |
| 3982 | 3952 | try cg.addTag(.select); |
| 3983 | 3953 | return .stack; |
| 3984 | 3954 | } else { |
| 3985 | | try cg.lowerToStack(max_val); |
| 3986 | | try cg.lowerToStack(op_val); |
| 3955 | try cg.emitWValue(max_val); |
| 3956 | try cg.emitWValue(op_val); |
| 3987 | 3957 | const is_overflow = try cg.intCmp(int_ty, .neq, check_val, lhs); |
| 3988 | 3958 | try cg.emitWValue(is_overflow); |
| 3989 | 3959 | try cg.addTag(.select); |
| ... | ... | @@ -4055,9 +4025,9 @@ fn intAddOverflow(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerErro |
| 4055 | 4025 | else => { |
| 4056 | 4026 | const result = try cg.allocInt(ty); |
| 4057 | 4027 | |
| 4058 | | try cg.lowerToStack(result); |
| 4059 | | try cg.lowerToStack(lhs); |
| 4060 | | try cg.lowerToStack(rhs); |
| 4028 | try cg.emitWValue(result); |
| 4029 | try cg.emitWValue(lhs); |
| 4030 | try cg.emitWValue(rhs); |
| 4061 | 4031 | try cg.addImm32(@intFromBool(ty.is_signed)); |
| 4062 | 4032 | try cg.addImm32(ty.bits); |
| 4063 | 4033 | try cg.addCallIntrinsic(.__addo_limb64); |
| ... | ... | @@ -4087,9 +4057,9 @@ fn intSubOverflow(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerErro |
| 4087 | 4057 | else => { |
| 4088 | 4058 | const result = try cg.allocInt(ty); |
| 4089 | 4059 | |
| 4090 | | try cg.lowerToStack(result); |
| 4091 | | try cg.lowerToStack(lhs); |
| 4092 | | try cg.lowerToStack(rhs); |
| 4060 | try cg.emitWValue(result); |
| 4061 | try cg.emitWValue(lhs); |
| 4062 | try cg.emitWValue(rhs); |
| 4093 | 4063 | try cg.addImm32(@intFromBool(ty.is_signed)); |
| 4094 | 4064 | try cg.addImm32(ty.bits); |
| 4095 | 4065 | try cg.addCallIntrinsic(.__subo_limb64); |
| ... | ... | @@ -4145,9 +4115,9 @@ fn intMulOverflow(cg: *CodeGen, int_ty: IntType, lhs: WValue, rhs: WValue) Inner |
| 4145 | 4115 | } else { |
| 4146 | 4116 | const result = try cg.allocInt(int_ty); |
| 4147 | 4117 | |
| 4148 | | try cg.lowerToStack(result); |
| 4149 | | try cg.lowerToStack(lhs); |
| 4150 | | try cg.lowerToStack(rhs); |
| 4118 | try cg.emitWValue(result); |
| 4119 | try cg.emitWValue(lhs); |
| 4120 | try cg.emitWValue(rhs); |
| 4151 | 4121 | try cg.addImm32(@intFromBool(int_ty.is_signed)); |
| 4152 | 4122 | try cg.addImm32(int_ty.bits); |
| 4153 | 4123 | try cg.addCallIntrinsic(.__mulo_limb64); |
| ... | ... | @@ -4174,9 +4144,9 @@ fn intShlOverflow(cg: *CodeGen, ty: IntType, lhs: WValue, rhs: WValue) InnerErro |
| 4174 | 4144 | else => { |
| 4175 | 4145 | const result = try cg.allocInt(ty); |
| 4176 | 4146 | |
| 4177 | | try cg.lowerToStack(result); |
| 4178 | | try cg.lowerToStack(lhs); |
| 4179 | | try cg.lowerToStack(rhs); |
| 4147 | try cg.emitWValue(result); |
| 4148 | try cg.emitWValue(lhs); |
| 4149 | try cg.emitWValue(rhs); |
| 4180 | 4150 | try cg.addImm32(@intFromBool(ty.is_signed)); |
| 4181 | 4151 | try cg.addImm32(ty.bits); |
| 4182 | 4152 | try cg.addCallIntrinsic(.__shlo_limb64); |
| ... | ... | @@ -4213,15 +4183,15 @@ fn intCast(cg: *CodeGen, dest_ty: IntType, src_ty: IntType, operand: WValue) Inn |
| 4213 | 4183 | } else { |
| 4214 | 4184 | var src_len: u32 = undefined; |
| 4215 | 4185 | if (src_bits == 32) { |
| 4216 | | try cg.emitWValue(result); |
| 4186 | try cg.emitMemBase(result); |
| 4217 | 4187 | try cg.emitWValue(operand); |
| 4218 | 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 | 4190 | src_len = 8; |
| 4221 | 4191 | } else if (src_bits == 64) { |
| 4222 | | try cg.emitWValue(result); |
| 4192 | try cg.emitMemBase(result); |
| 4223 | 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 | 4195 | src_len = 8; |
| 4226 | 4196 | } else { |
| 4227 | 4197 | src_len = src_bits / 8; |
| ... | ... | @@ -4230,7 +4200,7 @@ fn intCast(cg: *CodeGen, dest_ty: IntType, src_ty: IntType, operand: WValue) Inn |
| 4230 | 4200 | |
| 4231 | 4201 | if (dest_bits == 128) { |
| 4232 | 4202 | if (src_ty.is_signed) { |
| 4233 | | try cg.emitWValue(result); |
| 4203 | try cg.emitMemBase(result); |
| 4234 | 4204 | if (src_bits == 32) { |
| 4235 | 4205 | try cg.emitWValue(operand); |
| 4236 | 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 | 4208 | try cg.emitWValue(operand); |
| 4239 | 4209 | } else unreachable; |
| 4240 | 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 | 4212 | } else { |
| 4243 | 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 | 4612 | }, |
| 4643 | 4613 | .f80, .f128 => { |
| 4644 | 4614 | const result = try cg.allocStack(Type.f128); |
| 4645 | | try cg.emitWValue(result); |
| 4646 | | try cg.emitWValue(arg); |
| 4647 | | try cg.addMemArg(.i64_load, .{ .offset = 0 + arg.offset(), .alignment = .@"2" }); |
| 4648 | | try cg.addMemArg(.i64_store, .{ .offset = 0 + result.offset(), .alignment = .@"2" }); |
| 4649 | | try cg.emitWValue(result); |
| 4650 | | try cg.emitWValue(arg); |
| 4651 | | try cg.addMemArg(.i64_load, .{ .offset = 8 + arg.offset(), .alignment = .@"2" }); |
| 4615 | const result_offset = result.memOffset(); |
| 4616 | const arg_offset = arg.memOffset(); |
| 4617 | try cg.emitMemBase(result); |
| 4618 | try cg.emitMemBase(arg); |
| 4619 | try cg.addMemArg(.i64_load, .{ .offset = arg_offset, .alignment = .@"2" }); |
| 4620 | try cg.addMemArg(.i64_store, .{ .offset = result_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 | 4624 | if (ty == .f80) { |
| 4653 | 4625 | try cg.addImm64(0x8000); |
| 4654 | 4626 | } else { |
| 4655 | 4627 | try cg.addImm64(0x8000000000000000); |
| 4656 | 4628 | } |
| 4657 | 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 | 4631 | return result; |
| 4660 | 4632 | }, |
| 4661 | 4633 | } |
| ... | ... | @@ -4681,20 +4653,22 @@ fn floatAbs(cg: *CodeGen, ty: FloatType, arg: WValue) InnerError!WValue { |
| 4681 | 4653 | }, |
| 4682 | 4654 | .f80, .f128 => { |
| 4683 | 4655 | const result = try cg.allocStack(Type.f128); |
| 4684 | | try cg.emitWValue(result); |
| 4685 | | try cg.emitWValue(arg); |
| 4686 | | try cg.addMemArg(.i64_load, .{ .offset = 0 + arg.offset(), .alignment = .@"2" }); |
| 4687 | | try cg.addMemArg(.i64_store, .{ .offset = 0 + result.offset(), .alignment = .@"2" }); |
| 4688 | | try cg.emitWValue(result); |
| 4689 | | try cg.emitWValue(arg); |
| 4690 | | try cg.addMemArg(.i64_load, .{ .offset = 8 + arg.offset(), .alignment = .@"2" }); |
| 4656 | const result_offset = result.memOffset(); |
| 4657 | const arg_offset = arg.memOffset(); |
| 4658 | try cg.emitMemBase(result); |
| 4659 | try cg.emitMemBase(arg); |
| 4660 | try cg.addMemArg(.i64_load, .{ .offset = arg_offset, .alignment = .@"2" }); |
| 4661 | try cg.addMemArg(.i64_store, .{ .offset = result_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 | 4665 | if (ty == .f80) { |
| 4692 | 4666 | try cg.addImm64(0x7FFF); |
| 4693 | 4667 | } else { |
| 4694 | 4668 | try cg.addImm64(0x7FFFFFFFFFFFFFFF); |
| 4695 | 4669 | } |
| 4696 | 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 | 4672 | return result; |
| 4699 | 4673 | }, |
| 4700 | 4674 | } |
| ... | ... | @@ -5377,8 +5351,8 @@ fn intCmp(cg: *CodeGen, ty: IntType, op: std.math.CompareOperator, lhs: WValue, |
| 5377 | 5351 | 0 => unreachable, |
| 5378 | 5352 | 1...32 => { |
| 5379 | 5353 | // lhs or rhs could be stack pointers |
| 5380 | | try cg.lowerToStack(lhs); |
| 5381 | | try cg.lowerToStack(rhs); |
| 5354 | try cg.emitWValue(lhs); |
| 5355 | try cg.emitWValue(rhs); |
| 5382 | 5356 | const opcode: Mir.Inst.Tag = switch (op) { |
| 5383 | 5357 | .eq => .i32_eq, |
| 5384 | 5358 | .neq => .i32_ne, |
| ... | ... | @@ -5392,8 +5366,8 @@ fn intCmp(cg: *CodeGen, ty: IntType, op: std.math.CompareOperator, lhs: WValue, |
| 5392 | 5366 | }, |
| 5393 | 5367 | 33...64 => { |
| 5394 | 5368 | // lhs or rhs could be stack pointers |
| 5395 | | try cg.lowerToStack(lhs); |
| 5396 | | try cg.lowerToStack(rhs); |
| 5369 | try cg.emitWValue(lhs); |
| 5370 | try cg.emitWValue(rhs); |
| 5397 | 5371 | const opcode: Mir.Inst.Tag = switch (op) { |
| 5398 | 5372 | .eq => .i64_eq, |
| 5399 | 5373 | .neq => .i64_ne, |
| ... | ... | @@ -5442,8 +5416,8 @@ fn intCmp(cg: *CodeGen, ty: IntType, op: std.math.CompareOperator, lhs: WValue, |
| 5442 | 5416 | return .stack; |
| 5443 | 5417 | }, |
| 5444 | 5418 | else => { |
| 5445 | | try cg.lowerToStack(lhs); |
| 5446 | | try cg.lowerToStack(rhs); |
| 5419 | try cg.emitWValue(lhs); |
| 5420 | try cg.emitWValue(rhs); |
| 5447 | 5421 | try cg.addImm32(@intFromBool(ty.is_signed)); |
| 5448 | 5422 | try cg.addImm32(ty.bits); |
| 5449 | 5423 | try cg.addCallIntrinsic(.__cmp_limb64); |
| ... | ... | @@ -5554,7 +5528,7 @@ fn airBr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 5554 | 5528 | // if operand has codegen bits we should break with a value |
| 5555 | 5529 | if (block.value != .none) { |
| 5556 | 5530 | const operand = try cg.resolveInst(br.operand); |
| 5557 | | try cg.lowerToStack(operand); |
| 5531 | try cg.emitWValue(operand); |
| 5558 | 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 | 5592 | assert(operand_ty.abiAlignment(zcu) == dest_ty.abiAlignment(zcu)); |
| 5619 | 5593 | |
| 5620 | 5594 | const operand = try cg.resolveInst(ty_op.operand); |
| 5621 | | const result = switch (operand) { |
| 5622 | | .stack_offset => try cg.buildPointerOffset(operand, 0, .new), |
| 5623 | | else => operand, |
| 5624 | | }; |
| 5625 | | return cg.finishAir(inst, result, &.{ty_op.operand}); |
| 5595 | if (operand == .stack_offset) { |
| 5596 | // materialize operand, we assume precomputed value is more efficient |
| 5597 | try cg.emitWValue(operand); |
| 5598 | return cg.finishAir(inst, .stack, &.{ty_op.operand}); |
| 5599 | } |
| 5600 | return cg.finishAir(inst, operand, &.{ty_op.operand}); |
| 5626 | 5601 | } |
| 5627 | 5602 | |
| 5628 | 5603 | fn airUnionFromEnum(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| ... | ... | @@ -5801,16 +5776,7 @@ fn structFieldPtr( |
| 5801 | 5776 | }, |
| 5802 | 5777 | else => struct_ty.structFieldOffset(index, zcu), |
| 5803 | 5778 | }; |
| 5804 | | // save a load and store when we can simply reuse the operand |
| 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 | | } |
| 5779 | return cg.offsetPointer(struct_ptr, offset); |
| 5814 | 5780 | } |
| 5815 | 5781 | |
| 5816 | 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 | 5798 | return cg.fail("Field type '{f}' too big to fit into stack frame", .{field_ty.fmt(pt)}); |
| 5833 | 5799 | }; |
| 5834 | 5800 | if (isByRef(field_ty, zcu, cg.target)) { |
| 5835 | | switch (operand) { |
| 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 | | } |
| 5801 | break :result try cg.offsetPointer(operand, offset); |
| 5841 | 5802 | } |
| 5842 | 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 | 5820 | const target = if (is_dispatch_loop) target: { |
| 5860 | 5821 | const initial_target = try cg.resolveInst(switch_br.operand); |
| 5861 | 5822 | const target: WValue = try cg.allocLocal(target_ty); |
| 5862 | | try cg.lowerToStack(initial_target); |
| 5823 | try cg.emitWValue(initial_target); |
| 5863 | 5824 | try cg.addLocal(.local_set, target.local.value); |
| 5864 | 5825 | |
| 5865 | 5826 | try cg.startBlock(.loop, .empty); // dispatch loop start |
| ... | ... | @@ -6052,7 +6013,7 @@ fn airSwitchDispatch(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6052 | 6013 | const switch_loop = cg.blocks.get(br.block_inst).?; |
| 6053 | 6014 | |
| 6054 | 6015 | const operand = try cg.resolveInst(br.operand); |
| 6055 | | try cg.lowerToStack(operand); |
| 6016 | try cg.emitWValue(operand); |
| 6056 | 6017 | try cg.addLocal(.local_set, switch_loop.value.local.value); |
| 6057 | 6018 | |
| 6058 | 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 | 6041 | } |
| 6081 | 6042 | } |
| 6082 | 6043 | |
| 6083 | | try cg.emitWValue(operand); |
| 6084 | 6044 | if (op_kind == .ptr or pl_ty.hasRuntimeBits(zcu)) { |
| 6045 | try cg.emitMemBase(operand); |
| 6085 | 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 | 6048 | .alignment = Type.anyerror.abiAlignment(zcu).toStdMem(), |
| 6088 | 6049 | }); |
| 6050 | } else { |
| 6051 | try cg.emitWValue(operand); |
| 6089 | 6052 | } |
| 6090 | 6053 | |
| 6091 | 6054 | // Compare the error value with '0' |
| ... | ... | @@ -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 | 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 | 6085 | } else { |
| 6123 | 6086 | assert(isByRef(eu_ty, zcu, cg.target)); |
| 6124 | 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 | 6132 | } |
| 6170 | 6133 | |
| 6171 | 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); |
| 6173 | | try cg.store(payload_ptr, operand, pl_ty, .{}); |
| 6135 | try cg.store(err_union, operand, pl_ty, .{ .offset = errUnionPayloadOffset(pl_ty, zcu) }); |
| 6174 | 6136 | |
| 6175 | 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 | 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 | 6141 | try cg.addMemArg(.i32_store16, .{ |
| 6180 | | .offset = err_union.offset() + err_val_offset, |
| 6142 | .offset = err_union.memOffset() + err_val_offset, |
| 6181 | 6143 | .alignment = .@"2", |
| 6182 | 6144 | }); |
| 6183 | 6145 | break :result err_union; |
| ... | ... | @@ -6203,7 +6165,7 @@ fn airWrapErrUnionErr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6203 | 6165 | try cg.store(err_union, operand, .anyerror, .{ .offset = errUnionErrorOffset(pl_ty, zcu) }); |
| 6204 | 6166 | |
| 6205 | 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 | 6169 | const len = @as(u32, @intCast(err_ty.errorUnionPayload(zcu).abiSize(zcu))); |
| 6208 | 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 | 6190 | fn isNull(cg: *CodeGen, operand: WValue, op_ty: Type, opcode: std.wasm.Opcode, op_kind: OpKind) InnerError!WValue { |
| 6229 | 6191 | const pt = cg.pt; |
| 6230 | 6192 | const zcu = pt.zcu; |
| 6231 | | try cg.emitWValue(operand); |
| 6232 | 6193 | const optional_ty = switch (op_kind) { |
| 6233 | 6194 | .value => op_ty, |
| 6234 | 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 | 6202 | const offset = std.math.cast(u32, payload_ty.abiSize(zcu)) orelse { |
| 6242 | 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 | 6210 | } else if (payload_ty.isSlice(zcu)) { |
| 6211 | const base_offset = operand.memOffset(); |
| 6212 | try cg.emitMemBase(operand); |
| 6247 | 6213 | switch (cg.ptr_size) { |
| 6248 | | .wasm32 => try cg.addMemArg(.i32_load, .{ .offset = operand.offset(), .alignment = .@"4" }), |
| 6249 | | .wasm64 => try cg.addMemArg(.i64_load, .{ .offset = operand.offset(), .alignment = .@"8" }), |
| 6214 | .wasm32 => try cg.addMemArg(.i32_load, .{ .offset = base_offset, .alignment = .@"4" }), |
| 6215 | .wasm64 => try cg.addMemArg(.i64_load, .{ .offset = base_offset, .alignment = .@"8" }), |
| 6250 | 6216 | } |
| 6251 | 6217 | } else { |
| 6252 | 6218 | if (op_kind == .ptr) { |
| 6219 | try cg.emitMemBase(operand); |
| 6253 | 6220 | try cg.addMemArg(.i32_load, .{ |
| 6254 | | .offset = operand.offset(), |
| 6221 | .offset = operand.memOffset(), |
| 6255 | 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 | 6247 | if (opt_ty.optionalReprIsPayload(zcu)) break :result operand; |
| 6279 | 6248 | |
| 6280 | 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 | 6253 | break :result try cg.load(operand, payload_ty, .{}); |
| ... | ... | @@ -6298,7 +6267,7 @@ fn airOptionalPayloadPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6298 | 6267 | break :result operand; |
| 6299 | 6268 | } |
| 6300 | 6269 | |
| 6301 | | break :result try cg.buildPointerOffset(operand, 0, .new); |
| 6270 | break :result operand; |
| 6302 | 6271 | }; |
| 6303 | 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 | 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 | 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); |
| 6327 | | return cg.finishAir(inst, result, &.{ty_op.operand}); |
| 6295 | return cg.finishAir(inst, operand, &.{ty_op.operand}); |
| 6328 | 6296 | } |
| 6329 | 6297 | |
| 6330 | 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 | 6304 | const result = result: { |
| 6337 | 6305 | if (!payload_ty.hasRuntimeBits(zcu)) { |
| 6338 | 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 | 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 | 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 | 6321 | |
| 6354 | 6322 | // Create optional type, set the non-null bit, and store the operand inside the optional type |
| 6355 | 6323 | const result_ptr = try cg.allocStack(op_ty); |
| 6356 | | try cg.emitWValue(result_ptr); |
| 6324 | try cg.emitMemBase(result_ptr); |
| 6357 | 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); |
| 6361 | | try cg.store(payload_ptr, operand, payload_ty, .{}); |
| 6328 | try cg.store(result_ptr, operand, payload_ty, .{}); |
| 6362 | 6329 | break :result result_ptr; |
| 6363 | 6330 | }; |
| 6364 | 6331 | |
| ... | ... | @@ -6483,7 +6450,7 @@ fn airPtrElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6483 | 6450 | if (ptr_ty.isSlice(zcu)) { |
| 6484 | 6451 | _ = try cg.load(ptr, .usize, .{}); |
| 6485 | 6452 | } else { |
| 6486 | | try cg.lowerToStack(ptr); |
| 6453 | try cg.emitWValue(ptr); |
| 6487 | 6454 | } |
| 6488 | 6455 | |
| 6489 | 6456 | // calculate index into slice |
| ... | ... | @@ -6513,7 +6480,7 @@ fn airPtrElemPtr(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6513 | 6480 | if (ptr_ty.isSlice(zcu)) { |
| 6514 | 6481 | _ = try cg.load(ptr, .usize, .{}); |
| 6515 | 6482 | } else { |
| 6516 | | try cg.lowerToStack(ptr); |
| 6483 | try cg.emitWValue(ptr); |
| 6517 | 6484 | } |
| 6518 | 6485 | |
| 6519 | 6486 | // calculate index into ptr |
| ... | ... | @@ -6538,7 +6505,7 @@ fn airPtrBinOp(cg: *CodeGen, inst: Air.Inst.Index, op: enum { add, sub }) InnerE |
| 6538 | 6505 | else => ptr_ty.childType(zcu), |
| 6539 | 6506 | }; |
| 6540 | 6507 | |
| 6541 | | try cg.lowerToStack(ptr); |
| 6508 | try cg.emitWValue(ptr); |
| 6542 | 6509 | try cg.emitWValue(offset); |
| 6543 | 6510 | |
| 6544 | 6511 | switch (cg.ptr_size) { |
| ... | ... | @@ -6620,7 +6587,7 @@ fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue) |
| 6620 | 6587 | try cg.addLabel(.br_if, 0); |
| 6621 | 6588 | } |
| 6622 | 6589 | |
| 6623 | | try cg.lowerToStack(ptr); |
| 6590 | try cg.emitWValue(ptr); |
| 6624 | 6591 | try cg.emitWValue(value); |
| 6625 | 6592 | try cg.emitWValue(len); |
| 6626 | 6593 | try cg.addExtended(.memory_fill); |
| ... | ... | @@ -6655,11 +6622,13 @@ fn memset(cg: *CodeGen, elem_ty: Type, ptr: WValue, len: WValue, value: WValue) |
| 6655 | 6622 | |
| 6656 | 6623 | var end_ptr = try cg.allocLocal(Type.usize); |
| 6657 | 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 | 6626 | defer new_ptr.free(cg); |
| 6627 | try cg.emitWValue(ptr); |
| 6628 | try cg.addLocal(.local_set, new_ptr.local.value); |
| 6660 | 6629 | |
| 6661 | 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 | 6632 | try cg.emitWValue(final_len); |
| 6664 | 6633 | switch (cg.ptr_size) { |
| 6665 | 6634 | .wasm32 => try cg.addTag(.i32_add), |
| ... | ... | @@ -6714,7 +6683,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6714 | 6683 | const elem_size = elem_ty.abiSize(zcu); |
| 6715 | 6684 | |
| 6716 | 6685 | if (isByRef(array_ty, zcu, cg.target)) { |
| 6717 | | try cg.lowerToStack(array); |
| 6686 | try cg.emitWValue(array); |
| 6718 | 6687 | try cg.emitWValue(index); |
| 6719 | 6688 | try cg.addImm32(@intCast(elem_size)); |
| 6720 | 6689 | try cg.addTag(.i32_mul); |
| ... | ... | @@ -6747,7 +6716,7 @@ fn airArrayElemVal(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6747 | 6716 | try cg.store(stack_vec, array, array_ty, .{}); |
| 6748 | 6717 | |
| 6749 | 6718 | // Is a non-unrolled vector (v128) |
| 6750 | | try cg.lowerToStack(stack_vec); |
| 6719 | try cg.emitWValue(stack_vec); |
| 6751 | 6720 | try cg.emitWValue(index); |
| 6752 | 6721 | try cg.addImm32(@intCast(elem_size)); |
| 6753 | 6722 | try cg.addTag(.i32_mul); |
| ... | ... | @@ -6783,13 +6752,13 @@ fn airSplat(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 6783 | 6752 | 64 => @backingInt(std.wasm.SimdOpcode.v128_load64_splat), |
| 6784 | 6753 | else => break :blk, // Cannot make use of simd-instructions |
| 6785 | 6754 | }; |
| 6786 | | try cg.emitWValue(operand); |
| 6755 | try cg.emitMemBase(operand); |
| 6787 | 6756 | const extra_index: u32 = @intCast(cg.mir_extra.items.len); |
| 6788 | 6757 | // stores as := opcode, offset, alignment (opcode::memarg) |
| 6789 | 6758 | try cg.mir_extra.ensureUnusedCapacity(cg.gpa, 4); |
| 6790 | 6759 | cg.mir_extra.appendAssumeCapacity(opcode); |
| 6791 | 6760 | _ = try cg.addExtraAssumeCapacity(Mir.MemArg{ |
| 6792 | | .offset = operand.offset(), |
| 6761 | .offset = operand.memOffset(), |
| 6793 | 6762 | .alignment = elem_ty.abiAlignment(zcu).toStdMem(), |
| 6794 | 6763 | }); |
| 6795 | 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 | 6825 | |
| 6857 | 6826 | const dest_alloc = try cg.allocStack(result_ty); |
| 6858 | 6827 | for (mask, 0..) |mask_elem, out_idx| { |
| 6859 | | try cg.emitWValue(dest_alloc); |
| 6828 | try cg.emitMemBase(dest_alloc); |
| 6860 | 6829 | const elem_val = switch (mask_elem.unwrap()) { |
| 6861 | 6830 | .elem => |idx| try cg.load(operand, elem_ty, .{ .offset = elem_size * idx }), |
| 6862 | 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 | 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 | 6893 | |
| 6925 | 6894 | const dest_alloc = try cg.allocStack(result_ty); |
| 6926 | 6895 | for (mask, 0..) |mask_elem, out_idx| { |
| 6927 | | try cg.emitWValue(dest_alloc); |
| 6896 | try cg.emitMemBase(dest_alloc); |
| 6928 | 6897 | const elem_val = switch (mask_elem.unwrap()) { |
| 6929 | 6898 | .a_elem => |idx| try cg.load(operand_a, elem_ty, .{ .offset = elem_size * idx }), |
| 6930 | 6899 | .b_elem => |idx| try cg.load(operand_b, elem_ty, .{ .offset = elem_size * idx }), |
| 6931 | 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 | 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 | 6925 | .array, .vector => { |
| 6957 | 6926 | const result = try cg.allocStack(result_ty); |
| 6958 | 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 | 6929 | const sentinel = result_ty.sentinel(zcu); |
| 6961 | 6930 | |
| 6962 | | // When the element type is by reference, we must copy the entire |
| 6963 | | // value. It is therefore safer to move the offset pointer and store |
| 6964 | | // each value individually, instead of using store offsets. |
| 6965 | | if (isByRef(elem_ty, zcu, cg.target)) { |
| 6966 | | // copy stack pointer into a temporary local, which is |
| 6967 | | // moved for each element to store each value in the right position. |
| 6968 | | const offset = try cg.buildPointerOffset(result, 0, .new); |
| 6969 | | for (elements, 0..) |elem, elem_index| { |
| 6970 | | const elem_val = try cg.resolveInst(elem); |
| 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 | | } |
| 6931 | var offset: u64 = 0; |
| 6932 | for (elements) |elem| { |
| 6933 | const elem_val = try cg.resolveInst(elem); |
| 6934 | try cg.store(result, elem_val, elem_ty, .{ .offset = offset }); |
| 6935 | offset += elem_size; |
| 6936 | } |
| 6937 | if (sentinel) |s| { |
| 6938 | const val = try cg.resolveValue(s); |
| 6939 | try cg.store(result, val, elem_ty, .{ .offset = offset }); |
| 6992 | 6940 | } |
| 6993 | 6941 | break :result_value result; |
| 6994 | 6942 | }, |
| ... | ... | @@ -7001,10 +6949,9 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7001 | 6949 | |
| 7002 | 6950 | const elem_ty = result_ty.fieldType(elem_index, zcu); |
| 7003 | 6951 | const field_offset = result_ty.structFieldOffset(elem_index, zcu); |
| 7004 | | const offset = try cg.buildPointerOffset(result, field_offset, .new); |
| 7005 | 6952 | |
| 7006 | 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 | 6957 | break :result_value result; |
| ... | ... | @@ -7051,12 +6998,7 @@ fn airUnionInit(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7051 | 6998 | const result_ptr = try cg.allocStack(union_ty); |
| 7052 | 6999 | const payload = try cg.resolveInst(extra.init); |
| 7053 | 7000 | if (layout.tag_align.compare(.gte, layout.payload_align)) { |
| 7054 | | if (isByRef(field_ty, zcu, cg.target)) { |
| 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 | | } |
| 7001 | try cg.store(result_ptr, payload, field_ty, .{ .offset = layout.tag_size }); |
| 7060 | 7002 | |
| 7061 | 7003 | if (layout.tag_size > 0) { |
| 7062 | 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 | 7105 | .{ .offset = errUnionErrorOffset(payload_ty, zcu) }, |
| 7164 | 7106 | ); |
| 7165 | 7107 | |
| 7166 | | const result = result: { |
| 7167 | | if (!payload_ty.hasRuntimeBits(zcu)) { |
| 7168 | | break :result operand; |
| 7169 | | } |
| 7108 | if (!payload_ty.hasRuntimeBits(zcu)) { |
| 7109 | return cg.finishAir(inst, operand, &.{ty_op.operand}); |
| 7110 | } |
| 7170 | 7111 | |
| 7171 | | break :result try cg.buildPointerOffset(operand, @as(u32, @intCast(errUnionPayloadOffset(payload_ty, zcu))), .new); |
| 7172 | | }; |
| 7112 | const result = try cg.offsetPointer(operand, errUnionPayloadOffset(payload_ty, zcu)); |
| 7173 | 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 | 7134 | }, |
| 7195 | 7135 | }; |
| 7196 | 7136 | |
| 7197 | | const result = if (field_offset != 0) result: { |
| 7198 | | const base = try cg.buildPointerOffset(field_ptr, 0, .new); |
| 7199 | | try cg.addLocal(.local_get, base.local.value); |
| 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; |
| 7137 | if (field_offset == 0) { |
| 7138 | return cg.finishAir(inst, field_ptr, &.{extra.field_ptr}); |
| 7139 | } |
| 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 | 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 | 7269 | fn airPtrSliceFieldPtr(cg: *CodeGen, inst: Air.Inst.Index, offset: u32) InnerError!void { |
| 7323 | 7270 | const ty_op = cg.air.instructions.items(.data)[@backingInt(inst)].ty_op; |
| 7324 | 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 | 7273 | return cg.finishAir(inst, result, &.{ty_op.operand}); |
| 7327 | 7274 | } |
| 7328 | 7275 | |
| ... | ... | @@ -7392,13 +7339,15 @@ fn lowerTry( |
| 7392 | 7339 | try cg.startBlock(.block, .empty); |
| 7393 | 7340 | |
| 7394 | 7341 | // check if the error tag is set for the error union. |
| 7395 | | try cg.emitWValue(err_union); |
| 7396 | 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 | 7345 | try cg.addMemArg(.i32_load16_u, .{ |
| 7399 | | .offset = err_union.offset() + err_offset, |
| 7346 | .offset = err_union.memOffset() + err_offset, |
| 7400 | 7347 | .alignment = Type.anyerror.abiAlignment(zcu).toStdMem(), |
| 7401 | 7348 | }); |
| 7349 | } else { |
| 7350 | try cg.emitWValue(err_union); |
| 7402 | 7351 | } |
| 7403 | 7352 | try cg.addTag(.i32_eqz); |
| 7404 | 7353 | try cg.addLabel(.br_if, 0); // jump out of block when error is '0' |
| ... | ... | @@ -7417,9 +7366,9 @@ fn lowerTry( |
| 7417 | 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 | 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 | 7373 | const payload = try cg.load(err_union, pl_ty, .{ .offset = pl_offset }); |
| 7425 | 7374 | return payload.toLocal(cg, pl_ty); |
| ... | ... | @@ -7448,7 +7397,7 @@ fn callIntrinsic( |
| 7448 | 7397 | // and emit it as our first argument |
| 7449 | 7398 | const sret = if (want_sret_param) blk: { |
| 7450 | 7399 | const sret_local = try cg.allocStack(return_type); |
| 7451 | | try cg.lowerToStack(sret_local); |
| 7400 | try cg.emitWValue(sret_local); |
| 7452 | 7401 | break :blk sret_local; |
| 7453 | 7402 | } else .none; |
| 7454 | 7403 | |
| ... | ... | @@ -7476,7 +7425,7 @@ fn airTagName(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7476 | 7425 | const enum_ty = cg.typeOf(un_op); |
| 7477 | 7426 | |
| 7478 | 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 | 7429 | try cg.addInst(.{ .tag = .call_tag_index, .data = .{ .ip_index = enum_ty.toIntern() } }); |
| 7481 | 7430 | |
| 7482 | 7431 | switch (cg.ptr_size) { |
| ... | ... | @@ -7500,7 +7449,7 @@ fn airIsNamedEnumValue(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7500 | 7449 | const operand = try cg.resolveInst(un_op); |
| 7501 | 7450 | const enum_ty = cg.typeOf(un_op); |
| 7502 | 7451 | |
| 7503 | | try cg.lowerToStack(operand); |
| 7452 | try cg.emitWValue(operand); |
| 7504 | 7453 | try cg.addInst(.{ .tag = .call_tag_index, .data = .{ .ip_index = enum_ty.toIntern() } }); |
| 7505 | 7454 | try cg.addImm32(~@as(u32, 0)); |
| 7506 | 7455 | try cg.addTag(.i32_ne); |
| ... | ... | @@ -7614,9 +7563,9 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7614 | 7563 | |
| 7615 | 7564 | const ptr_val = if (cg.useAtomicFeature()) val: { |
| 7616 | 7565 | const val_local = try cg.allocLocal(ty); |
| 7617 | | try cg.emitWValue(ptr_operand); |
| 7618 | | try cg.lowerToStack(expected_val); |
| 7619 | | try cg.lowerToStack(new_val); |
| 7566 | try cg.emitMemBase(ptr_operand); |
| 7567 | try cg.emitWValue(expected_val); |
| 7568 | try cg.emitWValue(new_val); |
| 7620 | 7569 | try cg.addAtomicMemArg(switch (ty.abiSize(zcu)) { |
| 7621 | 7570 | 1 => .i32_atomic_rmw8_cmpxchg_u, |
| 7622 | 7571 | 2 => .i32_atomic_rmw16_cmpxchg_u, |
| ... | ... | @@ -7624,7 +7573,7 @@ fn airCmpxchg(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7624 | 7573 | 8 => .i32_atomic_rmw_cmpxchg, |
| 7625 | 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 | 7577 | .alignment = ty.abiAlignment(zcu).toStdMem(), |
| 7629 | 7578 | }); |
| 7630 | 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 | 7586 | } |
| 7638 | 7587 | const ptr_val = try WValue.toLocal(try cg.load(ptr_operand, ty, .{}), cg, ty); |
| 7639 | 7588 | |
| 7640 | | try cg.lowerToStack(ptr_operand); |
| 7641 | | try cg.lowerToStack(new_val); |
| 7589 | try cg.emitMemBase(ptr_operand); |
| 7590 | try cg.emitWValue(new_val); |
| 7642 | 7591 | try cg.emitWValue(ptr_val); |
| 7643 | 7592 | _ = try cg.intCmp(int_ty, .eq, ptr_val, expected_val); |
| 7644 | 7593 | try cg.addLocal(.local_tee, cmp_result.local.value); |
| 7645 | 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 | 7597 | break :val ptr_val; |
| 7649 | 7598 | }; |
| ... | ... | @@ -7684,9 +7633,9 @@ fn airAtomicLoad(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7684 | 7633 | 8 => .i64_atomic_load, |
| 7685 | 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 | 7637 | try cg.addAtomicMemArg(tag, .{ |
| 7689 | | .offset = ptr.offset(), |
| 7638 | .offset = ptr.memOffset(), |
| 7690 | 7639 | .alignment = ty.abiAlignment(zcu).toStdMem(), |
| 7691 | 7640 | }); |
| 7692 | 7641 | } else { |
| ... | ... | @@ -7719,7 +7668,7 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7719 | 7668 | // create a loop to cmpxchg the new value |
| 7720 | 7669 | try cg.startBlock(.loop, .empty); |
| 7721 | 7670 | |
| 7722 | | try cg.emitWValue(ptr); |
| 7671 | try cg.emitMemBase(ptr); |
| 7723 | 7672 | try cg.emitWValue(value); |
| 7724 | 7673 | if (op == .Nand) { |
| 7725 | 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 | 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 | 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 | 7713 | |
| 7765 | 7714 | // the other operations have their own instructions for Wasm. |
| 7766 | 7715 | else => { |
| 7767 | | try cg.emitWValue(ptr); |
| 7716 | try cg.emitMemBase(ptr); |
| 7768 | 7717 | try cg.emitWValue(operand); |
| 7769 | 7718 | const tag: std.wasm.AtomicsOpcode = switch (ty.abiSize(zcu)) { |
| 7770 | 7719 | 1 => switch (op) { |
| ... | ... | @@ -7806,7 +7755,7 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7806 | 7755 | else => |size| return cg.fail("TODO: Implement `@atomicRmw` for types with abi size {d}", .{size}), |
| 7807 | 7756 | }; |
| 7808 | 7757 | try cg.addAtomicMemArg(tag, .{ |
| 7809 | | .offset = ptr.offset(), |
| 7758 | .offset = ptr.memOffset(), |
| 7810 | 7759 | .alignment = ty.abiAlignment(zcu).toStdMem(), |
| 7811 | 7760 | }); |
| 7812 | 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 | 7774 | => { |
| 7826 | 7775 | if (ty.isAnyFloat()) { |
| 7827 | 7776 | const float_ty: FloatType = .fromType(cg, ty); |
| 7828 | | try cg.emitWValue(ptr); |
| 7777 | try cg.emitMemBase(ptr); |
| 7829 | 7778 | _ = switch (op) { |
| 7830 | 7779 | .Add => try cg.floatAdd(float_ty, result, operand), |
| 7831 | 7780 | .Sub => try cg.floatSub(float_ty, result, operand), |
| 7832 | 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 | 7784 | } else { |
| 7836 | 7785 | const int_ty: IntType = .fromType(cg, ty); |
| 7837 | | try cg.emitWValue(ptr); |
| 7786 | try cg.emitMemBase(ptr); |
| 7838 | 7787 | _ = switch (op) { |
| 7839 | 7788 | .Add => try cg.intAdd(int_ty, result, operand), |
| 7840 | 7789 | .Sub => try cg.intSub(int_ty, result, operand), |
| 7841 | 7790 | else => unreachable, |
| 7842 | 7791 | }; |
| 7843 | 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 | 7796 | .And, |
| ... | ... | @@ -7849,39 +7798,39 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7849 | 7798 | .Xor, |
| 7850 | 7799 | => { |
| 7851 | 7800 | const int_ty: IntType = .fromType(cg, ty); |
| 7852 | | try cg.emitWValue(ptr); |
| 7801 | try cg.emitMemBase(ptr); |
| 7853 | 7802 | _ = switch (op) { |
| 7854 | 7803 | .And => try cg.intAnd(int_ty, result, operand), |
| 7855 | 7804 | .Or => try cg.intOr(int_ty, result, operand), |
| 7856 | 7805 | .Xor => try cg.intXor(int_ty, result, operand), |
| 7857 | 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 | 7810 | .Max, |
| 7862 | 7811 | .Min, |
| 7863 | 7812 | => { |
| 7864 | 7813 | if (ty.isAnyFloat()) { |
| 7865 | 7814 | const float_ty: FloatType = .fromType(cg, ty); |
| 7866 | | try cg.emitWValue(ptr); |
| 7815 | try cg.emitMemBase(ptr); |
| 7867 | 7816 | try cg.emitWValue(result); |
| 7868 | 7817 | try cg.emitWValue(operand); |
| 7869 | 7818 | _ = try cg.floatCmp(float_ty, if (op == .Max) .gt else .lt, result, operand); |
| 7870 | 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 | 7821 | } else { |
| 7873 | 7822 | const int_ty: IntType = .fromType(cg, ty); |
| 7874 | | try cg.emitWValue(ptr); |
| 7823 | try cg.emitMemBase(ptr); |
| 7875 | 7824 | try cg.emitWValue(result); |
| 7876 | 7825 | try cg.emitWValue(operand); |
| 7877 | 7826 | _ = try cg.intCmp(int_ty, if (op == .Max) .gt else .lt, result, operand); |
| 7878 | 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 | 7831 | .Nand => { |
| 7883 | 7832 | const int_ty: IntType = .fromType(cg, ty); |
| 7884 | | try cg.emitWValue(ptr); |
| 7833 | try cg.emitMemBase(ptr); |
| 7885 | 7834 | const and_res = try cg.intAnd(int_ty, result, operand); |
| 7886 | 7835 | if (int_ty.bits <= 32) { |
| 7887 | 7836 | try cg.addImm32(~@as(u32, 0)); |
| ... | ... | @@ -7891,7 +7840,7 @@ fn airAtomicRmw(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7891 | 7840 | return cg.fail("TODO: `@atomicRmw` with operator `Nand` for types larger than 64 bits", .{}); |
| 7892 | 7841 | } |
| 7893 | 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 | 7865 | 8 => .i64_atomic_store, |
| 7917 | 7866 | else => |size| return cg.fail("TODO: @atomicLoad for types with abi size {d}", .{size}), |
| 7918 | 7867 | }; |
| 7919 | | try cg.emitWValue(ptr); |
| 7920 | | try cg.lowerToStack(operand); |
| 7868 | try cg.emitMemBase(ptr); |
| 7869 | try cg.emitWValue(operand); |
| 7921 | 7870 | try cg.addAtomicMemArg(tag, .{ |
| 7922 | | .offset = ptr.offset(), |
| 7871 | .offset = ptr.memOffset(), |
| 7923 | 7872 | .alignment = ty.abiAlignment(zcu).toStdMem(), |
| 7924 | 7873 | }); |
| 7925 | 7874 | } else { |
| ... | ... | @@ -7996,7 +7945,7 @@ fn airAsm(cg: *CodeGen, inst: Air.Inst.Index) InnerError!void { |
| 7996 | 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 | 7949 | const op_local = try WValue.toLocal(.stack, cg, cg.typeOf(input.operand)); |
| 8001 | 7950 | |
| 8002 | 7951 | const gop = try local_map.getOrPutValue(cg.gpa, name, op_local.local.value); |