| ... | @@ -5,6 +5,7 @@ const Signedness = std.lang.Signedness; | ... | @@ -5,6 +5,7 @@ const Signedness = std.lang.Signedness; |
| 5 | const assert = std.debug.assert; | 5 | const assert = std.debug.assert; |
| 6 | const log = std.log.scoped(.codegen); | 6 | const log = std.log.scoped(.codegen); |
| 7 | | 7 | |
| | 8 | const builtin = @import("builtin"); |
| 8 | const link = @import("../../link.zig"); | 9 | const link = @import("../../link.zig"); |
| 9 | const codegen = @import("../../codegen.zig"); | 10 | const codegen = @import("../../codegen.zig"); |
| 10 | const Zcu = @import("../../Zcu.zig"); | 11 | const Zcu = @import("../../Zcu.zig"); |
| ... | @@ -511,8 +512,8 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { | ... | @@ -511,8 +512,8 @@ pub fn genNav(cg: *CodeGen, do_codegen: bool) Error!void { |
| 511 | else => {}, | 512 | else => {}, |
| 512 | } | 513 | } |
| 513 | | 514 | |
| 514 | if (std.meta.stringToEnum(spec.BuiltIn, nav.fqn.toSlice(ip))) |builtin| { | 515 | if (std.meta.stringToEnum(spec.BuiltIn, nav.fqn.toSlice(ip))) |built_in| { |
| 515 | try cg.module.decorate(result_id, .{ .built_in = .{ .built_in = builtin } }); | 516 | try cg.module.decorate(result_id, .{ .built_in = .{ .built_in = built_in } }); |
| 516 | } | 517 | } |
| 517 | | 518 | |
| 518 | try cg.module.debugName(result_id, nav.fqn.toSlice(ip)); | 519 | try cg.module.debugName(result_id, nav.fqn.toSlice(ip)); |
| ... | @@ -956,6 +957,7 @@ fn constBool(cg: *CodeGen, value: bool, repr: Repr) !Id { | ... | @@ -956,6 +957,7 @@ fn constBool(cg: *CodeGen, value: bool, repr: Repr) !Id { |
| 956 | /// This function, unlike Module.constInt, takes care to bitcast | 957 | /// This function, unlike Module.constInt, takes care to bitcast |
| 957 | /// the value to an unsigned int first for Kernels. | 958 | /// the value to an unsigned int first for Kernels. |
| 958 | fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id { | 959 | fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id { |
| | 960 | const gpa = cg.module.gpa; |
| 959 | const zcu = cg.module.zcu; | 961 | const zcu = cg.module.zcu; |
| 960 | const target = cg.module.zcu.getTarget(); | 962 | const target = cg.module.zcu.getTarget(); |
| 961 | const scalar_ty = ty.scalarType(zcu); | 963 | const scalar_ty = ty.scalarType(zcu); |
| ... | @@ -975,11 +977,18 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id { | ... | @@ -975,11 +977,18 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id { |
| 975 | .signed => @bitCast(@as(i64, @intCast(value))), | 977 | .signed => @bitCast(@as(i64, @intCast(value))), |
| 976 | .unsigned => @as(u64, @intCast(value)), | 978 | .unsigned => @as(u64, @intCast(value)), |
| 977 | }; | 979 | }; |
| 978 | assert(backing_bits == 64); | 980 | const n_limbs = backing_bits / Module.big_int_bits; |
| 979 | return cg.constructComposite(result_ty_id, &.{ | 981 | const fill: u32 = if (signedness == .signed and value < 0) 0xFFFFFFFF else 0; |
| 980 | try cg.constInt(.u32, @as(u32, @truncate(value64))), | 982 | const scratch_top = cg.id_scratch.items.len; |
| 981 | try cg.constInt(.u32, @as(u32, @truncate(value64 << 32))), | 983 | defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); |
| 982 | }); | 984 | const constituents = try cg.id_scratch.addManyAsSlice(gpa, n_limbs); |
| | 985 | for (constituents, 0..) |*c, i| { |
| | 986 | c.* = try cg.constInt( |
| | 987 | .u32, |
| | 988 | if (i < 2) @as(u32, @truncate(value64 >> @intCast(i * 32))) else fill, |
| | 989 | ); |
| | 990 | } |
| | 991 | return cg.constructComposite(result_ty_id, constituents); |
| 983 | } | 992 | } |
| 984 | | 993 | |
| 985 | const final_value: spec.LiteralContextDependentNumber = switch (target.os.tag) { | 994 | const final_value: spec.LiteralContextDependentNumber = switch (target.os.tag) { |
| ... | @@ -1014,6 +1023,35 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id { | ... | @@ -1014,6 +1023,35 @@ fn constInt(cg: *CodeGen, ty: Type, value: anytype) !Id { |
| 1014 | return cg.constructCompositeSplat(ty, result_id); | 1023 | return cg.constructCompositeSplat(ty, result_id); |
| 1015 | } | 1024 | } |
| 1016 | | 1025 | |
| | 1026 | fn constIntBig(cg: *CodeGen, ty: Type, val: Value) !Id { |
| | 1027 | const gpa = cg.module.gpa; |
| | 1028 | const zcu = cg.module.zcu; |
| | 1029 | const int_info = ty.intInfo(zcu); |
| | 1030 | const backing_bits, _ = cg.module.backingIntBits(int_info.bits); |
| | 1031 | const n_limbs = backing_bits / Module.big_int_bits; |
| | 1032 | const result_ty_id = try cg.resolveType(ty, .indirect); |
| | 1033 | |
| | 1034 | var bigint_space: Value.BigIntSpace = undefined; |
| | 1035 | const bigint = val.toBigInt(&bigint_space, zcu); |
| | 1036 | |
| | 1037 | const limb_values = try gpa.alloc(u32, n_limbs); |
| | 1038 | defer gpa.free(limb_values); |
| | 1039 | |
| | 1040 | const bytes = std.mem.sliceAsBytes(limb_values); |
| | 1041 | bigint.writeTwosComplement(bytes, .little); |
| | 1042 | if (builtin.cpu.arch.endian() == .big) { |
| | 1043 | for (limb_values) |*limb| limb.* = @byteSwap(limb.*); |
| | 1044 | } |
| | 1045 | |
| | 1046 | const scratch_top = cg.id_scratch.items.len; |
| | 1047 | defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); |
| | 1048 | const constituents = try cg.id_scratch.addManyAsSlice(gpa, n_limbs); |
| | 1049 | for (constituents, 0..) |*c, i| { |
| | 1050 | c.* = try cg.constInt(.u32, limb_values[i]); |
| | 1051 | } |
| | 1052 | return cg.constructComposite(result_ty_id, constituents); |
| | 1053 | } |
| | 1054 | |
| 1017 | pub fn constructComposite(cg: *CodeGen, result_ty_id: Id, constituents: []const Id) !Id { | 1055 | pub fn constructComposite(cg: *CodeGen, result_ty_id: Id, constituents: []const Id) !Id { |
| 1018 | const gpa = cg.module.gpa; | 1056 | const gpa = cg.module.gpa; |
| 1019 | const result_id = cg.module.allocId(); | 1057 | const result_id = cg.module.allocId(); |
| ... | @@ -1106,6 +1144,11 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id { | ... | @@ -1106,6 +1144,11 @@ fn constant(cg: *CodeGen, ty: Type, val: Value, repr: Repr) Error!Id { |
| 1106 | .false, .true => break :cache try cg.constBool(val.toBool(), repr), | 1144 | .false, .true => break :cache try cg.constBool(val.toBool(), repr), |
| 1107 | }, | 1145 | }, |
| 1108 | .int => { | 1146 | .int => { |
| | 1147 | const int_info = ty.intInfo(zcu); |
| | 1148 | _, const is_big_int = cg.module.backingIntBits(int_info.bits); |
| | 1149 | if (is_big_int) { |
| | 1150 | break :cache try cg.constIntBig(ty, val); |
| | 1151 | } |
| 1109 | if (ty.isSignedInt(zcu)) { | 1152 | if (ty.isSignedInt(zcu)) { |
| 1110 | break :cache try cg.constInt(ty, val.toSignedInt(zcu)); | 1153 | break :cache try cg.constInt(ty, val.toSignedInt(zcu)); |
| 1111 | } else { | 1154 | } else { |
| ... | @@ -1385,15 +1428,32 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id { | ... | @@ -1385,15 +1428,32 @@ fn derivePtr(cg: *CodeGen, derivation: Value.PointerDeriveStep) !Id { |
| 1385 | } | 1428 | } |
| 1386 | | 1429 | |
| 1387 | if (oac.byte_offset == 0) { | 1430 | if (oac.byte_offset == 0) { |
| 1388 | // Allow changing the pointer type child only to restructure arrays. | 1431 | var depth: u32 = 0; |
| 1389 | // e.g. [3][2]T to T is fine, as is [2]T -> [2][1]T. | 1432 | var cur = parent_ptr_ty.childType(zcu); |
| 1390 | const result_ptr_id = cg.module.allocId(); | 1433 | const dst_child = oac.new_ptr_ty.childType(zcu); |
| 1391 | try cg.body.emit(gpa, .OpBitcast, .{ | 1434 | while (cur.toIntern() != dst_child.toIntern()) { |
| 1392 | .id_result_type = result_ty_id, | 1435 | if (cur.zigTypeTag(zcu) == .array) { |
| 1393 | .id_result = result_ptr_id, | 1436 | cur = cur.childType(zcu); |
| 1394 | .operand = parent_ptr_id, | 1437 | depth += 1; |
| 1395 | }); | 1438 | } else break; |
| 1396 | return result_ptr_id; | 1439 | } |
| | 1440 | if (depth > 0 and cur.toIntern() == dst_child.toIntern()) { |
| | 1441 | const scratch_top = cg.id_scratch.items.len; |
| | 1442 | defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); |
| | 1443 | const zero = try cg.constInt(.u32, 0); |
| | 1444 | const ids = try cg.id_scratch.addManyAsSlice(gpa, depth); |
| | 1445 | @memset(ids, zero); |
| | 1446 | return cg.accessChainId(result_ty_id, parent_ptr_id, ids); |
| | 1447 | } |
| | 1448 | if (target.os.tag == .opencl) { |
| | 1449 | const result_ptr_id = cg.module.allocId(); |
| | 1450 | try cg.body.emit(gpa, .OpBitcast, .{ |
| | 1451 | .id_result_type = result_ty_id, |
| | 1452 | .id_result = result_ptr_id, |
| | 1453 | .operand = parent_ptr_id, |
| | 1454 | }); |
| | 1455 | return result_ptr_id; |
| | 1456 | } |
| 1397 | } | 1457 | } |
| 1398 | | 1458 | |
| 1399 | return cg.fail("cannot perform pointer cast: '{f}' to '{f}'", .{ | 1459 | return cg.fail("cannot perform pointer cast: '{f}' to '{f}'", .{ |
| ... | @@ -1684,10 +1744,6 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { | ... | @@ -1684,10 +1744,6 @@ fn resolveType(cg: *CodeGen, ty: Type, repr: Repr) Error!Id { |
| 1684 | return try cg.module.opaqueType("u0"); | 1744 | return try cg.module.opaqueType("u0"); |
| 1685 | } | 1745 | } |
| 1686 | const int_info = ty.intInfo(zcu); | 1746 | const int_info = ty.intInfo(zcu); |
| 1687 | const backing_bits, const big_int = cg.module.backingIntBits(int_info.bits); | | |
| 1688 | if (big_int and backing_bits > 64) { | | |
| 1689 | return cg.fail("integer width of {} bits is not yet supported on the SPIR-V backend", .{int_info.bits}); | | |
| 1690 | } | | |
| 1691 | return try cg.module.intType(int_info.signedness, int_info.bits); | 1747 | return try cg.module.intType(int_info.signedness, int_info.bits); |
| 1692 | }, | 1748 | }, |
| 1693 | .@"enum" => return try cg.resolveType(ty.intTagType(zcu), repr), | 1749 | .@"enum" => return try cg.resolveType(ty.intTagType(zcu), repr), |
| ... | @@ -2216,6 +2272,697 @@ const Temporary = struct { | ... | @@ -2216,6 +2272,697 @@ const Temporary = struct { |
| 2216 | } | 2272 | } |
| 2217 | }; | 2273 | }; |
| 2218 | | 2274 | |
| | 2275 | /// composite integers are represented as [N]u32 arrays |
| | 2276 | const CompositeInt = struct { |
| | 2277 | cg: *CodeGen, |
| | 2278 | limbs: []Id, |
| | 2279 | n_limbs: u16, |
| | 2280 | info: ArithmeticTypeInfo, |
| | 2281 | |
| | 2282 | fn init(cg: *CodeGen, composite_id: Id, info: ArithmeticTypeInfo) !CompositeInt { |
| | 2283 | const n_limbs: u16 = info.backing_bits / Module.big_int_bits; |
| | 2284 | const gpa = cg.module.gpa; |
| | 2285 | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| | 2286 | const limbs = try cg.id_scratch.addManyAsSlice(gpa, n_limbs); |
| | 2287 | for (limbs, 0..) |*limb, i| { |
| | 2288 | const result_id = cg.module.allocId(); |
| | 2289 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| | 2290 | .id_result_type = u32_ty_id, |
| | 2291 | .id_result = result_id, |
| | 2292 | .composite = composite_id, |
| | 2293 | .indexes = &.{@as(u32, @intCast(i))}, |
| | 2294 | }); |
| | 2295 | limb.* = result_id; |
| | 2296 | } |
| | 2297 | return .{ .cg = cg, .limbs = limbs, .n_limbs = n_limbs, .info = info }; |
| | 2298 | } |
| | 2299 | |
| | 2300 | fn fromLimbs(cg: *CodeGen, limbs: []Id, info: ArithmeticTypeInfo) CompositeInt { |
| | 2301 | return .{ |
| | 2302 | .cg = cg, |
| | 2303 | .limbs = limbs, |
| | 2304 | .n_limbs = @intCast(limbs.len), |
| | 2305 | .info = info, |
| | 2306 | }; |
| | 2307 | } |
| | 2308 | |
| | 2309 | fn zero(cg: *CodeGen, info: ArithmeticTypeInfo) !CompositeInt { |
| | 2310 | const n_limbs: u16 = info.backing_bits / Module.big_int_bits; |
| | 2311 | const limbs = try cg.id_scratch.addManyAsSlice(cg.module.gpa, n_limbs); |
| | 2312 | const zero_id = try cg.constInt(.u32, @as(u32, 0)); |
| | 2313 | for (limbs) |*limb| limb.* = zero_id; |
| | 2314 | return .{ .cg = cg, .limbs = limbs, .n_limbs = n_limbs, .info = info }; |
| | 2315 | } |
| | 2316 | |
| | 2317 | fn materialize(ci: CompositeInt, ty: Type) !Id { |
| | 2318 | const result_ty_id = try ci.cg.resolveType(ty, .indirect); |
| | 2319 | return ci.cg.constructComposite(result_ty_id, ci.limbs); |
| | 2320 | } |
| | 2321 | |
| | 2322 | fn limbBinOp(ci: CompositeInt, opcode: Opcode, lhs: Id, rhs: Id) !Id { |
| | 2323 | const cg = ci.cg; |
| | 2324 | const gpa = cg.module.gpa; |
| | 2325 | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| | 2326 | const result_id = cg.module.allocId(); |
| | 2327 | try cg.body.emitRaw(gpa, opcode, 4); |
| | 2328 | cg.body.writeOperand(Id, u32_ty_id); |
| | 2329 | cg.body.writeOperand(Id, result_id); |
| | 2330 | cg.body.writeOperand(Id, lhs); |
| | 2331 | cg.body.writeOperand(Id, rhs); |
| | 2332 | return result_id; |
| | 2333 | } |
| | 2334 | |
| | 2335 | fn limbUnOp(ci: CompositeInt, opcode: Opcode, operand: Id) !Id { |
| | 2336 | const cg = ci.cg; |
| | 2337 | const gpa = cg.module.gpa; |
| | 2338 | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| | 2339 | const result_id = cg.module.allocId(); |
| | 2340 | try cg.body.emitRaw(gpa, opcode, 3); |
| | 2341 | cg.body.writeOperand(Id, u32_ty_id); |
| | 2342 | cg.body.writeOperand(Id, result_id); |
| | 2343 | cg.body.writeOperand(Id, operand); |
| | 2344 | return result_id; |
| | 2345 | } |
| | 2346 | |
| | 2347 | fn bitwiseOp(ci: CompositeInt, other: CompositeInt, opcode: Opcode) !CompositeInt { |
| | 2348 | const cg = ci.cg; |
| | 2349 | const gpa = cg.module.gpa; |
| | 2350 | const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs); |
| | 2351 | for (result_limbs, 0..) |*r, i| { |
| | 2352 | r.* = try ci.limbBinOp(opcode, ci.limbs[i], other.limbs[i]); |
| | 2353 | } |
| | 2354 | return .fromLimbs(cg, result_limbs, ci.info); |
| | 2355 | } |
| | 2356 | |
| | 2357 | fn bitwiseNot(ci: CompositeInt) !CompositeInt { |
| | 2358 | const cg = ci.cg; |
| | 2359 | const gpa = cg.module.gpa; |
| | 2360 | const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs); |
| | 2361 | for (result_limbs, 0..) |*r, i| { |
| | 2362 | r.* = try ci.limbUnOp(.OpNot, ci.limbs[i]); |
| | 2363 | } |
| | 2364 | return .fromLimbs(cg, result_limbs, ci.info); |
| | 2365 | } |
| | 2366 | |
| | 2367 | fn cmp(ci: CompositeInt, other: CompositeInt, op: std.math.CompareOperator) !Id { |
| | 2368 | const cg = ci.cg; |
| | 2369 | const gpa = cg.module.gpa; |
| | 2370 | const bool_ty_id = try cg.resolveType(.bool, .direct); |
| | 2371 | |
| | 2372 | switch (op) { |
| | 2373 | .eq, .neq => { |
| | 2374 | var result = blk: { |
| | 2375 | const r = cg.module.allocId(); |
| | 2376 | try cg.body.emitRaw(gpa, .OpIEqual, 4); |
| | 2377 | cg.body.writeOperand(Id, bool_ty_id); |
| | 2378 | cg.body.writeOperand(Id, r); |
| | 2379 | cg.body.writeOperand(Id, ci.limbs[0]); |
| | 2380 | cg.body.writeOperand(Id, other.limbs[0]); |
| | 2381 | break :blk r; |
| | 2382 | }; |
| | 2383 | for (1..ci.n_limbs) |i| { |
| | 2384 | const limb_eq = cg.module.allocId(); |
| | 2385 | try cg.body.emitRaw(gpa, .OpIEqual, 4); |
| | 2386 | cg.body.writeOperand(Id, bool_ty_id); |
| | 2387 | cg.body.writeOperand(Id, limb_eq); |
| | 2388 | cg.body.writeOperand(Id, ci.limbs[i]); |
| | 2389 | cg.body.writeOperand(Id, other.limbs[i]); |
| | 2390 | const combined = cg.module.allocId(); |
| | 2391 | try cg.body.emitRaw(gpa, .OpLogicalAnd, 4); |
| | 2392 | cg.body.writeOperand(Id, bool_ty_id); |
| | 2393 | cg.body.writeOperand(Id, combined); |
| | 2394 | cg.body.writeOperand(Id, result); |
| | 2395 | cg.body.writeOperand(Id, limb_eq); |
| | 2396 | result = combined; |
| | 2397 | } |
| | 2398 | if (op == .neq) { |
| | 2399 | const negated = cg.module.allocId(); |
| | 2400 | try cg.body.emitRaw(gpa, .OpLogicalNot, 3); |
| | 2401 | cg.body.writeOperand(Id, bool_ty_id); |
| | 2402 | cg.body.writeOperand(Id, negated); |
| | 2403 | cg.body.writeOperand(Id, result); |
| | 2404 | result = negated; |
| | 2405 | } |
| | 2406 | return result; |
| | 2407 | }, |
| | 2408 | .lt, .lte, .gt, .gte => { |
| | 2409 | const is_lt = (op == .lt or op == .lte); |
| | 2410 | const is_strict = (op == .lt or op == .gt); |
| | 2411 | var result = try cg.constBool(!is_strict, .direct); |
| | 2412 | |
| | 2413 | for (0..ci.n_limbs) |i| { |
| | 2414 | const l = ci.limbs[i]; |
| | 2415 | const r = other.limbs[i]; |
| | 2416 | const limb_ne = cg.module.allocId(); |
| | 2417 | try cg.body.emitRaw(gpa, .OpINotEqual, 4); |
| | 2418 | cg.body.writeOperand(Id, bool_ty_id); |
| | 2419 | cg.body.writeOperand(Id, limb_ne); |
| | 2420 | cg.body.writeOperand(Id, l); |
| | 2421 | cg.body.writeOperand(Id, r); |
| | 2422 | |
| | 2423 | const is_top = (i == ci.n_limbs - 1); |
| | 2424 | const use_signed = is_top and ci.info.signedness == .signed; |
| | 2425 | var cmp_l = l; |
| | 2426 | var cmp_r = r; |
| | 2427 | if (use_signed) { |
| | 2428 | const i32_ty_id = try cg.resolveType(.i32, .direct); |
| | 2429 | const sl = cg.module.allocId(); |
| | 2430 | try cg.body.emit(gpa, .OpBitcast, .{ |
| | 2431 | .id_result_type = i32_ty_id, |
| | 2432 | .id_result = sl, |
| | 2433 | .operand = l, |
| | 2434 | }); |
| | 2435 | const sr = cg.module.allocId(); |
| | 2436 | try cg.body.emit(gpa, .OpBitcast, .{ |
| | 2437 | .id_result_type = i32_ty_id, |
| | 2438 | .id_result = sr, |
| | 2439 | .operand = r, |
| | 2440 | }); |
| | 2441 | cmp_l = sl; |
| | 2442 | cmp_r = sr; |
| | 2443 | } |
| | 2444 | |
| | 2445 | const cmp_opcode: Opcode = if (is_lt) |
| | 2446 | (if (use_signed) .OpSLessThan else .OpULessThan) |
| | 2447 | else |
| | 2448 | (if (use_signed) .OpSGreaterThan else .OpUGreaterThan); |
| | 2449 | |
| | 2450 | const limb_cmp = cg.module.allocId(); |
| | 2451 | try cg.body.emitRaw(gpa, cmp_opcode, 4); |
| | 2452 | cg.body.writeOperand(Id, bool_ty_id); |
| | 2453 | cg.body.writeOperand(Id, limb_cmp); |
| | 2454 | cg.body.writeOperand(Id, cmp_l); |
| | 2455 | cg.body.writeOperand(Id, cmp_r); |
| | 2456 | |
| | 2457 | const selected = cg.module.allocId(); |
| | 2458 | try cg.body.emit(gpa, .OpSelect, .{ |
| | 2459 | .id_result_type = bool_ty_id, |
| | 2460 | .id_result = selected, |
| | 2461 | .condition = limb_ne, |
| | 2462 | .object_1 = limb_cmp, |
| | 2463 | .object_2 = result, |
| | 2464 | }); |
| | 2465 | result = selected; |
| | 2466 | } |
| | 2467 | return result; |
| | 2468 | }, |
| | 2469 | } |
| | 2470 | } |
| | 2471 | |
| | 2472 | fn addSub(ci: CompositeInt, other: CompositeInt, comptime is_add: bool) !CompositeInt { |
| | 2473 | const cg = ci.cg; |
| | 2474 | const gpa = cg.module.gpa; |
| | 2475 | const pt = cg.pt; |
| | 2476 | const zcu = cg.module.zcu; |
| | 2477 | const ip = &zcu.intern_pool; |
| | 2478 | const comp = zcu.comp; |
| | 2479 | const io = comp.io; |
| | 2480 | |
| | 2481 | const u32_zig = try pt.intType(.unsigned, 32); |
| | 2482 | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| | 2483 | const carry_struct_ty: Type = .fromInterned(try ip.getTupleType(gpa, io, pt.tid, .{ |
| | 2484 | .types = &.{ u32_zig.toIntern(), u32_zig.toIntern() }, |
| | 2485 | .values = &.{ .none, .none }, |
| | 2486 | })); |
| | 2487 | const carry_struct_ty_id = try cg.resolveType(carry_struct_ty, .direct); |
| | 2488 | |
| | 2489 | const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs); |
| | 2490 | var carry_id = try cg.constInt(.u32, @as(u32, 0)); |
| | 2491 | |
| | 2492 | const opcode: Opcode = if (is_add) .OpIAddCarry else .OpISubBorrow; |
| | 2493 | |
| | 2494 | for (0..ci.n_limbs) |i| { |
| | 2495 | const op1 = cg.module.allocId(); |
| | 2496 | try cg.body.emitRaw(gpa, opcode, 4); |
| | 2497 | cg.body.writeOperand(Id, carry_struct_ty_id); |
| | 2498 | cg.body.writeOperand(Id, op1); |
| | 2499 | cg.body.writeOperand(Id, ci.limbs[i]); |
| | 2500 | cg.body.writeOperand(Id, other.limbs[i]); |
| | 2501 | |
| | 2502 | const sum1 = cg.module.allocId(); |
| | 2503 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| | 2504 | .id_result_type = u32_ty_id, |
| | 2505 | .id_result = sum1, |
| | 2506 | .composite = op1, |
| | 2507 | .indexes = &.{0}, |
| | 2508 | }); |
| | 2509 | const carry1 = cg.module.allocId(); |
| | 2510 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| | 2511 | .id_result_type = u32_ty_id, |
| | 2512 | .id_result = carry1, |
| | 2513 | .composite = op1, |
| | 2514 | .indexes = &.{1}, |
| | 2515 | }); |
| | 2516 | |
| | 2517 | const op2 = cg.module.allocId(); |
| | 2518 | try cg.body.emitRaw(gpa, opcode, 4); |
| | 2519 | cg.body.writeOperand(Id, carry_struct_ty_id); |
| | 2520 | cg.body.writeOperand(Id, op2); |
| | 2521 | cg.body.writeOperand(Id, sum1); |
| | 2522 | cg.body.writeOperand(Id, carry_id); |
| | 2523 | |
| | 2524 | result_limbs[i] = cg.module.allocId(); |
| | 2525 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| | 2526 | .id_result_type = u32_ty_id, |
| | 2527 | .id_result = result_limbs[i], |
| | 2528 | .composite = op2, |
| | 2529 | .indexes = &.{0}, |
| | 2530 | }); |
| | 2531 | const carry2 = cg.module.allocId(); |
| | 2532 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| | 2533 | .id_result_type = u32_ty_id, |
| | 2534 | .id_result = carry2, |
| | 2535 | .composite = op2, |
| | 2536 | .indexes = &.{1}, |
| | 2537 | }); |
| | 2538 | |
| | 2539 | carry_id = try ci.limbBinOp(.OpBitwiseOr, carry1, carry2); |
| | 2540 | } |
| | 2541 | |
| | 2542 | return .fromLimbs(cg, result_limbs, ci.info); |
| | 2543 | } |
| | 2544 | |
| | 2545 | fn shl(ci: CompositeInt, shift_amt_id: Id) !CompositeInt { |
| | 2546 | const cg = ci.cg; |
| | 2547 | const gpa = cg.module.gpa; |
| | 2548 | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| | 2549 | const bool_ty_id = try cg.resolveType(.bool, .direct); |
| | 2550 | const zero_id = try cg.constInt(.u32, @as(u32, 0)); |
| | 2551 | const five_id = try cg.constInt(.u32, @as(u32, 5)); |
| | 2552 | const thirty_one_id = try cg.constInt(.u32, @as(u32, 31)); |
| | 2553 | const thirty_two_id = try cg.constInt(.u32, @as(u32, 32)); |
| | 2554 | |
| | 2555 | const whole = try ci.limbBinOp(.OpShiftRightLogical, shift_amt_id, five_id); |
| | 2556 | const frac = try ci.limbBinOp(.OpBitwiseAnd, shift_amt_id, thirty_one_id); |
| | 2557 | const comp_frac = try ci.limbBinOp(.OpISub, thirty_two_id, frac); |
| | 2558 | const frac_is_zero = blk: { |
| | 2559 | const r = cg.module.allocId(); |
| | 2560 | try cg.body.emitRaw(gpa, .OpIEqual, 4); |
| | 2561 | cg.body.writeOperand(Id, bool_ty_id); |
| | 2562 | cg.body.writeOperand(Id, r); |
| | 2563 | cg.body.writeOperand(Id, frac); |
| | 2564 | cg.body.writeOperand(Id, zero_id); |
| | 2565 | break :blk r; |
| | 2566 | }; |
| | 2567 | |
| | 2568 | const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs); |
| | 2569 | |
| | 2570 | for (0..ci.n_limbs) |i| { |
| | 2571 | const i_id = try cg.constInt(.u32, @as(u32, @intCast(i))); |
| | 2572 | var main_val = zero_id; |
| | 2573 | var carry_val = zero_id; |
| | 2574 | |
| | 2575 | for (0..ci.n_limbs) |j| { |
| | 2576 | const j_id = try cg.constInt(.u32, @as(u32, @intCast(j))); |
| | 2577 | const j_plus_whole = try ci.limbBinOp(.OpIAdd, j_id, whole); |
| | 2578 | |
| | 2579 | const is_main = blk: { |
| | 2580 | const r = cg.module.allocId(); |
| | 2581 | try cg.body.emitRaw(gpa, .OpIEqual, 4); |
| | 2582 | cg.body.writeOperand(Id, bool_ty_id); |
| | 2583 | cg.body.writeOperand(Id, r); |
| | 2584 | cg.body.writeOperand(Id, j_plus_whole); |
| | 2585 | cg.body.writeOperand(Id, i_id); |
| | 2586 | break :blk r; |
| | 2587 | }; |
| | 2588 | const shifted = try ci.limbBinOp(.OpShiftLeftLogical, ci.limbs[j], frac); |
| | 2589 | main_val = blk: { |
| | 2590 | const r = cg.module.allocId(); |
| | 2591 | try cg.body.emit(gpa, .OpSelect, .{ |
| | 2592 | .id_result_type = u32_ty_id, |
| | 2593 | .id_result = r, |
| | 2594 | .condition = is_main, |
| | 2595 | .object_1 = shifted, |
| | 2596 | .object_2 = main_val, |
| | 2597 | }); |
| | 2598 | break :blk r; |
| | 2599 | }; |
| | 2600 | |
| | 2601 | const one_id = try cg.constInt(.u32, @as(u32, 1)); |
| | 2602 | const j_plus_whole_plus_1 = try ci.limbBinOp(.OpIAdd, j_plus_whole, one_id); |
| | 2603 | const is_carry = blk: { |
| | 2604 | const r = cg.module.allocId(); |
| | 2605 | try cg.body.emitRaw(gpa, .OpIEqual, 4); |
| | 2606 | cg.body.writeOperand(Id, bool_ty_id); |
| | 2607 | cg.body.writeOperand(Id, r); |
| | 2608 | cg.body.writeOperand(Id, j_plus_whole_plus_1); |
| | 2609 | cg.body.writeOperand(Id, i_id); |
| | 2610 | break :blk r; |
| | 2611 | }; |
| | 2612 | const carry_shifted = try ci.limbBinOp(.OpShiftRightLogical, ci.limbs[j], comp_frac); |
| | 2613 | const guarded_carry = blk: { |
| | 2614 | const r = cg.module.allocId(); |
| | 2615 | try cg.body.emit(gpa, .OpSelect, .{ |
| | 2616 | .id_result_type = u32_ty_id, |
| | 2617 | .id_result = r, |
| | 2618 | .condition = frac_is_zero, |
| | 2619 | .object_1 = zero_id, |
| | 2620 | .object_2 = carry_shifted, |
| | 2621 | }); |
| | 2622 | break :blk r; |
| | 2623 | }; |
| | 2624 | carry_val = blk: { |
| | 2625 | const r = cg.module.allocId(); |
| | 2626 | try cg.body.emit(gpa, .OpSelect, .{ |
| | 2627 | .id_result_type = u32_ty_id, |
| | 2628 | .id_result = r, |
| | 2629 | .condition = is_carry, |
| | 2630 | .object_1 = guarded_carry, |
| | 2631 | .object_2 = carry_val, |
| | 2632 | }); |
| | 2633 | break :blk r; |
| | 2634 | }; |
| | 2635 | } |
| | 2636 | |
| | 2637 | result_limbs[i] = try ci.limbBinOp(.OpBitwiseOr, main_val, carry_val); |
| | 2638 | } |
| | 2639 | |
| | 2640 | return .fromLimbs(cg, result_limbs, ci.info); |
| | 2641 | } |
| | 2642 | |
| | 2643 | fn shr(ci: CompositeInt, shift_amt_id: Id, comptime is_arithmetic: bool) !CompositeInt { |
| | 2644 | const cg = ci.cg; |
| | 2645 | const gpa = cg.module.gpa; |
| | 2646 | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| | 2647 | const bool_ty_id = try cg.resolveType(.bool, .direct); |
| | 2648 | const zero_id = try cg.constInt(.u32, @as(u32, 0)); |
| | 2649 | const five_id = try cg.constInt(.u32, @as(u32, 5)); |
| | 2650 | const thirty_one_id = try cg.constInt(.u32, @as(u32, 31)); |
| | 2651 | const thirty_two_id = try cg.constInt(.u32, @as(u32, 32)); |
| | 2652 | |
| | 2653 | const whole = try ci.limbBinOp(.OpShiftRightLogical, shift_amt_id, five_id); |
| | 2654 | const frac = try ci.limbBinOp(.OpBitwiseAnd, shift_amt_id, thirty_one_id); |
| | 2655 | const comp_frac = try ci.limbBinOp(.OpISub, thirty_two_id, frac); |
| | 2656 | const frac_is_zero = blk: { |
| | 2657 | const r = cg.module.allocId(); |
| | 2658 | try cg.body.emitRaw(gpa, .OpIEqual, 4); |
| | 2659 | cg.body.writeOperand(Id, bool_ty_id); |
| | 2660 | cg.body.writeOperand(Id, r); |
| | 2661 | cg.body.writeOperand(Id, frac); |
| | 2662 | cg.body.writeOperand(Id, zero_id); |
| | 2663 | break :blk r; |
| | 2664 | }; |
| | 2665 | |
| | 2666 | const fill_id = if (is_arithmetic) blk: { |
| | 2667 | const i32_ty_id = try cg.resolveType(.i32, .direct); |
| | 2668 | const msb_signed = cg.module.allocId(); |
| | 2669 | try cg.body.emit(gpa, .OpBitcast, .{ |
| | 2670 | .id_result_type = i32_ty_id, |
| | 2671 | .id_result = msb_signed, |
| | 2672 | .operand = ci.limbs[ci.n_limbs - 1], |
| | 2673 | }); |
| | 2674 | const shift31 = try cg.constInt(.i32, @as(i32, 31)); |
| | 2675 | const sign_ext = cg.module.allocId(); |
| | 2676 | try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4); |
| | 2677 | cg.body.writeOperand(Id, i32_ty_id); |
| | 2678 | cg.body.writeOperand(Id, sign_ext); |
| | 2679 | cg.body.writeOperand(Id, msb_signed); |
| | 2680 | cg.body.writeOperand(Id, shift31); |
| | 2681 | const back = cg.module.allocId(); |
| | 2682 | try cg.body.emit(gpa, .OpBitcast, .{ |
| | 2683 | .id_result_type = u32_ty_id, |
| | 2684 | .id_result = back, |
| | 2685 | .operand = sign_ext, |
| | 2686 | }); |
| | 2687 | break :blk back; |
| | 2688 | } else zero_id; |
| | 2689 | |
| | 2690 | const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs); |
| | 2691 | |
| | 2692 | const arith_carry_init = if (is_arithmetic) blk: { |
| | 2693 | const shifted_fill = try ci.limbBinOp(.OpShiftLeftLogical, fill_id, comp_frac); |
| | 2694 | const guarded = cg.module.allocId(); |
| | 2695 | try cg.body.emit(gpa, .OpSelect, .{ |
| | 2696 | .id_result_type = u32_ty_id, |
| | 2697 | .id_result = guarded, |
| | 2698 | .condition = frac_is_zero, |
| | 2699 | .object_1 = zero_id, |
| | 2700 | .object_2 = shifted_fill, |
| | 2701 | }); |
| | 2702 | break :blk guarded; |
| | 2703 | } else zero_id; |
| | 2704 | |
| | 2705 | for (0..ci.n_limbs) |i| { |
| | 2706 | const i_id = try cg.constInt(.u32, @as(u32, @intCast(i))); |
| | 2707 | var main_val = fill_id; |
| | 2708 | var carry_val = arith_carry_init; |
| | 2709 | |
| | 2710 | for (0..ci.n_limbs) |j| { |
| | 2711 | const j_id = try cg.constInt(.u32, @as(u32, @intCast(j))); |
| | 2712 | const i_plus_whole = try ci.limbBinOp(.OpIAdd, i_id, whole); |
| | 2713 | const is_main = blk: { |
| | 2714 | const r = cg.module.allocId(); |
| | 2715 | try cg.body.emitRaw(gpa, .OpIEqual, 4); |
| | 2716 | cg.body.writeOperand(Id, bool_ty_id); |
| | 2717 | cg.body.writeOperand(Id, r); |
| | 2718 | cg.body.writeOperand(Id, j_id); |
| | 2719 | cg.body.writeOperand(Id, i_plus_whole); |
| | 2720 | break :blk r; |
| | 2721 | }; |
| | 2722 | const shifted = try ci.limbBinOp(.OpShiftRightLogical, ci.limbs[j], frac); |
| | 2723 | main_val = blk: { |
| | 2724 | const r = cg.module.allocId(); |
| | 2725 | try cg.body.emit(gpa, .OpSelect, .{ |
| | 2726 | .id_result_type = u32_ty_id, |
| | 2727 | .id_result = r, |
| | 2728 | .condition = is_main, |
| | 2729 | .object_1 = shifted, |
| | 2730 | .object_2 = main_val, |
| | 2731 | }); |
| | 2732 | break :blk r; |
| | 2733 | }; |
| | 2734 | |
| | 2735 | const one_id = try cg.constInt(.u32, @as(u32, 1)); |
| | 2736 | const i_plus_whole_plus_1 = try ci.limbBinOp(.OpIAdd, i_plus_whole, one_id); |
| | 2737 | const is_carry = blk: { |
| | 2738 | const r = cg.module.allocId(); |
| | 2739 | try cg.body.emitRaw(gpa, .OpIEqual, 4); |
| | 2740 | cg.body.writeOperand(Id, bool_ty_id); |
| | 2741 | cg.body.writeOperand(Id, r); |
| | 2742 | cg.body.writeOperand(Id, j_id); |
| | 2743 | cg.body.writeOperand(Id, i_plus_whole_plus_1); |
| | 2744 | break :blk r; |
| | 2745 | }; |
| | 2746 | const carry_shifted = try ci.limbBinOp(.OpShiftLeftLogical, ci.limbs[j], comp_frac); |
| | 2747 | const guarded_carry = blk: { |
| | 2748 | const r = cg.module.allocId(); |
| | 2749 | try cg.body.emit(gpa, .OpSelect, .{ |
| | 2750 | .id_result_type = u32_ty_id, |
| | 2751 | .id_result = r, |
| | 2752 | .condition = frac_is_zero, |
| | 2753 | .object_1 = zero_id, |
| | 2754 | .object_2 = carry_shifted, |
| | 2755 | }); |
| | 2756 | break :blk r; |
| | 2757 | }; |
| | 2758 | carry_val = blk: { |
| | 2759 | const r = cg.module.allocId(); |
| | 2760 | try cg.body.emit(gpa, .OpSelect, .{ |
| | 2761 | .id_result_type = u32_ty_id, |
| | 2762 | .id_result = r, |
| | 2763 | .condition = is_carry, |
| | 2764 | .object_1 = guarded_carry, |
| | 2765 | .object_2 = carry_val, |
| | 2766 | }); |
| | 2767 | break :blk r; |
| | 2768 | }; |
| | 2769 | } |
| | 2770 | |
| | 2771 | result_limbs[i] = try ci.limbBinOp(.OpBitwiseOr, main_val, carry_val); |
| | 2772 | } |
| | 2773 | |
| | 2774 | return .fromLimbs(cg, result_limbs, ci.info); |
| | 2775 | } |
| | 2776 | |
| | 2777 | fn mul(ci: CompositeInt, other: CompositeInt, comptime wide: bool) ![]Id { |
| | 2778 | const cg = ci.cg; |
| | 2779 | const gpa = cg.module.gpa; |
| | 2780 | const pt = cg.pt; |
| | 2781 | const zcu = cg.module.zcu; |
| | 2782 | const ip = &zcu.intern_pool; |
| | 2783 | const comp = zcu.comp; |
| | 2784 | const io = comp.io; |
| | 2785 | const target = zcu.getTarget(); |
| | 2786 | |
| | 2787 | const n: usize = ci.n_limbs; |
| | 2788 | const total: usize = if (wide) 2 * n else n; |
| | 2789 | const u32_zig = try pt.intType(.unsigned, 32); |
| | 2790 | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| | 2791 | |
| | 2792 | const pair_struct_ty: Type = .fromInterned(try ip.getTupleType(gpa, io, pt.tid, .{ |
| | 2793 | .types = &.{ u32_zig.toIntern(), u32_zig.toIntern() }, |
| | 2794 | .values = &.{ .none, .none }, |
| | 2795 | })); |
| | 2796 | const pair_struct_ty_id = try cg.resolveType(pair_struct_ty, .direct); |
| | 2797 | |
| | 2798 | const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, total); |
| | 2799 | const zero_id = try cg.constInt(.u32, @as(u32, 0)); |
| | 2800 | for (result_limbs) |*r| r.* = zero_id; |
| | 2801 | |
| | 2802 | for (0..n) |i| { |
| | 2803 | var carry_id = zero_id; |
| | 2804 | for (0..n) |j| { |
| | 2805 | const k = i + j; |
| | 2806 | if (k >= total) break; |
| | 2807 | |
| | 2808 | var lo: Id = undefined; |
| | 2809 | var hi: Id = undefined; |
| | 2810 | switch (target.os.tag) { |
| | 2811 | .opencl => { |
| | 2812 | lo = cg.module.allocId(); |
| | 2813 | try cg.body.emitRaw(gpa, .OpIMul, 4); |
| | 2814 | cg.body.writeOperand(Id, u32_ty_id); |
| | 2815 | cg.body.writeOperand(Id, lo); |
| | 2816 | cg.body.writeOperand(Id, ci.limbs[i]); |
| | 2817 | cg.body.writeOperand(Id, other.limbs[j]); |
| | 2818 | |
| | 2819 | const set = try cg.importExtendedSet(); |
| | 2820 | hi = cg.module.allocId(); |
| | 2821 | try cg.body.emit(gpa, .OpExtInst, .{ |
| | 2822 | .id_result_type = u32_ty_id, |
| | 2823 | .id_result = hi, |
| | 2824 | .set = set, |
| | 2825 | .instruction = .{ .inst = @intFromEnum(spec.OpenClOpcode.u_mul_hi) }, |
| | 2826 | .id_ref_4 = &.{ ci.limbs[i], other.limbs[j] }, |
| | 2827 | }); |
| | 2828 | }, |
| | 2829 | else => { |
| | 2830 | const mul_result = cg.module.allocId(); |
| | 2831 | try cg.body.emitRaw(gpa, .OpUMulExtended, 4); |
| | 2832 | cg.body.writeOperand(Id, pair_struct_ty_id); |
| | 2833 | cg.body.writeOperand(Id, mul_result); |
| | 2834 | cg.body.writeOperand(Id, ci.limbs[i]); |
| | 2835 | cg.body.writeOperand(Id, other.limbs[j]); |
| | 2836 | |
| | 2837 | lo = cg.module.allocId(); |
| | 2838 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| | 2839 | .id_result_type = u32_ty_id, |
| | 2840 | .id_result = lo, |
| | 2841 | .composite = mul_result, |
| | 2842 | .indexes = &.{0}, |
| | 2843 | }); |
| | 2844 | hi = cg.module.allocId(); |
| | 2845 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| | 2846 | .id_result_type = u32_ty_id, |
| | 2847 | .id_result = hi, |
| | 2848 | .composite = mul_result, |
| | 2849 | .indexes = &.{1}, |
| | 2850 | }); |
| | 2851 | }, |
| | 2852 | } |
| | 2853 | |
| | 2854 | const add1 = cg.module.allocId(); |
| | 2855 | try cg.body.emitRaw(gpa, .OpIAddCarry, 4); |
| | 2856 | cg.body.writeOperand(Id, pair_struct_ty_id); |
| | 2857 | cg.body.writeOperand(Id, add1); |
| | 2858 | cg.body.writeOperand(Id, result_limbs[k]); |
| | 2859 | cg.body.writeOperand(Id, lo); |
| | 2860 | |
| | 2861 | const sum1 = cg.module.allocId(); |
| | 2862 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| | 2863 | .id_result_type = u32_ty_id, |
| | 2864 | .id_result = sum1, |
| | 2865 | .composite = add1, |
| | 2866 | .indexes = &.{0}, |
| | 2867 | }); |
| | 2868 | const c1 = cg.module.allocId(); |
| | 2869 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| | 2870 | .id_result_type = u32_ty_id, |
| | 2871 | .id_result = c1, |
| | 2872 | .composite = add1, |
| | 2873 | .indexes = &.{1}, |
| | 2874 | }); |
| | 2875 | |
| | 2876 | const add2 = cg.module.allocId(); |
| | 2877 | try cg.body.emitRaw(gpa, .OpIAddCarry, 4); |
| | 2878 | cg.body.writeOperand(Id, pair_struct_ty_id); |
| | 2879 | cg.body.writeOperand(Id, add2); |
| | 2880 | cg.body.writeOperand(Id, sum1); |
| | 2881 | cg.body.writeOperand(Id, carry_id); |
| | 2882 | |
| | 2883 | result_limbs[k] = cg.module.allocId(); |
| | 2884 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| | 2885 | .id_result_type = u32_ty_id, |
| | 2886 | .id_result = result_limbs[k], |
| | 2887 | .composite = add2, |
| | 2888 | .indexes = &.{0}, |
| | 2889 | }); |
| | 2890 | const c2 = cg.module.allocId(); |
| | 2891 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| | 2892 | .id_result_type = u32_ty_id, |
| | 2893 | .id_result = c2, |
| | 2894 | .composite = add2, |
| | 2895 | .indexes = &.{1}, |
| | 2896 | }); |
| | 2897 | |
| | 2898 | const hi_plus_c1 = try ci.limbBinOp(.OpIAdd, hi, c1); |
| | 2899 | carry_id = try ci.limbBinOp(.OpIAdd, hi_plus_c1, c2); |
| | 2900 | } |
| | 2901 | if (wide and i + n < 2 * n) { |
| | 2902 | result_limbs[i + n] = try ci.limbBinOp(.OpIAdd, result_limbs[i + n], carry_id); |
| | 2903 | } |
| | 2904 | } |
| | 2905 | |
| | 2906 | return result_limbs; |
| | 2907 | } |
| | 2908 | |
| | 2909 | fn normalize(ci: CompositeInt) !CompositeInt { |
| | 2910 | if (ci.info.bits == ci.info.backing_bits) return ci; |
| | 2911 | const cg = ci.cg; |
| | 2912 | const gpa = cg.module.gpa; |
| | 2913 | const top_bits: u16 = ci.info.bits % Module.big_int_bits; |
| | 2914 | assert(top_bits != 0); |
| | 2915 | |
| | 2916 | const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, ci.n_limbs); |
| | 2917 | for (0..ci.n_limbs - 1) |i| { |
| | 2918 | result_limbs[i] = ci.limbs[i]; |
| | 2919 | } |
| | 2920 | |
| | 2921 | const top_limb = ci.limbs[ci.n_limbs - 1]; |
| | 2922 | switch (ci.info.signedness) { |
| | 2923 | .unsigned => { |
| | 2924 | const mask_val: u32 = (@as(u32, 1) << @as(u5, @intCast(top_bits))) - 1; |
| | 2925 | const mask_id = try cg.constInt(.u32, mask_val); |
| | 2926 | result_limbs[ci.n_limbs - 1] = try ci.limbBinOp(.OpBitwiseAnd, top_limb, mask_id); |
| | 2927 | }, |
| | 2928 | .signed => { |
| | 2929 | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| | 2930 | const i32_ty_id = try cg.resolveType(.i32, .direct); |
| | 2931 | const shift_amt: u32 = 32 - top_bits; |
| | 2932 | const shift_id = try cg.constInt(.u32, shift_amt); |
| | 2933 | |
| | 2934 | const as_signed = cg.module.allocId(); |
| | 2935 | try cg.body.emit(gpa, .OpBitcast, .{ |
| | 2936 | .id_result_type = i32_ty_id, |
| | 2937 | .id_result = as_signed, |
| | 2938 | .operand = top_limb, |
| | 2939 | }); |
| | 2940 | const shifted_left = cg.module.allocId(); |
| | 2941 | try cg.body.emitRaw(gpa, .OpShiftLeftLogical, 4); |
| | 2942 | cg.body.writeOperand(Id, i32_ty_id); |
| | 2943 | cg.body.writeOperand(Id, shifted_left); |
| | 2944 | cg.body.writeOperand(Id, as_signed); |
| | 2945 | cg.body.writeOperand(Id, shift_id); |
| | 2946 | const shifted_right = cg.module.allocId(); |
| | 2947 | try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4); |
| | 2948 | cg.body.writeOperand(Id, i32_ty_id); |
| | 2949 | cg.body.writeOperand(Id, shifted_right); |
| | 2950 | cg.body.writeOperand(Id, shifted_left); |
| | 2951 | cg.body.writeOperand(Id, shift_id); |
| | 2952 | const back = cg.module.allocId(); |
| | 2953 | try cg.body.emit(gpa, .OpBitcast, .{ |
| | 2954 | .id_result_type = u32_ty_id, |
| | 2955 | .id_result = back, |
| | 2956 | .operand = shifted_right, |
| | 2957 | }); |
| | 2958 | result_limbs[ci.n_limbs - 1] = back; |
| | 2959 | }, |
| | 2960 | } |
| | 2961 | |
| | 2962 | return .fromLimbs(cg, result_limbs, ci.info); |
| | 2963 | } |
| | 2964 | }; |
| | 2965 | |
| 2219 | /// Initialize a `Temporary` from an AIR value. | 2966 | /// Initialize a `Temporary` from an AIR value. |
| 2220 | fn temporary(cg: *CodeGen, inst: Air.Inst.Ref) !Temporary { | 2967 | fn temporary(cg: *CodeGen, inst: Air.Inst.Ref) !Temporary { |
| 2221 | return .{ | 2968 | return .{ |
| ... | @@ -3234,7 +3981,21 @@ fn airBitwiseOp(cg: *CodeGen, inst: Air.Inst.Index, op: BitwiseOp) !?Id { | ... | @@ -3234,7 +3981,21 @@ fn airBitwiseOp(cg: *CodeGen, inst: Air.Inst.Index, op: BitwiseOp) !?Id { |
| 3234 | .xor => .OpBitwiseXor, | 3981 | .xor => .OpBitwiseXor, |
| 3235 | }, | 3982 | }, |
| 3236 | .float => unreachable, | 3983 | .float => unreachable, |
| 3237 | .composite_integer => unreachable, // TODO | 3984 | .composite_integer => { |
| | 3985 | const spv_opcode: Opcode = switch (op) { |
| | 3986 | .bit_and => .OpBitwiseAnd, |
| | 3987 | .bit_or => .OpBitwiseOr, |
| | 3988 | .xor => .OpBitwiseXor, |
| | 3989 | }; |
| | 3990 | const lhs_id = try lhs.materialize(cg); |
| | 3991 | const rhs_id = try rhs.materialize(cg); |
| | 3992 | const scratch_top = cg.id_scratch.items.len; |
| | 3993 | defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); |
| | 3994 | const ci_lhs = try CompositeInt.init(cg, lhs_id, info); |
| | 3995 | const ci_rhs = try CompositeInt.init(cg, rhs_id, info); |
| | 3996 | const ci_result = try ci_lhs.bitwiseOp(ci_rhs, spv_opcode); |
| | 3997 | return try ci_result.materialize(lhs.ty); |
| | 3998 | }, |
| 3238 | }; | 3999 | }; |
| 3239 | | 4000 | |
| 3240 | const result = try cg.buildBinary(opcode, lhs, rhs); | 4001 | const result = try cg.buildBinary(opcode, lhs, rhs); |
| ... | @@ -3256,7 +4017,39 @@ fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: Opcode, signed: Opcode | ... | @@ -3256,7 +4017,39 @@ fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: Opcode, signed: Opcode |
| 3256 | | 4017 | |
| 3257 | const info = cg.arithmeticTypeInfo(result_ty); | 4018 | const info = cg.arithmeticTypeInfo(result_ty); |
| 3258 | switch (info.class) { | 4019 | switch (info.class) { |
| 3259 | .composite_integer => return cg.todo("shift ops for composite integers", .{}), | 4020 | .composite_integer => { |
| | 4021 | const shift_info = cg.arithmeticTypeInfo(shift.ty); |
| | 4022 | const shift_amt_id = switch (shift_info.class) { |
| | 4023 | .composite_integer => blk: { |
| | 4024 | const shift_id = try shift.materialize(cg); |
| | 4025 | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| | 4026 | const result_id = cg.module.allocId(); |
| | 4027 | try cg.body.emit(cg.module.gpa, .OpCompositeExtract, .{ |
| | 4028 | .id_result_type = u32_ty_id, |
| | 4029 | .id_result = result_id, |
| | 4030 | .composite = shift_id, |
| | 4031 | .indexes = &.{@as(u32, 0)}, |
| | 4032 | }); |
| | 4033 | break :blk result_id; |
| | 4034 | }, |
| | 4035 | else => blk: { |
| | 4036 | const converted = try cg.buildConvert(.u32, shift); |
| | 4037 | break :blk try converted.materialize(cg); |
| | 4038 | }, |
| | 4039 | }; |
| | 4040 | const base_id = try base.materialize(cg); |
| | 4041 | const scratch_top = cg.id_scratch.items.len; |
| | 4042 | defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); |
| | 4043 | const ci = try CompositeInt.init(cg, base_id, info); |
| | 4044 | const ci_result = if (unsigned == .OpShiftLeftLogical) |
| | 4045 | try ci.shl(shift_amt_id) |
| | 4046 | else switch (info.signedness) { |
| | 4047 | .unsigned => try ci.shr(shift_amt_id, false), |
| | 4048 | .signed => try ci.shr(shift_amt_id, true), |
| | 4049 | }; |
| | 4050 | const normalized = try ci_result.normalize(); |
| | 4051 | return try normalized.materialize(result_ty); |
| | 4052 | }, |
| 3260 | .integer, .strange_integer => {}, | 4053 | .integer, .strange_integer => {}, |
| 3261 | .float, .bool => unreachable, | 4054 | .float, .bool => unreachable, |
| 3262 | } | 4055 | } |
| ... | @@ -3380,7 +4173,16 @@ fn normalize(cg: *CodeGen, value: Temporary, info: ArithmeticTypeInfo) !Temporar | ... | @@ -3380,7 +4173,16 @@ fn normalize(cg: *CodeGen, value: Temporary, info: ArithmeticTypeInfo) !Temporar |
| 3380 | const zcu = cg.module.zcu; | 4173 | const zcu = cg.module.zcu; |
| 3381 | const ty = value.ty; | 4174 | const ty = value.ty; |
| 3382 | switch (info.class) { | 4175 | switch (info.class) { |
| 3383 | .composite_integer, .integer, .bool, .float => return value, | 4176 | .integer, .bool, .float => return value, |
| | 4177 | .composite_integer => { |
| | 4178 | if (info.bits == info.backing_bits) return value; |
| | 4179 | const val_id = try value.materialize(cg); |
| | 4180 | const scratch_top = cg.id_scratch.items.len; |
| | 4181 | defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); |
| | 4182 | const ci = try CompositeInt.init(cg, val_id, info); |
| | 4183 | const normalized = try ci.normalize(); |
| | 4184 | return .init(ty, try normalized.materialize(ty)); |
| | 4185 | }, |
| 3384 | .strange_integer => switch (info.signedness) { | 4186 | .strange_integer => switch (info.signedness) { |
| 3385 | .unsigned => { | 4187 | .unsigned => { |
| 3386 | const mask_value = @as(u64, std.math.maxInt(u64)) >> @as(u6, @intCast(64 - info.bits)); | 4188 | const mask_value = @as(u64, std.math.maxInt(u64)) >> @as(u6, @intCast(64 - info.bits)); |
| ... | @@ -3484,7 +4286,22 @@ fn airArithOp( | ... | @@ -3484,7 +4286,22 @@ fn airArithOp( |
| 3484 | const rhs = try cg.temporary(bin_op.rhs); | 4286 | const rhs = try cg.temporary(bin_op.rhs); |
| 3485 | const info = cg.arithmeticTypeInfo(lhs.ty); | 4287 | const info = cg.arithmeticTypeInfo(lhs.ty); |
| 3486 | const result = switch (info.class) { | 4288 | const result = switch (info.class) { |
| 3487 | .composite_integer => return cg.todo("arith op for composite integers", .{}), | 4289 | .composite_integer => res: { |
| | 4290 | const lhs_id = try lhs.materialize(cg); |
| | 4291 | const rhs_id = try rhs.materialize(cg); |
| | 4292 | const scratch_top = cg.id_scratch.items.len; |
| | 4293 | defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); |
| | 4294 | const ci_lhs = try CompositeInt.init(cg, lhs_id, info); |
| | 4295 | const ci_rhs = try CompositeInt.init(cg, rhs_id, info); |
| | 4296 | const ci_result = switch (uop) { |
| | 4297 | .OpIAdd => try ci_lhs.addSub(ci_rhs, true), |
| | 4298 | .OpISub => try ci_lhs.addSub(ci_rhs, false), |
| | 4299 | .OpIMul => CompositeInt.fromLimbs(cg, try ci_lhs.mul(ci_rhs, false), info), |
| | 4300 | else => return cg.todo("arith op for composite integers", .{}), |
| | 4301 | }; |
| | 4302 | const normalized = try ci_result.normalize(); |
| | 4303 | break :res Temporary.init(lhs.ty, try normalized.materialize(lhs.ty)); |
| | 4304 | }, |
| 3488 | .integer, .strange_integer => res: { | 4305 | .integer, .strange_integer => res: { |
| 3489 | const raw = switch (info.signedness) { | 4306 | const raw = switch (info.signedness) { |
| 3490 | .signed => try cg.buildBinary(sop, lhs, rhs), | 4307 | .signed => try cg.buildBinary(sop, lhs, rhs), |
| ... | @@ -3514,18 +4331,50 @@ fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary { | ... | @@ -3514,18 +4331,50 @@ fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary { |
| 3514 | switch (operand_info.class) { | 4331 | switch (operand_info.class) { |
| 3515 | .float => return try cg.buildUnary(.f_abs, value), | 4332 | .float => return try cg.buildUnary(.f_abs, value), |
| 3516 | .integer, .strange_integer => { | 4333 | .integer, .strange_integer => { |
| 3517 | const abs_value = try cg.buildUnary(.i_abs, value); | 4334 | var abs_value = try cg.buildUnary(.i_abs, value); |
| 3518 | switch (target.os.tag) { | 4335 | switch (target.os.tag) { |
| 3519 | .vulkan, .opengl => { | 4336 | .vulkan, .opengl => { |
| 3520 | if (value.ty.intInfo(zcu).signedness == .signed) { | 4337 | if (value.ty.intInfo(zcu).signedness == .signed) { |
| 3521 | return cg.todo("perform bitcast after @abs", .{}); | 4338 | const abs_id = try abs_value.materialize(cg); |
| | 4339 | const dst_ty_id = try cg.resolveType(result_ty, .direct); |
| | 4340 | const cast_id = cg.module.allocId(); |
| | 4341 | try cg.body.emit(cg.module.gpa, .OpBitcast, .{ |
| | 4342 | .id_result_type = dst_ty_id, |
| | 4343 | .id_result = cast_id, |
| | 4344 | .operand = abs_id, |
| | 4345 | }); |
| | 4346 | abs_value = .init(result_ty, cast_id); |
| 3522 | } | 4347 | } |
| 3523 | }, | 4348 | }, |
| 3524 | else => {}, | 4349 | else => {}, |
| 3525 | } | 4350 | } |
| 3526 | return try cg.normalize(abs_value, cg.arithmeticTypeInfo(result_ty)); | 4351 | return try cg.normalize(abs_value, cg.arithmeticTypeInfo(result_ty)); |
| 3527 | }, | 4352 | }, |
| 3528 | .composite_integer => return cg.todo("@abs for composite integers", .{}), | 4353 | .composite_integer => { |
| | 4354 | const val_id = try value.materialize(cg); |
| | 4355 | const scratch_top = cg.id_scratch.items.len; |
| | 4356 | defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); |
| | 4357 | const ci = try CompositeInt.init(cg, val_id, operand_info); |
| | 4358 | const ci_z = try CompositeInt.zero(cg, operand_info); |
| | 4359 | const is_neg = try ci.cmp(ci_z, .lt); |
| | 4360 | const ci_neg = try ci_z.addSub(ci, false); |
| | 4361 | const result_info = cg.arithmeticTypeInfo(result_ty); |
| | 4362 | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| | 4363 | const result_limbs = try cg.id_scratch.addManyAsSlice(cg.module.gpa, ci.n_limbs); |
| | 4364 | for (0..ci.n_limbs) |i| { |
| | 4365 | result_limbs[i] = cg.module.allocId(); |
| | 4366 | try cg.body.emit(cg.module.gpa, .OpSelect, .{ |
| | 4367 | .id_result_type = u32_ty_id, |
| | 4368 | .id_result = result_limbs[i], |
| | 4369 | .condition = is_neg, |
| | 4370 | .object_1 = ci_neg.limbs[i], |
| | 4371 | .object_2 = ci.limbs[i], |
| | 4372 | }); |
| | 4373 | } |
| | 4374 | const ci_result = CompositeInt.fromLimbs(cg, result_limbs, result_info); |
| | 4375 | const normalized = try ci_result.normalize(); |
| | 4376 | return .init(result_ty, try normalized.materialize(result_ty)); |
| | 4377 | }, |
| 3529 | .bool => unreachable, | 4378 | .bool => unreachable, |
| 3530 | } | 4379 | } |
| 3531 | } | 4380 | } |
| ... | @@ -3553,7 +4402,69 @@ fn airAddSubOverflow( | ... | @@ -3553,7 +4402,69 @@ fn airAddSubOverflow( |
| 3553 | | 4402 | |
| 3554 | const info = cg.arithmeticTypeInfo(lhs.ty); | 4403 | const info = cg.arithmeticTypeInfo(lhs.ty); |
| 3555 | switch (info.class) { | 4404 | switch (info.class) { |
| 3556 | .composite_integer => return cg.todo("add/sub-with-overflow for composite integers", .{}), | 4405 | .composite_integer => { |
| | 4406 | const lhs_id = try lhs.materialize(cg); |
| | 4407 | const rhs_id = try rhs.materialize(cg); |
| | 4408 | const scratch_top = cg.id_scratch.items.len; |
| | 4409 | defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); |
| | 4410 | const ci_lhs = try CompositeInt.init(cg, lhs_id, info); |
| | 4411 | const ci_rhs = try CompositeInt.init(cg, rhs_id, info); |
| | 4412 | const ci_sum = if (add == .OpIAdd) try ci_lhs.addSub(ci_rhs, true) else try ci_lhs.addSub(ci_rhs, false); |
| | 4413 | const ci_result = try ci_sum.normalize(); |
| | 4414 | const result_val_id = try ci_result.materialize(lhs.ty); |
| | 4415 | |
| | 4416 | const ov_bool = switch (info.signedness) { |
| | 4417 | .unsigned => blk: { |
| | 4418 | const ci_res2 = try CompositeInt.init(cg, result_val_id, info); |
| | 4419 | const ci_lhs2 = try CompositeInt.init(cg, lhs_id, info); |
| | 4420 | break :blk if (add == .OpIAdd) |
| | 4421 | try ci_res2.cmp(ci_lhs2, .lt) |
| | 4422 | else |
| | 4423 | try ci_res2.cmp(ci_lhs2, .gt); |
| | 4424 | }, |
| | 4425 | .signed => blk: { |
| | 4426 | const ci_res2 = try CompositeInt.init(cg, result_val_id, info); |
| | 4427 | const ci_lhs2 = try CompositeInt.init(cg, lhs_id, info); |
| | 4428 | const ci_rhs2 = try CompositeInt.init(cg, rhs_id, info); |
| | 4429 | const ci_z = try CompositeInt.zero(cg, info); |
| | 4430 | const lhs_neg = try ci_lhs2.cmp(ci_z, .lt); |
| | 4431 | const rhs_neg = try ci_rhs2.cmp(ci_z, .lt); |
| | 4432 | const res_neg = try ci_res2.cmp(ci_z, .lt); |
| | 4433 | |
| | 4434 | const bool_ty_id = try cg.resolveType(.bool, .direct); |
| | 4435 | const signs_match = cg.module.allocId(); |
| | 4436 | try cg.body.emitRaw(cg.module.gpa, .OpLogicalEqual, 4); |
| | 4437 | cg.body.writeOperand(Id, bool_ty_id); |
| | 4438 | cg.body.writeOperand(Id, signs_match); |
| | 4439 | cg.body.writeOperand(Id, lhs_neg); |
| | 4440 | cg.body.writeOperand(Id, rhs_neg); |
| | 4441 | const res_sign_diff = cg.module.allocId(); |
| | 4442 | try cg.body.emitRaw(cg.module.gpa, .OpLogicalNotEqual, 4); |
| | 4443 | cg.body.writeOperand(Id, bool_ty_id); |
| | 4444 | cg.body.writeOperand(Id, res_sign_diff); |
| | 4445 | cg.body.writeOperand(Id, lhs_neg); |
| | 4446 | cg.body.writeOperand(Id, res_neg); |
| | 4447 | const ov_cond = if (add == .OpIAdd) signs_match else blk2: { |
| | 4448 | const not_match = cg.module.allocId(); |
| | 4449 | try cg.body.emitRaw(cg.module.gpa, .OpLogicalNot, 3); |
| | 4450 | cg.body.writeOperand(Id, bool_ty_id); |
| | 4451 | cg.body.writeOperand(Id, not_match); |
| | 4452 | cg.body.writeOperand(Id, signs_match); |
| | 4453 | break :blk2 not_match; |
| | 4454 | }; |
| | 4455 | const ov_result = cg.module.allocId(); |
| | 4456 | try cg.body.emitRaw(cg.module.gpa, .OpLogicalAnd, 4); |
| | 4457 | cg.body.writeOperand(Id, bool_ty_id); |
| | 4458 | cg.body.writeOperand(Id, ov_result); |
| | 4459 | cg.body.writeOperand(Id, ov_cond); |
| | 4460 | cg.body.writeOperand(Id, res_sign_diff); |
| | 4461 | break :blk ov_result; |
| | 4462 | }, |
| | 4463 | }; |
| | 4464 | const ov = try cg.intFromBool(.init(.bool, ov_bool), .u1); |
| | 4465 | const result_ty_id = try cg.resolveType(result_ty, .direct); |
| | 4466 | return try cg.constructComposite(result_ty_id, &.{ result_val_id, try ov.materialize(cg) }); |
| | 4467 | }, |
| 3557 | .strange_integer, .integer => {}, | 4468 | .strange_integer, .integer => {}, |
| 3558 | .float, .bool => unreachable, | 4469 | .float, .bool => unreachable, |
| 3559 | } | 4470 | } |
| ... | @@ -3595,6 +4506,7 @@ fn airAddSubOverflow( | ... | @@ -3595,6 +4506,7 @@ fn airAddSubOverflow( |
| 3595 | | 4506 | |
| 3596 | fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | 4507 | fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 3597 | const pt = cg.pt; | 4508 | const pt = cg.pt; |
| | 4509 | const gpa = cg.module.gpa; |
| 3598 | const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; | 4510 | const ty_pl = cg.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl; |
| 3599 | const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data; | 4511 | const extra = cg.air.extraData(Air.Bin, ty_pl.payload).data; |
| 3600 | const lhs = try cg.temporary(extra.lhs); | 4512 | const lhs = try cg.temporary(extra.lhs); |
| ... | @@ -3603,7 +4515,158 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | ... | @@ -3603,7 +4515,158 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 3603 | | 4515 | |
| 3604 | const info = cg.arithmeticTypeInfo(lhs.ty); | 4516 | const info = cg.arithmeticTypeInfo(lhs.ty); |
| 3605 | switch (info.class) { | 4517 | switch (info.class) { |
| 3606 | .composite_integer => return cg.todo("mul-with-overflow for composite integers", .{}), | 4518 | .composite_integer => { |
| | 4519 | const lhs_id = try lhs.materialize(cg); |
| | 4520 | const rhs_id = try rhs.materialize(cg); |
| | 4521 | const scratch_top = cg.id_scratch.items.len; |
| | 4522 | defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); |
| | 4523 | const ci_lhs = try CompositeInt.init(cg, lhs_id, info); |
| | 4524 | const ci_rhs = try CompositeInt.init(cg, rhs_id, info); |
| | 4525 | |
| | 4526 | const low_limbs = try ci_lhs.mul(ci_rhs, false); |
| | 4527 | const ci_result = try CompositeInt.fromLimbs(cg, low_limbs, info).normalize(); |
| | 4528 | const result_val_id = try ci_result.materialize(lhs.ty); |
| | 4529 | |
| | 4530 | const ci_lhs2 = try CompositeInt.init(cg, lhs_id, info); |
| | 4531 | const ci_rhs2 = try CompositeInt.init(cg, rhs_id, info); |
| | 4532 | const wide_limbs = try ci_lhs2.mul(ci_rhs2, true); |
| | 4533 | const high_limbs = wide_limbs[ci_lhs2.n_limbs..]; |
| | 4534 | |
| | 4535 | const bool_ty_id = try cg.resolveType(.bool, .direct); |
| | 4536 | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| | 4537 | const n: usize = info.backing_bits / Module.big_int_bits; |
| | 4538 | |
| | 4539 | const ov_bool = switch (info.signedness) { |
| | 4540 | .unsigned => blk: { |
| | 4541 | const zero_id = try cg.constInt(.u32, @as(u32, 0)); |
| | 4542 | var any_nonzero = cg.module.allocId(); |
| | 4543 | try cg.body.emitRaw(gpa, .OpINotEqual, 4); |
| | 4544 | cg.body.writeOperand(Id, bool_ty_id); |
| | 4545 | cg.body.writeOperand(Id, any_nonzero); |
| | 4546 | cg.body.writeOperand(Id, high_limbs[0]); |
| | 4547 | cg.body.writeOperand(Id, zero_id); |
| | 4548 | |
| | 4549 | for (1..n) |i| { |
| | 4550 | const limb_nz = cg.module.allocId(); |
| | 4551 | try cg.body.emitRaw(gpa, .OpINotEqual, 4); |
| | 4552 | cg.body.writeOperand(Id, bool_ty_id); |
| | 4553 | cg.body.writeOperand(Id, limb_nz); |
| | 4554 | cg.body.writeOperand(Id, high_limbs[i]); |
| | 4555 | cg.body.writeOperand(Id, zero_id); |
| | 4556 | |
| | 4557 | const combined = cg.module.allocId(); |
| | 4558 | try cg.body.emitRaw(gpa, .OpLogicalOr, 4); |
| | 4559 | cg.body.writeOperand(Id, bool_ty_id); |
| | 4560 | cg.body.writeOperand(Id, combined); |
| | 4561 | cg.body.writeOperand(Id, any_nonzero); |
| | 4562 | cg.body.writeOperand(Id, limb_nz); |
| | 4563 | any_nonzero = combined; |
| | 4564 | } |
| | 4565 | |
| | 4566 | break :blk any_nonzero; |
| | 4567 | }, |
| | 4568 | .signed => blk: { |
| | 4569 | const ci_res = try CompositeInt.init(cg, result_val_id, info); |
| | 4570 | const top_limb = ci_res.limbs[n - 1]; |
| | 4571 | const i32_ty_id = try cg.resolveType(.i32, .direct); |
| | 4572 | |
| | 4573 | const top_bits: u16 = if (info.bits % Module.big_int_bits == 0) |
| | 4574 | Module.big_int_bits |
| | 4575 | else |
| | 4576 | info.bits % Module.big_int_bits; |
| | 4577 | |
| | 4578 | const shift_amt: u32 = top_bits - 1; |
| | 4579 | const shift_id = try cg.constInt(.u32, shift_amt); |
| | 4580 | |
| | 4581 | const as_signed = cg.module.allocId(); |
| | 4582 | try cg.body.emit(gpa, .OpBitcast, .{ |
| | 4583 | .id_result_type = i32_ty_id, |
| | 4584 | .id_result = as_signed, |
| | 4585 | .operand = top_limb, |
| | 4586 | }); |
| | 4587 | const sign_ext = cg.module.allocId(); |
| | 4588 | try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4); |
| | 4589 | cg.body.writeOperand(Id, i32_ty_id); |
| | 4590 | cg.body.writeOperand(Id, sign_ext); |
| | 4591 | cg.body.writeOperand(Id, as_signed); |
| | 4592 | cg.body.writeOperand(Id, shift_id); |
| | 4593 | const expected = cg.module.allocId(); |
| | 4594 | try cg.body.emit(gpa, .OpBitcast, .{ |
| | 4595 | .id_result_type = u32_ty_id, |
| | 4596 | .id_result = expected, |
| | 4597 | .operand = sign_ext, |
| | 4598 | }); |
| | 4599 | |
| | 4600 | var any_mismatch = cg.module.allocId(); |
| | 4601 | try cg.body.emitRaw(gpa, .OpINotEqual, 4); |
| | 4602 | cg.body.writeOperand(Id, bool_ty_id); |
| | 4603 | cg.body.writeOperand(Id, any_mismatch); |
| | 4604 | cg.body.writeOperand(Id, high_limbs[0]); |
| | 4605 | cg.body.writeOperand(Id, expected); |
| | 4606 | |
| | 4607 | for (1..n) |i| { |
| | 4608 | const limb_ne = cg.module.allocId(); |
| | 4609 | try cg.body.emitRaw(gpa, .OpINotEqual, 4); |
| | 4610 | cg.body.writeOperand(Id, bool_ty_id); |
| | 4611 | cg.body.writeOperand(Id, limb_ne); |
| | 4612 | cg.body.writeOperand(Id, high_limbs[i]); |
| | 4613 | cg.body.writeOperand(Id, expected); |
| | 4614 | |
| | 4615 | const combined = cg.module.allocId(); |
| | 4616 | try cg.body.emitRaw(gpa, .OpLogicalOr, 4); |
| | 4617 | cg.body.writeOperand(Id, bool_ty_id); |
| | 4618 | cg.body.writeOperand(Id, combined); |
| | 4619 | cg.body.writeOperand(Id, any_mismatch); |
| | 4620 | cg.body.writeOperand(Id, limb_ne); |
| | 4621 | any_mismatch = combined; |
| | 4622 | } |
| | 4623 | |
| | 4624 | if (info.bits != info.backing_bits) { |
| | 4625 | const top_bits_s: u16 = info.bits % Module.big_int_bits; |
| | 4626 | const s_shift_id = try cg.constInt(.u32, top_bits_s - 1); |
| | 4627 | |
| | 4628 | const top_as_signed = cg.module.allocId(); |
| | 4629 | try cg.body.emit(gpa, .OpBitcast, .{ |
| | 4630 | .id_result_type = i32_ty_id, |
| | 4631 | .id_result = top_as_signed, |
| | 4632 | .operand = top_limb, |
| | 4633 | }); |
| | 4634 | const top_sign_ext = cg.module.allocId(); |
| | 4635 | try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4); |
| | 4636 | cg.body.writeOperand(Id, i32_ty_id); |
| | 4637 | cg.body.writeOperand(Id, top_sign_ext); |
| | 4638 | cg.body.writeOperand(Id, top_as_signed); |
| | 4639 | cg.body.writeOperand(Id, s_shift_id); |
| | 4640 | const top_expected = cg.module.allocId(); |
| | 4641 | try cg.body.emit(gpa, .OpBitcast, .{ |
| | 4642 | .id_result_type = u32_ty_id, |
| | 4643 | .id_result = top_expected, |
| | 4644 | .operand = top_sign_ext, |
| | 4645 | }); |
| | 4646 | const top_mismatch = cg.module.allocId(); |
| | 4647 | try cg.body.emitRaw(gpa, .OpINotEqual, 4); |
| | 4648 | cg.body.writeOperand(Id, bool_ty_id); |
| | 4649 | cg.body.writeOperand(Id, top_mismatch); |
| | 4650 | cg.body.writeOperand(Id, top_limb); |
| | 4651 | cg.body.writeOperand(Id, top_expected); |
| | 4652 | |
| | 4653 | const combined = cg.module.allocId(); |
| | 4654 | try cg.body.emitRaw(gpa, .OpLogicalOr, 4); |
| | 4655 | cg.body.writeOperand(Id, bool_ty_id); |
| | 4656 | cg.body.writeOperand(Id, combined); |
| | 4657 | cg.body.writeOperand(Id, any_mismatch); |
| | 4658 | cg.body.writeOperand(Id, top_mismatch); |
| | 4659 | any_mismatch = combined; |
| | 4660 | } |
| | 4661 | |
| | 4662 | break :blk any_mismatch; |
| | 4663 | }, |
| | 4664 | }; |
| | 4665 | |
| | 4666 | const ov = try cg.intFromBool(.init(.bool, ov_bool), .u1); |
| | 4667 | const result_ty_id = try cg.resolveType(result_ty, .direct); |
| | 4668 | return try cg.constructComposite(result_ty_id, &.{ result_val_id, try ov.materialize(cg) }); |
| | 4669 | }, |
| 3607 | .strange_integer, .integer => {}, | 4670 | .strange_integer, .integer => {}, |
| 3608 | .float, .bool => unreachable, | 4671 | .float, .bool => unreachable, |
| 3609 | } | 4672 | } |
| ... | @@ -3622,7 +4685,7 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | ... | @@ -3622,7 +4685,7 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 3622 | 1...16 => 32, | 4685 | 1...16 => 32, |
| 3623 | 17...32 => if (largest_int_bits > 32) 64 else null, // Upcast if we can. | 4686 | 17...32 => if (largest_int_bits > 32) 64 else null, // Upcast if we can. |
| 3624 | 33...64 => null, // Always use wide multiplication. | 4687 | 33...64 => null, // Always use wide multiplication. |
| 3625 | else => unreachable, // TODO: Composite integers | 4688 | else => unreachable, |
| 3626 | }; | 4689 | }; |
| 3627 | | 4690 | |
| 3628 | const result, const overflowed = switch (info.signedness) { | 4691 | const result, const overflowed = switch (info.signedness) { |
| ... | @@ -4245,7 +5308,16 @@ fn cmp( | ... | @@ -4245,7 +5308,16 @@ fn cmp( |
| 4245 | | 5308 | |
| 4246 | const info = cg.arithmeticTypeInfo(scalar_ty); | 5309 | const info = cg.arithmeticTypeInfo(scalar_ty); |
| 4247 | const pred: Opcode = switch (info.class) { | 5310 | const pred: Opcode = switch (info.class) { |
| 4248 | .composite_integer => return cg.todo("comparison for composite integers", .{}), | 5311 | .composite_integer => { |
| | 5312 | const lhs_id = try lhs.materialize(cg); |
| | 5313 | const rhs_id = try rhs.materialize(cg); |
| | 5314 | const scratch_top = cg.id_scratch.items.len; |
| | 5315 | defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); |
| | 5316 | const ci_lhs = try CompositeInt.init(cg, lhs_id, info); |
| | 5317 | const ci_rhs = try CompositeInt.init(cg, rhs_id, info); |
| | 5318 | const result_id = try ci_lhs.cmp(ci_rhs, op); |
| | 5319 | return .init(.bool, result_id); |
| | 5320 | }, |
| 4249 | .float => switch (op) { | 5321 | .float => switch (op) { |
| 4250 | .eq => .OpFOrdEqual, | 5322 | .eq => .OpFOrdEqual, |
| 4251 | .neq => .OpFUnordNotEqual, | 5323 | .neq => .OpFUnordNotEqual, |
| ... | @@ -4408,6 +5480,192 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | ... | @@ -4408,6 +5480,192 @@ fn airIntCast(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 4408 | const src_info = cg.arithmeticTypeInfo(src.ty); | 5480 | const src_info = cg.arithmeticTypeInfo(src.ty); |
| 4409 | const dst_info = cg.arithmeticTypeInfo(dst_ty); | 5481 | const dst_info = cg.arithmeticTypeInfo(dst_ty); |
| 4410 | | 5482 | |
| | 5483 | const src_composite = src_info.class == .composite_integer; |
| | 5484 | const dst_composite = dst_info.class == .composite_integer; |
| | 5485 | |
| | 5486 | if (src_composite or dst_composite) { |
| | 5487 | const gpa = cg.module.gpa; |
| | 5488 | const scratch_top = cg.id_scratch.items.len; |
| | 5489 | defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); |
| | 5490 | |
| | 5491 | if (src_composite and dst_composite) { |
| | 5492 | const src_id = try src.materialize(cg); |
| | 5493 | const src_n: u16 = src_info.backing_bits / Module.big_int_bits; |
| | 5494 | const dst_n: u16 = dst_info.backing_bits / Module.big_int_bits; |
| | 5495 | const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, dst_n); |
| | 5496 | const min_n = @min(src_n, dst_n); |
| | 5497 | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| | 5498 | for (0..min_n) |i| { |
| | 5499 | result_limbs[i] = cg.module.allocId(); |
| | 5500 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| | 5501 | .id_result_type = u32_ty_id, |
| | 5502 | .id_result = result_limbs[i], |
| | 5503 | .composite = src_id, |
| | 5504 | .indexes = &.{@as(u32, @intCast(i))}, |
| | 5505 | }); |
| | 5506 | } |
| | 5507 | if (dst_n > src_n) { |
| | 5508 | const fill = if (src_info.signedness == .signed) blk: { |
| | 5509 | const i32_ty_id = try cg.resolveType(.i32, .direct); |
| | 5510 | const msb = result_limbs[src_n - 1]; |
| | 5511 | const msb_signed = cg.module.allocId(); |
| | 5512 | try cg.body.emit(gpa, .OpBitcast, .{ |
| | 5513 | .id_result_type = i32_ty_id, |
| | 5514 | .id_result = msb_signed, |
| | 5515 | .operand = msb, |
| | 5516 | }); |
| | 5517 | const shift31 = try cg.constInt(.i32, @as(i32, 31)); |
| | 5518 | const sign_ext = cg.module.allocId(); |
| | 5519 | try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4); |
| | 5520 | cg.body.writeOperand(Id, i32_ty_id); |
| | 5521 | cg.body.writeOperand(Id, sign_ext); |
| | 5522 | cg.body.writeOperand(Id, msb_signed); |
| | 5523 | cg.body.writeOperand(Id, shift31); |
| | 5524 | const back = cg.module.allocId(); |
| | 5525 | try cg.body.emit(gpa, .OpBitcast, .{ |
| | 5526 | .id_result_type = u32_ty_id, |
| | 5527 | .id_result = back, |
| | 5528 | .operand = sign_ext, |
| | 5529 | }); |
| | 5530 | break :blk back; |
| | 5531 | } else try cg.constInt(.u32, @as(u32, 0)); |
| | 5532 | for (min_n..dst_n) |i| { |
| | 5533 | result_limbs[i] = fill; |
| | 5534 | } |
| | 5535 | } |
| | 5536 | const ci = CompositeInt.fromLimbs(cg, result_limbs, dst_info); |
| | 5537 | const normalized = try ci.normalize(); |
| | 5538 | return try normalized.materialize(dst_ty); |
| | 5539 | } else if (src_composite and !dst_composite) { |
| | 5540 | const src_id = try src.materialize(cg); |
| | 5541 | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| | 5542 | if (dst_info.backing_bits <= 32) { |
| | 5543 | const limb0 = cg.module.allocId(); |
| | 5544 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| | 5545 | .id_result_type = u32_ty_id, |
| | 5546 | .id_result = limb0, |
| | 5547 | .composite = src_id, |
| | 5548 | .indexes = &.{@as(u32, 0)}, |
| | 5549 | }); |
| | 5550 | const tmp: Temporary = .init(.u32, limb0); |
| | 5551 | const converted = try cg.buildConvert(dst_ty, tmp); |
| | 5552 | const result = if (dst_info.bits < src_info.bits) |
| | 5553 | try cg.normalize(converted, dst_info) |
| | 5554 | else |
| | 5555 | converted; |
| | 5556 | return try result.materialize(cg); |
| | 5557 | } else { |
| | 5558 | const limb0 = cg.module.allocId(); |
| | 5559 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| | 5560 | .id_result_type = u32_ty_id, |
| | 5561 | .id_result = limb0, |
| | 5562 | .composite = src_id, |
| | 5563 | .indexes = &.{@as(u32, 0)}, |
| | 5564 | }); |
| | 5565 | const limb1 = cg.module.allocId(); |
| | 5566 | try cg.body.emit(gpa, .OpCompositeExtract, .{ |
| | 5567 | .id_result_type = u32_ty_id, |
| | 5568 | .id_result = limb1, |
| | 5569 | .composite = src_id, |
| | 5570 | .indexes = &.{@as(u32, 1)}, |
| | 5571 | }); |
| | 5572 | const u64_ty_id = try cg.resolveType(.u64, .direct); |
| | 5573 | const lo = cg.module.allocId(); |
| | 5574 | try cg.body.emitRaw(gpa, .OpUConvert, 3); |
| | 5575 | cg.body.writeOperand(Id, u64_ty_id); |
| | 5576 | cg.body.writeOperand(Id, lo); |
| | 5577 | cg.body.writeOperand(Id, limb0); |
| | 5578 | const hi = cg.module.allocId(); |
| | 5579 | try cg.body.emitRaw(gpa, .OpUConvert, 3); |
| | 5580 | cg.body.writeOperand(Id, u64_ty_id); |
| | 5581 | cg.body.writeOperand(Id, hi); |
| | 5582 | cg.body.writeOperand(Id, limb1); |
| | 5583 | const shift32 = try cg.constInt(.u64, @as(u64, 32)); |
| | 5584 | const hi_shifted = cg.module.allocId(); |
| | 5585 | try cg.body.emitRaw(gpa, .OpShiftLeftLogical, 4); |
| | 5586 | cg.body.writeOperand(Id, u64_ty_id); |
| | 5587 | cg.body.writeOperand(Id, hi_shifted); |
| | 5588 | cg.body.writeOperand(Id, hi); |
| | 5589 | cg.body.writeOperand(Id, shift32); |
| | 5590 | const combined = cg.module.allocId(); |
| | 5591 | try cg.body.emitRaw(gpa, .OpBitwiseOr, 4); |
| | 5592 | cg.body.writeOperand(Id, u64_ty_id); |
| | 5593 | cg.body.writeOperand(Id, combined); |
| | 5594 | cg.body.writeOperand(Id, lo); |
| | 5595 | cg.body.writeOperand(Id, hi_shifted); |
| | 5596 | const tmp: Temporary = .init(.u64, combined); |
| | 5597 | const converted = try cg.buildConvert(dst_ty, tmp); |
| | 5598 | const result = if (dst_info.bits < src_info.bits) |
| | 5599 | try cg.normalize(converted, dst_info) |
| | 5600 | else |
| | 5601 | converted; |
| | 5602 | return try result.materialize(cg); |
| | 5603 | } |
| | 5604 | } else { |
| | 5605 | const dst_n: u16 = dst_info.backing_bits / Module.big_int_bits; |
| | 5606 | const result_limbs = try cg.id_scratch.addManyAsSlice(gpa, dst_n); |
| | 5607 | const u32_ty_id = try cg.resolveType(.u32, .direct); |
| | 5608 | |
| | 5609 | if (src_info.backing_bits <= 32) { |
| | 5610 | const converted = try cg.buildConvert(.u32, src); |
| | 5611 | result_limbs[0] = try converted.materialize(cg); |
| | 5612 | } else { |
| | 5613 | const src_as_u64 = try cg.buildConvert(.u64, src); |
| | 5614 | const src_id = try src_as_u64.materialize(cg); |
| | 5615 | result_limbs[0] = cg.module.allocId(); |
| | 5616 | try cg.body.emitRaw(gpa, .OpUConvert, 3); |
| | 5617 | cg.body.writeOperand(Id, u32_ty_id); |
| | 5618 | cg.body.writeOperand(Id, result_limbs[0]); |
| | 5619 | cg.body.writeOperand(Id, src_id); |
| | 5620 | const u64_ty_id = try cg.resolveType(.u64, .direct); |
| | 5621 | const shift32 = try cg.constInt(.u64, @as(u64, 32)); |
| | 5622 | const hi = cg.module.allocId(); |
| | 5623 | try cg.body.emitRaw(gpa, .OpShiftRightLogical, 4); |
| | 5624 | cg.body.writeOperand(Id, u64_ty_id); |
| | 5625 | cg.body.writeOperand(Id, hi); |
| | 5626 | cg.body.writeOperand(Id, src_id); |
| | 5627 | cg.body.writeOperand(Id, shift32); |
| | 5628 | result_limbs[1] = cg.module.allocId(); |
| | 5629 | try cg.body.emitRaw(gpa, .OpUConvert, 3); |
| | 5630 | cg.body.writeOperand(Id, u32_ty_id); |
| | 5631 | cg.body.writeOperand(Id, result_limbs[1]); |
| | 5632 | cg.body.writeOperand(Id, hi); |
| | 5633 | } |
| | 5634 | // Sign/zero-extend remaining limbs. |
| | 5635 | const fill_start: u16 = if (src_info.backing_bits <= 32) 1 else 2; |
| | 5636 | const fill = if (src_info.signedness == .signed) blk: { |
| | 5637 | const i32_ty_id = try cg.resolveType(.i32, .direct); |
| | 5638 | const msb = result_limbs[fill_start - 1]; |
| | 5639 | const msb_signed = cg.module.allocId(); |
| | 5640 | try cg.body.emit(gpa, .OpBitcast, .{ |
| | 5641 | .id_result_type = i32_ty_id, |
| | 5642 | .id_result = msb_signed, |
| | 5643 | .operand = msb, |
| | 5644 | }); |
| | 5645 | const shift31 = try cg.constInt(.i32, @as(i32, 31)); |
| | 5646 | const sign_ext = cg.module.allocId(); |
| | 5647 | try cg.body.emitRaw(gpa, .OpShiftRightArithmetic, 4); |
| | 5648 | cg.body.writeOperand(Id, i32_ty_id); |
| | 5649 | cg.body.writeOperand(Id, sign_ext); |
| | 5650 | cg.body.writeOperand(Id, msb_signed); |
| | 5651 | cg.body.writeOperand(Id, shift31); |
| | 5652 | const back = cg.module.allocId(); |
| | 5653 | try cg.body.emit(gpa, .OpBitcast, .{ |
| | 5654 | .id_result_type = u32_ty_id, |
| | 5655 | .id_result = back, |
| | 5656 | .operand = sign_ext, |
| | 5657 | }); |
| | 5658 | break :blk back; |
| | 5659 | } else try cg.constInt(.u32, @as(u32, 0)); |
| | 5660 | for (fill_start..dst_n) |i| { |
| | 5661 | result_limbs[i] = fill; |
| | 5662 | } |
| | 5663 | const ci = CompositeInt.fromLimbs(cg, result_limbs, dst_info); |
| | 5664 | const normalized = try ci.normalize(); |
| | 5665 | return try normalized.materialize(dst_ty); |
| | 5666 | } |
| | 5667 | } |
| | 5668 | |
| 4411 | if (src_info.backing_bits == dst_info.backing_bits) { | 5669 | if (src_info.backing_bits == dst_info.backing_bits) { |
| 4412 | const result = if (dst_info.bits < src_info.bits) | 5670 | const result = if (dst_info.bits < src_info.bits) |
| 4413 | try cg.normalize(src.pun(dst_ty), dst_info) | 5671 | try cg.normalize(src.pun(dst_ty), dst_info) |
| ... | @@ -4513,7 +5771,15 @@ fn airNot(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | ... | @@ -4513,7 +5771,15 @@ fn airNot(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 4513 | const result = switch (info.class) { | 5771 | const result = switch (info.class) { |
| 4514 | .bool => try cg.buildUnary(.l_not, operand), | 5772 | .bool => try cg.buildUnary(.l_not, operand), |
| 4515 | .float => unreachable, | 5773 | .float => unreachable, |
| 4516 | .composite_integer => return cg.todo("bitwise not for composite integers", .{}), | 5774 | .composite_integer => blk: { |
| | 5775 | const op_id = try operand.materialize(cg); |
| | 5776 | const scratch_top = cg.id_scratch.items.len; |
| | 5777 | defer cg.id_scratch.shrinkRetainingCapacity(scratch_top); |
| | 5778 | const ci = try CompositeInt.init(cg, op_id, info); |
| | 5779 | const notted = try ci.bitwiseNot(); |
| | 5780 | const normalized = try notted.normalize(); |
| | 5781 | break :blk Temporary.init(result_ty, try normalized.materialize(result_ty)); |
| | 5782 | }, |
| 4517 | .strange_integer, .integer => blk: { | 5783 | .strange_integer, .integer => blk: { |
| 4518 | const complement = try cg.buildUnary(.bit_not, operand); | 5784 | const complement = try cg.buildUnary(.bit_not, operand); |
| 4519 | break :blk try cg.normalize(complement, info); | 5785 | break :blk try cg.normalize(complement, info); |
| ... | @@ -6198,9 +7464,7 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void { | ... | @@ -6198,9 +7464,7 @@ fn airSwitchBr(cg: *CodeGen, inst: Air.Inst.Index) !void { |
| 6198 | const value: Value = .fromInterned(item.toInterned().?); | 7464 | const value: Value = .fromInterned(item.toInterned().?); |
| 6199 | const int_val: u64 = switch (cond_ty.zigTypeTag(zcu)) { | 7465 | const int_val: u64 = switch (cond_ty.zigTypeTag(zcu)) { |
| 6200 | .bool, .int => if (cond_ty.isSignedInt(zcu)) @bitCast(value.toSignedInt(zcu)) else value.toUnsignedInt(zcu), | 7466 | .bool, .int => if (cond_ty.isSignedInt(zcu)) @bitCast(value.toSignedInt(zcu)) else value.toUnsignedInt(zcu), |
| 6201 | .@"enum" => blk: { | 7467 | .@"enum" => value.intFromEnum(zcu).toUnsignedInt(zcu), |
| 6202 | break :blk value.intFromEnum(zcu).toUnsignedInt(zcu); // TODO: composite integer constants | | |
| 6203 | }, | | |
| 6204 | .error_set => value.getErrorInt(zcu), | 7468 | .error_set => value.getErrorInt(zcu), |
| 6205 | .pointer => value.toUnsignedInt(zcu), | 7469 | .pointer => value.toUnsignedInt(zcu), |
| 6206 | else => unreachable, | 7470 | else => unreachable, |
| ... | @@ -6502,7 +7766,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) | ... | @@ -6502,7 +7766,7 @@ fn airCall(cg: *CodeGen, inst: Air.Inst.Index, modifier: std.lang.CallModifier) |
| 6502 | fn builtin3D( | 7766 | fn builtin3D( |
| 6503 | cg: *CodeGen, | 7767 | cg: *CodeGen, |
| 6504 | result_ty: Type, | 7768 | result_ty: Type, |
| 6505 | builtin: spec.BuiltIn, | 7769 | built_in: spec.BuiltIn, |
| 6506 | dimension: u32, | 7770 | dimension: u32, |
| 6507 | out_of_range_value: anytype, | 7771 | out_of_range_value: anytype, |
| 6508 | ) !Id { | 7772 | ) !Id { |
| ... | @@ -6511,7 +7775,7 @@ fn builtin3D( | ... | @@ -6511,7 +7775,7 @@ fn builtin3D( |
| 6511 | const u32_ty_id = try cg.module.intType(.unsigned, 32); | 7775 | const u32_ty_id = try cg.module.intType(.unsigned, 32); |
| 6512 | const vec_ty_id = try cg.module.vectorType(3, u32_ty_id); | 7776 | const vec_ty_id = try cg.module.vectorType(3, u32_ty_id); |
| 6513 | const ptr_ty_id = try cg.module.ptrType(vec_ty_id, .input); | 7777 | const ptr_ty_id = try cg.module.ptrType(vec_ty_id, .input); |
| 6514 | const spv_decl_index = try cg.module.builtin(ptr_ty_id, builtin, .input); | 7778 | const spv_decl_index = try cg.module.builtin(ptr_ty_id, built_in, .input); |
| 6515 | try cg.module.decl_deps.append(gpa, spv_decl_index); | 7779 | try cg.module.decl_deps.append(gpa, spv_decl_index); |
| 6516 | const ptr_id = cg.module.declPtr(spv_decl_index).result_id; | 7780 | const ptr_id = cg.module.declPtr(spv_decl_index).result_id; |
| 6517 | const vec_id = cg.module.allocId(); | 7781 | const vec_id = cg.module.allocId(); |