| ... | @@ -431,15 +431,12 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id { | ... | @@ -431,15 +431,12 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id { |
| 431 | const zcu = cg.module.zcu; | 431 | const zcu = cg.module.zcu; |
| 432 | const ty: Type = .fromInterned(zcu.intern_pool.typeOf(val)); | 432 | const ty: Type = .fromInterned(zcu.intern_pool.typeOf(val)); |
| 433 | const ty_id = try cg.resolveType(ty, .indirect); | 433 | const ty_id = try cg.resolveType(ty, .indirect); |
| 434 | const decl_ptr_ty_id = try cg.module.ptrType(ty_id, cg.module.storageClass(.generic)); | | |
| 435 | | 434 | |
| 436 | const spv_decl_index = blk: { | 435 | const spv_decl_index = blk: { |
| 437 | const entry = try cg.module.uav_link.getOrPut(cg.module.gpa, .{ val, .function }); | 436 | const entry = try cg.module.uav_link.getOrPut(cg.module.gpa, .{ val, .function }); |
| 438 | if (entry.found_existing) { | 437 | if (entry.found_existing) { |
| 439 | try cg.addFunctionDep(entry.value_ptr.*, .function); | 438 | try cg.addFunctionDep(entry.value_ptr.*, .function); |
| 440 | | 439 | return cg.module.declPtr(entry.value_ptr.*).result_id; |
| 441 | const result_id = cg.module.declPtr(entry.value_ptr.*).result_id; | | |
| 442 | return try cg.castToGeneric(decl_ptr_ty_id, result_id); | | |
| 443 | } | 440 | } |
| 444 | | 441 | |
| 445 | const spv_decl_index = try cg.module.allocDecl(.invocation_global); | 442 | const spv_decl_index = try cg.module.allocDecl(.invocation_global); |
| ... | @@ -520,7 +517,7 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id { | ... | @@ -520,7 +517,7 @@ fn resolveUav(cg: *CodeGen, val: InternPool.Index) !Id { |
| 520 | }); | 517 | }); |
| 521 | } | 518 | } |
| 522 | | 519 | |
| 523 | return try cg.castToGeneric(decl_ptr_ty_id, result_id); | 520 | return result_id; |
| 524 | } | 521 | } |
| 525 | | 522 | |
| 526 | fn addFunctionDep(cg: *CodeGen, decl_index: Module.Decl.Index, storage_class: StorageClass) !void { | 523 | fn addFunctionDep(cg: *CodeGen, decl_index: Module.Decl.Index, storage_class: StorageClass) !void { |
| ... | @@ -535,21 +532,6 @@ fn addFunctionDep(cg: *CodeGen, decl_index: Module.Decl.Index, storage_class: St | ... | @@ -535,21 +532,6 @@ fn addFunctionDep(cg: *CodeGen, decl_index: Module.Decl.Index, storage_class: St |
| 535 | } | 532 | } |
| 536 | } | 533 | } |
| 537 | | 534 | |
| 538 | fn castToGeneric(cg: *CodeGen, type_id: Id, ptr_id: Id) !Id { | | |
| 539 | const target = cg.module.zcu.getTarget(); | | |
| 540 | if (target.cpu.has(.spirv, .generic_pointer)) { | | |
| 541 | const result_id = cg.module.allocId(); | | |
| 542 | try cg.body.emit(cg.module.gpa, .OpPtrCastToGeneric, .{ | | |
| 543 | .id_result_type = type_id, | | |
| 544 | .id_result = result_id, | | |
| 545 | .pointer = ptr_id, | | |
| 546 | }); | | |
| 547 | return result_id; | | |
| 548 | } | | |
| 549 | | | |
| 550 | return ptr_id; | | |
| 551 | } | | |
| 552 | | | |
| 553 | /// Start a new SPIR-V block, Emits the label of the new block, and stores which | 535 | /// Start a new SPIR-V block, Emits the label of the new block, and stores which |
| 554 | /// block we are currently generating. | 536 | /// block we are currently generating. |
| 555 | /// Note that there is no such thing as nested blocks like in ZIR or AIR, so we don't need to | 537 | /// Note that there is no such thing as nested blocks like in ZIR or AIR, so we don't need to |
| ... | @@ -1209,11 +1191,7 @@ fn constantNavRef(cg: *CodeGen, ty: Type, nav_index: InternPool.Nav.Index) !Id { | ... | @@ -1209,11 +1191,7 @@ fn constantNavRef(cg: *CodeGen, ty: Type, nav_index: InternPool.Nav.Index) !Id { |
| 1209 | | 1191 | |
| 1210 | const spv_decl_index = try cg.module.resolveNav(ip, nav_index); | 1192 | const spv_decl_index = try cg.module.resolveNav(ip, nav_index); |
| 1211 | const spv_decl = cg.module.declPtr(spv_decl_index); | 1193 | const spv_decl = cg.module.declPtr(spv_decl_index); |
| 1212 | | 1194 | assert(spv_decl.kind != .func); |
| 1213 | const decl_id = switch (spv_decl.kind) { | | |
| 1214 | .func => unreachable, // TODO: Is this possible? | | |
| 1215 | .global, .invocation_global => spv_decl.result_id, | | |
| 1216 | }; | | |
| 1217 | | 1195 | |
| 1218 | const storage_class = cg.module.storageClass(nav.getAddrspace()); | 1196 | const storage_class = cg.module.storageClass(nav.getAddrspace()); |
| 1219 | try cg.addFunctionDep(spv_decl_index, storage_class); | 1197 | try cg.addFunctionDep(spv_decl_index, storage_class); |
| ... | @@ -1221,23 +1199,18 @@ fn constantNavRef(cg: *CodeGen, ty: Type, nav_index: InternPool.Nav.Index) !Id { | ... | @@ -1221,23 +1199,18 @@ fn constantNavRef(cg: *CodeGen, ty: Type, nav_index: InternPool.Nav.Index) !Id { |
| 1221 | const nav_ty_id = try cg.resolveType(nav_ty, .indirect); | 1199 | const nav_ty_id = try cg.resolveType(nav_ty, .indirect); |
| 1222 | const decl_ptr_ty_id = try cg.module.ptrType(nav_ty_id, storage_class); | 1200 | const decl_ptr_ty_id = try cg.module.ptrType(nav_ty_id, storage_class); |
| 1223 | | 1201 | |
| 1224 | const ptr_id = switch (storage_class) { | | |
| 1225 | .generic => try cg.castToGeneric(decl_ptr_ty_id, decl_id), | | |
| 1226 | else => decl_id, | | |
| 1227 | }; | | |
| 1228 | | | |
| 1229 | if (decl_ptr_ty_id != ty_id) { | 1202 | if (decl_ptr_ty_id != ty_id) { |
| 1230 | // Differing pointer types, insert a cast. | 1203 | // Differing pointer types, insert a cast. |
| 1231 | const casted_ptr_id = cg.module.allocId(); | 1204 | const casted_ptr_id = cg.module.allocId(); |
| 1232 | try cg.body.emit(cg.module.gpa, .OpBitcast, .{ | 1205 | try cg.body.emit(cg.module.gpa, .OpBitcast, .{ |
| 1233 | .id_result_type = ty_id, | 1206 | .id_result_type = ty_id, |
| 1234 | .id_result = casted_ptr_id, | 1207 | .id_result = casted_ptr_id, |
| 1235 | .operand = ptr_id, | 1208 | .operand = spv_decl.result_id, |
| 1236 | }); | 1209 | }); |
| 1237 | return casted_ptr_id; | 1210 | return casted_ptr_id; |
| 1238 | } else { | | |
| 1239 | return ptr_id; | | |
| 1240 | } | 1211 | } |
| | 1212 | |
| | 1213 | return spv_decl.result_id; |
| 1241 | } | 1214 | } |
| 1242 | | 1215 | |
| 1243 | // Turn a Zig type's name into a cache reference. | 1216 | // Turn a Zig type's name into a cache reference. |
| ... | @@ -2120,28 +2093,7 @@ fn buildSelect(cg: *CodeGen, condition: Temporary, lhs: Temporary, rhs: Temporar | ... | @@ -2120,28 +2093,7 @@ fn buildSelect(cg: *CodeGen, condition: Temporary, lhs: Temporary, rhs: Temporar |
| 2120 | return v.finalize(result_ty, results); | 2093 | return v.finalize(result_ty, results); |
| 2121 | } | 2094 | } |
| 2122 | | 2095 | |
| 2123 | const CmpPredicate = enum { | 2096 | fn buildCmp(cg: *CodeGen, opcode: Opcode, lhs: Temporary, rhs: Temporary) !Temporary { |
| 2124 | l_eq, | | |
| 2125 | l_ne, | | |
| 2126 | i_ne, | | |
| 2127 | i_eq, | | |
| 2128 | s_lt, | | |
| 2129 | s_gt, | | |
| 2130 | s_le, | | |
| 2131 | s_ge, | | |
| 2132 | u_lt, | | |
| 2133 | u_gt, | | |
| 2134 | u_le, | | |
| 2135 | u_ge, | | |
| 2136 | f_oeq, | | |
| 2137 | f_une, | | |
| 2138 | f_olt, | | |
| 2139 | f_ole, | | |
| 2140 | f_ogt, | | |
| 2141 | f_oge, | | |
| 2142 | }; | | |
| 2143 | | | |
| 2144 | fn buildCmp(cg: *CodeGen, pred: CmpPredicate, lhs: Temporary, rhs: Temporary) !Temporary { | | |
| 2145 | const v = cg.vectorization(.{ lhs, rhs }); | 2097 | const v = cg.vectorization(.{ lhs, rhs }); |
| 2146 | const ops = v.components(); | 2098 | const ops = v.components(); |
| 2147 | const results = cg.module.allocIds(ops); | 2099 | const results = cg.module.allocIds(ops); |
| ... | @@ -2153,27 +2105,6 @@ fn buildCmp(cg: *CodeGen, pred: CmpPredicate, lhs: Temporary, rhs: Temporary) !T | ... | @@ -2153,27 +2105,6 @@ fn buildCmp(cg: *CodeGen, pred: CmpPredicate, lhs: Temporary, rhs: Temporary) !T |
| 2153 | const op_lhs = try v.prepare(cg, lhs); | 2105 | const op_lhs = try v.prepare(cg, lhs); |
| 2154 | const op_rhs = try v.prepare(cg, rhs); | 2106 | const op_rhs = try v.prepare(cg, rhs); |
| 2155 | | 2107 | |
| 2156 | const opcode: Opcode = switch (pred) { | | |
| 2157 | .l_eq => .OpLogicalEqual, | | |
| 2158 | .l_ne => .OpLogicalNotEqual, | | |
| 2159 | .i_eq => .OpIEqual, | | |
| 2160 | .i_ne => .OpINotEqual, | | |
| 2161 | .s_lt => .OpSLessThan, | | |
| 2162 | .s_gt => .OpSGreaterThan, | | |
| 2163 | .s_le => .OpSLessThanEqual, | | |
| 2164 | .s_ge => .OpSGreaterThanEqual, | | |
| 2165 | .u_lt => .OpULessThan, | | |
| 2166 | .u_gt => .OpUGreaterThan, | | |
| 2167 | .u_le => .OpULessThanEqual, | | |
| 2168 | .u_ge => .OpUGreaterThanEqual, | | |
| 2169 | .f_oeq => .OpFOrdEqual, | | |
| 2170 | .f_une => .OpFUnordNotEqual, | | |
| 2171 | .f_olt => .OpFOrdLessThan, | | |
| 2172 | .f_ole => .OpFOrdLessThanEqual, | | |
| 2173 | .f_ogt => .OpFOrdGreaterThan, | | |
| 2174 | .f_oge => .OpFOrdGreaterThanEqual, | | |
| 2175 | }; | | |
| 2176 | | | |
| 2177 | for (0..ops) |i| { | 2108 | for (0..ops) |i| { |
| 2178 | try cg.body.emitRaw(cg.module.gpa, opcode, 4); | 2109 | try cg.body.emitRaw(cg.module.gpa, opcode, 4); |
| 2179 | cg.body.writeOperand(Id, op_result_ty_id); | 2110 | cg.body.writeOperand(Id, op_result_ty_id); |
| ... | @@ -2278,7 +2209,10 @@ fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary { | ... | @@ -2278,7 +2209,10 @@ fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary { |
| 2278 | .log, | 2209 | .log, |
| 2279 | .log2, | 2210 | .log2, |
| 2280 | .log10, | 2211 | .log10, |
| 2281 | => return cg.todo("implement unary operation '{s}' for {s} os", .{ @tagName(op), @tagName(target.os.tag) }), | 2212 | => return cg.todo( |
| | 2213 | "implement unary operation '{s}' for {s} os", |
| | 2214 | .{ @tagName(op), @tagName(target.os.tag) }, |
| | 2215 | ), |
| 2282 | else => unreachable, | 2216 | else => unreachable, |
| 2283 | }, | 2217 | }, |
| 2284 | else => unreachable, | 2218 | else => unreachable, |
| ... | @@ -2298,40 +2232,8 @@ fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary { | ... | @@ -2298,40 +2232,8 @@ fn buildUnary(cg: *CodeGen, op: UnaryOp, operand: Temporary) !Temporary { |
| 2298 | return v.finalize(result_ty, results); | 2232 | return v.finalize(result_ty, results); |
| 2299 | } | 2233 | } |
| 2300 | | 2234 | |
| 2301 | const BinaryOp = enum { | 2235 | fn buildBinary(cg: *CodeGen, opcode: Opcode, lhs: Temporary, rhs: Temporary) !Temporary { |
| 2302 | i_add, | | |
| 2303 | f_add, | | |
| 2304 | i_sub, | | |
| 2305 | f_sub, | | |
| 2306 | i_mul, | | |
| 2307 | f_mul, | | |
| 2308 | s_div, | | |
| 2309 | u_div, | | |
| 2310 | f_div, | | |
| 2311 | s_rem, | | |
| 2312 | f_rem, | | |
| 2313 | s_mod, | | |
| 2314 | u_mod, | | |
| 2315 | f_mod, | | |
| 2316 | srl, | | |
| 2317 | sra, | | |
| 2318 | sll, | | |
| 2319 | bit_and, | | |
| 2320 | bit_or, | | |
| 2321 | bit_xor, | | |
| 2322 | f_max, | | |
| 2323 | s_max, | | |
| 2324 | u_max, | | |
| 2325 | f_min, | | |
| 2326 | s_min, | | |
| 2327 | u_min, | | |
| 2328 | l_and, | | |
| 2329 | l_or, | | |
| 2330 | }; | | |
| 2331 | | | |
| 2332 | fn buildBinary(cg: *CodeGen, op: BinaryOp, lhs: Temporary, rhs: Temporary) !Temporary { | | |
| 2333 | const zcu = cg.module.zcu; | 2236 | const zcu = cg.module.zcu; |
| 2334 | const target = cg.module.zcu.getTarget(); | | |
| 2335 | | 2237 | |
| 2336 | const v = cg.vectorization(.{ lhs, rhs }); | 2238 | const v = cg.vectorization(.{ lhs, rhs }); |
| 2337 | const ops = v.components(); | 2239 | const ops = v.components(); |
| ... | @@ -2344,73 +2246,12 @@ fn buildBinary(cg: *CodeGen, op: BinaryOp, lhs: Temporary, rhs: Temporary) !Temp | ... | @@ -2344,73 +2246,12 @@ fn buildBinary(cg: *CodeGen, op: BinaryOp, lhs: Temporary, rhs: Temporary) !Temp |
| 2344 | const op_lhs = try v.prepare(cg, lhs); | 2246 | const op_lhs = try v.prepare(cg, lhs); |
| 2345 | const op_rhs = try v.prepare(cg, rhs); | 2247 | const op_rhs = try v.prepare(cg, rhs); |
| 2346 | | 2248 | |
| 2347 | if (switch (op) { | 2249 | for (0..ops) |i| { |
| 2348 | .i_add => .OpIAdd, | 2250 | try cg.body.emitRaw(cg.module.gpa, opcode, 4); |
| 2349 | .f_add => .OpFAdd, | 2251 | cg.body.writeOperand(Id, op_result_ty_id); |
| 2350 | .i_sub => .OpISub, | 2252 | cg.body.writeOperand(Id, results.at(i)); |
| 2351 | .f_sub => .OpFSub, | 2253 | cg.body.writeOperand(Id, op_lhs.at(i)); |
| 2352 | .i_mul => .OpIMul, | 2254 | cg.body.writeOperand(Id, op_rhs.at(i)); |
| 2353 | .f_mul => .OpFMul, | | |
| 2354 | .s_div => .OpSDiv, | | |
| 2355 | .u_div => .OpUDiv, | | |
| 2356 | .f_div => .OpFDiv, | | |
| 2357 | .s_rem => .OpSRem, | | |
| 2358 | .f_rem => .OpFRem, | | |
| 2359 | .s_mod => .OpSMod, | | |
| 2360 | .u_mod => .OpUMod, | | |
| 2361 | .f_mod => .OpFMod, | | |
| 2362 | .srl => .OpShiftRightLogical, | | |
| 2363 | .sra => .OpShiftRightArithmetic, | | |
| 2364 | .sll => .OpShiftLeftLogical, | | |
| 2365 | .bit_and => .OpBitwiseAnd, | | |
| 2366 | .bit_or => .OpBitwiseOr, | | |
| 2367 | .bit_xor => .OpBitwiseXor, | | |
| 2368 | .l_and => .OpLogicalAnd, | | |
| 2369 | .l_or => .OpLogicalOr, | | |
| 2370 | else => @as(?Opcode, null), | | |
| 2371 | }) |opcode| { | | |
| 2372 | for (0..ops) |i| { | | |
| 2373 | try cg.body.emitRaw(cg.module.gpa, opcode, 4); | | |
| 2374 | cg.body.writeOperand(Id, op_result_ty_id); | | |
| 2375 | cg.body.writeOperand(Id, results.at(i)); | | |
| 2376 | cg.body.writeOperand(Id, op_lhs.at(i)); | | |
| 2377 | cg.body.writeOperand(Id, op_rhs.at(i)); | | |
| 2378 | } | | |
| 2379 | } else { | | |
| 2380 | const set = try cg.importExtendedSet(); | | |
| 2381 | | | |
| 2382 | // TODO: Put these numbers in some definition | | |
| 2383 | const extinst: u32 = switch (target.os.tag) { | | |
| 2384 | .opencl => switch (op) { | | |
| 2385 | .f_max => 27, // fmax | | |
| 2386 | .s_max => 156, // s_max | | |
| 2387 | .u_max => 157, // u_max | | |
| 2388 | .f_min => 28, // fmin | | |
| 2389 | .s_min => 158, // s_min | | |
| 2390 | .u_min => 159, // u_min | | |
| 2391 | else => unreachable, | | |
| 2392 | }, | | |
| 2393 | .vulkan, .opengl => switch (op) { | | |
| 2394 | .f_max => 40, // FMax | | |
| 2395 | .s_max => 42, // SMax | | |
| 2396 | .u_max => 41, // UMax | | |
| 2397 | .f_min => 37, // FMin | | |
| 2398 | .s_min => 39, // SMin | | |
| 2399 | .u_min => 38, // UMin | | |
| 2400 | else => unreachable, | | |
| 2401 | }, | | |
| 2402 | else => unreachable, | | |
| 2403 | }; | | |
| 2404 | | | |
| 2405 | for (0..ops) |i| { | | |
| 2406 | try cg.body.emit(cg.module.gpa, .OpExtInst, .{ | | |
| 2407 | .id_result_type = op_result_ty_id, | | |
| 2408 | .id_result = results.at(i), | | |
| 2409 | .set = set, | | |
| 2410 | .instruction = .{ .inst = extinst }, | | |
| 2411 | .id_ref_4 = &.{ op_lhs.at(i), op_rhs.at(i) }, | | |
| 2412 | }); | | |
| 2413 | } | | |
| 2414 | } | 2255 | } |
| 2415 | | 2256 | |
| 2416 | return v.finalize(result_ty, results); | 2257 | return v.finalize(result_ty, results); |
| ... | @@ -2420,10 +2261,7 @@ fn buildBinary(cg: *CodeGen, op: BinaryOp, lhs: Temporary, rhs: Temporary) !Temp | ... | @@ -2420,10 +2261,7 @@ fn buildBinary(cg: *CodeGen, op: BinaryOp, lhs: Temporary, rhs: Temporary) !Temp |
| 2420 | /// or OpIMul and s_mul_hi or u_mul_hi on OpenCL. | 2261 | /// or OpIMul and s_mul_hi or u_mul_hi on OpenCL. |
| 2421 | fn buildWideMul( | 2262 | fn buildWideMul( |
| 2422 | cg: *CodeGen, | 2263 | cg: *CodeGen, |
| 2423 | op: enum { | 2264 | signedness: std.builtin.Signedness, |
| 2424 | s_mul_extended, | | |
| 2425 | u_mul_extended, | | |
| 2426 | }, | | |
| 2427 | lhs: Temporary, | 2265 | lhs: Temporary, |
| 2428 | rhs: Temporary, | 2266 | rhs: Temporary, |
| 2429 | ) !struct { Temporary, Temporary } { | 2267 | ) !struct { Temporary, Temporary } { |
| ... | @@ -2450,9 +2288,9 @@ fn buildWideMul( | ... | @@ -2450,9 +2288,9 @@ fn buildWideMul( |
| 2450 | // OpUMulExtended. For these we will use the OpenCL s_mul_hi to compute the high-order bits | 2288 | // OpUMulExtended. For these we will use the OpenCL s_mul_hi to compute the high-order bits |
| 2451 | // instead. | 2289 | // instead. |
| 2452 | const set = try cg.importExtendedSet(); | 2290 | const set = try cg.importExtendedSet(); |
| 2453 | const overflow_inst: u32 = switch (op) { | 2291 | const overflow_inst: u32 = switch (signedness) { |
| 2454 | .s_mul_extended => 160, // s_mul_hi | 2292 | .signed => 160, // s_mul_hi |
| 2455 | .u_mul_extended => 203, // u_mul_hi | 2293 | .unsigned => 203, // u_mul_hi |
| 2456 | }; | 2294 | }; |
| 2457 | | 2295 | |
| 2458 | for (0..ops) |i| { | 2296 | for (0..ops) |i| { |
| ... | @@ -2481,9 +2319,9 @@ fn buildWideMul( | ... | @@ -2481,9 +2319,9 @@ fn buildWideMul( |
| 2481 | })); | 2319 | })); |
| 2482 | const op_result_ty_id = try cg.resolveType(op_result_ty, .direct); | 2320 | const op_result_ty_id = try cg.resolveType(op_result_ty, .direct); |
| 2483 | | 2321 | |
| 2484 | const opcode: Opcode = switch (op) { | 2322 | const opcode: Opcode = switch (signedness) { |
| 2485 | .s_mul_extended => .OpSMulExtended, | 2323 | .signed => .OpSMulExtended, |
| 2486 | .u_mul_extended => .OpUMulExtended, | 2324 | .unsigned => .OpUMulExtended, |
| 2487 | }; | 2325 | }; |
| 2488 | | 2326 | |
| 2489 | for (0..ops) |i| { | 2327 | for (0..ops) |i| { |
| ... | @@ -2718,7 +2556,7 @@ fn convertToDirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id { | ... | @@ -2718,7 +2556,7 @@ fn convertToDirect(cg: *CodeGen, ty: Type, operand_id: Id) !Id { |
| 2718 | }; | 2556 | }; |
| 2719 | | 2557 | |
| 2720 | const result = try cg.buildCmp( | 2558 | const result = try cg.buildCmp( |
| 2721 | .i_ne, | 2559 | .OpINotEqual, |
| 2722 | Temporary.init(operand_ty, operand_id), | 2560 | Temporary.init(operand_ty, operand_id), |
| 2723 | Temporary.init(.u1, false_id), | 2561 | Temporary.init(.u1, false_id), |
| 2724 | ); | 2562 | ); |
| ... | @@ -2817,9 +2655,9 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void { | ... | @@ -2817,9 +2655,9 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void { |
| 2817 | const air_tags = cg.air.instructions.items(.tag); | 2655 | const air_tags = cg.air.instructions.items(.tag); |
| 2818 | const maybe_result_id: ?Id = switch (air_tags[@intFromEnum(inst)]) { | 2656 | const maybe_result_id: ?Id = switch (air_tags[@intFromEnum(inst)]) { |
| 2819 | // zig fmt: off | 2657 | // zig fmt: off |
| 2820 | .add, .add_wrap, .add_optimized => try cg.airArithOp(inst, .f_add, .i_add, .i_add), | 2658 | .add, .add_wrap, .add_optimized => try cg.airArithOp(inst, .OpFAdd, .OpIAdd, .OpIAdd), |
| 2821 | .sub, .sub_wrap, .sub_optimized => try cg.airArithOp(inst, .f_sub, .i_sub, .i_sub), | 2659 | .sub, .sub_wrap, .sub_optimized => try cg.airArithOp(inst, .OpFSub, .OpISub, .OpISub), |
| 2822 | .mul, .mul_wrap, .mul_optimized => try cg.airArithOp(inst, .f_mul, .i_mul, .i_mul), | 2660 | .mul, .mul_wrap, .mul_optimized => try cg.airArithOp(inst, .OpFMul, .OpIMul, .OpIMul), |
| 2823 | | 2661 | |
| 2824 | .sqrt => try cg.airUnOpSimple(inst, .sqrt), | 2662 | .sqrt => try cg.airUnOpSimple(inst, .sqrt), |
| 2825 | .sin => try cg.airUnOpSimple(inst, .sin), | 2663 | .sin => try cg.airUnOpSimple(inst, .sin), |
| ... | @@ -2837,15 +2675,15 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void { | ... | @@ -2837,15 +2675,15 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void { |
| 2837 | .trunc_float => try cg.airUnOpSimple(inst, .trunc), | 2675 | .trunc_float => try cg.airUnOpSimple(inst, .trunc), |
| 2838 | .neg, .neg_optimized => try cg.airUnOpSimple(inst, .f_neg), | 2676 | .neg, .neg_optimized => try cg.airUnOpSimple(inst, .f_neg), |
| 2839 | | 2677 | |
| 2840 | .div_float, .div_float_optimized => try cg.airArithOp(inst, .f_div, .s_div, .u_div), | 2678 | .div_float, .div_float_optimized => try cg.airArithOp(inst, .OpFDiv, .OpSDiv, .OpUDiv), |
| 2841 | .div_floor, .div_floor_optimized => try cg.airDivFloor(inst), | 2679 | .div_floor, .div_floor_optimized => try cg.airDivFloor(inst), |
| 2842 | .div_trunc, .div_trunc_optimized => try cg.airDivTrunc(inst), | 2680 | .div_trunc, .div_trunc_optimized => try cg.airDivTrunc(inst), |
| 2843 | | 2681 | |
| 2844 | .rem, .rem_optimized => try cg.airArithOp(inst, .f_rem, .s_rem, .u_mod), | 2682 | .rem, .rem_optimized => try cg.airArithOp(inst, .OpFRem, .OpSRem, .OpUMod), |
| 2845 | .mod, .mod_optimized => try cg.airArithOp(inst, .f_mod, .s_mod, .u_mod), | 2683 | .mod, .mod_optimized => try cg.airArithOp(inst, .OpFMod, .OpSMod, .OpUMod), |
| 2846 | | 2684 | |
| 2847 | .add_with_overflow => try cg.airAddSubOverflow(inst, .i_add, .u_lt, .s_lt), | 2685 | .add_with_overflow => try cg.airAddSubOverflow(inst, .OpIAdd, .OpULessThan, .OpSLessThan), |
| 2848 | .sub_with_overflow => try cg.airAddSubOverflow(inst, .i_sub, .u_gt, .s_gt), | 2686 | .sub_with_overflow => try cg.airAddSubOverflow(inst, .OpISub, .OpUGreaterThan, .OpSGreaterThan), |
| 2849 | .mul_with_overflow => try cg.airMulOverflow(inst), | 2687 | .mul_with_overflow => try cg.airMulOverflow(inst), |
| 2850 | .shl_with_overflow => try cg.airShlOverflow(inst), | 2688 | .shl_with_overflow => try cg.airShlOverflow(inst), |
| 2851 | | 2689 | |
| ... | @@ -2864,14 +2702,14 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void { | ... | @@ -2864,14 +2702,14 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void { |
| 2864 | .ptr_add => try cg.airPtrAdd(inst), | 2702 | .ptr_add => try cg.airPtrAdd(inst), |
| 2865 | .ptr_sub => try cg.airPtrSub(inst), | 2703 | .ptr_sub => try cg.airPtrSub(inst), |
| 2866 | | 2704 | |
| 2867 | .bit_and => try cg.airBinOpSimple(inst, .bit_and), | 2705 | .bit_and => try cg.airBinOpSimple(inst, .OpBitwiseAnd), |
| 2868 | .bit_or => try cg.airBinOpSimple(inst, .bit_or), | 2706 | .bit_or => try cg.airBinOpSimple(inst, .OpBitwiseOr), |
| 2869 | .xor => try cg.airBinOpSimple(inst, .bit_xor), | 2707 | .xor => try cg.airBinOpSimple(inst, .OpBitwiseXor), |
| 2870 | .bool_and => try cg.airBinOpSimple(inst, .l_and), | 2708 | .bool_and => try cg.airBinOpSimple(inst, .OpLogicalAnd), |
| 2871 | .bool_or => try cg.airBinOpSimple(inst, .l_or), | 2709 | .bool_or => try cg.airBinOpSimple(inst, .OpLogicalOr), |
| 2872 | | 2710 | |
| 2873 | .shl, .shl_exact => try cg.airShift(inst, .sll, .sll), | 2711 | .shl, .shl_exact => try cg.airShift(inst, .OpShiftLeftLogical, .OpShiftLeftLogical), |
| 2874 | .shr, .shr_exact => try cg.airShift(inst, .srl, .sra), | 2712 | .shr, .shr_exact => try cg.airShift(inst, .OpShiftRightLogical, .OpShiftRightArithmetic), |
| 2875 | | 2713 | |
| 2876 | .min => try cg.airMinMax(inst, .min), | 2714 | .min => try cg.airMinMax(inst, .min), |
| 2877 | .max => try cg.airMinMax(inst, .max), | 2715 | .max => try cg.airMinMax(inst, .max), |
| ... | @@ -2983,7 +2821,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void { | ... | @@ -2983,7 +2821,7 @@ fn genInst(cg: *CodeGen, inst: Air.Inst.Index) Error!void { |
| 2983 | try cg.inst_results.putNoClobber(gpa, inst, result_id); | 2821 | try cg.inst_results.putNoClobber(gpa, inst, result_id); |
| 2984 | } | 2822 | } |
| 2985 | | 2823 | |
| 2986 | fn airBinOpSimple(cg: *CodeGen, inst: Air.Inst.Index, op: BinaryOp) !?Id { | 2824 | fn airBinOpSimple(cg: *CodeGen, inst: Air.Inst.Index, op: Opcode) !?Id { |
| 2987 | const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 2825 | const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 2988 | const lhs = try cg.temporary(bin_op.lhs); | 2826 | const lhs = try cg.temporary(bin_op.lhs); |
| 2989 | const rhs = try cg.temporary(bin_op.rhs); | 2827 | const rhs = try cg.temporary(bin_op.rhs); |
| ... | @@ -2992,7 +2830,7 @@ fn airBinOpSimple(cg: *CodeGen, inst: Air.Inst.Index, op: BinaryOp) !?Id { | ... | @@ -2992,7 +2830,7 @@ fn airBinOpSimple(cg: *CodeGen, inst: Air.Inst.Index, op: BinaryOp) !?Id { |
| 2992 | return try result.materialize(cg); | 2830 | return try result.materialize(cg); |
| 2993 | } | 2831 | } |
| 2994 | | 2832 | |
| 2995 | fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: BinaryOp, signed: BinaryOp) !?Id { | 2833 | fn airShift(cg: *CodeGen, inst: Air.Inst.Index, unsigned: Opcode, signed: Opcode) !?Id { |
| 2996 | const zcu = cg.module.zcu; | 2834 | const zcu = cg.module.zcu; |
| 2997 | const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 2835 | const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 2998 | | 2836 | |
| ... | @@ -3042,28 +2880,77 @@ fn airMinMax(cg: *CodeGen, inst: Air.Inst.Index, op: MinMax) !?Id { | ... | @@ -3042,28 +2880,77 @@ fn airMinMax(cg: *CodeGen, inst: Air.Inst.Index, op: MinMax) !?Id { |
| 3042 | } | 2880 | } |
| 3043 | | 2881 | |
| 3044 | fn minMax(cg: *CodeGen, lhs: Temporary, rhs: Temporary, op: MinMax) !Temporary { | 2882 | fn minMax(cg: *CodeGen, lhs: Temporary, rhs: Temporary, op: MinMax) !Temporary { |
| | 2883 | const zcu = cg.module.zcu; |
| | 2884 | const target = zcu.getTarget(); |
| 3045 | const info = cg.arithmeticTypeInfo(lhs.ty); | 2885 | const info = cg.arithmeticTypeInfo(lhs.ty); |
| 3046 | | 2886 | |
| 3047 | const binop: BinaryOp = switch (info.class) { | 2887 | const v = cg.vectorization(.{ lhs, rhs }); |
| 3048 | .float => switch (op) { | 2888 | const ops = v.components(); |
| 3049 | .min => .f_min, | 2889 | const results = cg.module.allocIds(ops); |
| 3050 | .max => .f_max, | 2890 | |
| | 2891 | const op_result_ty = lhs.ty.scalarType(zcu); |
| | 2892 | const op_result_ty_id = try cg.resolveType(op_result_ty, .direct); |
| | 2893 | const result_ty = try v.resultType(cg, lhs.ty); |
| | 2894 | |
| | 2895 | const op_lhs = try v.prepare(cg, lhs); |
| | 2896 | const op_rhs = try v.prepare(cg, rhs); |
| | 2897 | |
| | 2898 | const ext_inst: u32 = switch (target.os.tag) { |
| | 2899 | .opencl => switch (info.class) { |
| | 2900 | .float => switch (op) { |
| | 2901 | .min => 28, // fmin |
| | 2902 | .max => 27, // fmax |
| | 2903 | }, |
| | 2904 | .integer, |
| | 2905 | .strange_integer, |
| | 2906 | .composite_integer, |
| | 2907 | => switch (info.signedness) { |
| | 2908 | .signed => switch (op) { |
| | 2909 | .min => 158, // s_min |
| | 2910 | .max => 156, // s_max |
| | 2911 | }, |
| | 2912 | .unsigned => switch (op) { |
| | 2913 | .min => 159, // u_min |
| | 2914 | .max => 157, // u_max |
| | 2915 | }, |
| | 2916 | }, |
| | 2917 | .bool => unreachable, |
| 3051 | }, | 2918 | }, |
| 3052 | .integer, .strange_integer => switch (info.signedness) { | 2919 | .vulkan, .opengl => switch (info.class) { |
| 3053 | .signed => switch (op) { | 2920 | .float => switch (op) { |
| 3054 | .min => .s_min, | 2921 | .min => 37, // FMin |
| 3055 | .max => .s_max, | 2922 | .max => 40, // FMax |
| 3056 | }, | 2923 | }, |
| 3057 | .unsigned => switch (op) { | 2924 | .integer, |
| 3058 | .min => .u_min, | 2925 | .strange_integer, |
| 3059 | .max => .u_max, | 2926 | .composite_integer, |
| | 2927 | => switch (info.signedness) { |
| | 2928 | .signed => switch (op) { |
| | 2929 | .min => 39, // SMin |
| | 2930 | .max => 42, // SMax |
| | 2931 | }, |
| | 2932 | .unsigned => switch (op) { |
| | 2933 | .min => 38, // UMin |
| | 2934 | .max => 41, // UMax |
| | 2935 | }, |
| 3060 | }, | 2936 | }, |
| | 2937 | .bool => unreachable, |
| 3061 | }, | 2938 | }, |
| 3062 | .composite_integer => unreachable, // TODO | 2939 | else => unreachable, |
| 3063 | .bool => unreachable, | | |
| 3064 | }; | 2940 | }; |
| 3065 | | 2941 | |
| 3066 | return try cg.buildBinary(binop, lhs, rhs); | 2942 | const set = try cg.importExtendedSet(); |
| | 2943 | for (0..ops) |i| { |
| | 2944 | try cg.body.emit(cg.module.gpa, .OpExtInst, .{ |
| | 2945 | .id_result_type = op_result_ty_id, |
| | 2946 | .id_result = results.at(i), |
| | 2947 | .set = set, |
| | 2948 | .instruction = .{ .inst = ext_inst }, |
| | 2949 | .id_ref_4 = &.{ op_lhs.at(i), op_rhs.at(i) }, |
| | 2950 | }); |
| | 2951 | } |
| | 2952 | |
| | 2953 | return v.finalize(result_ty, results); |
| 3067 | } | 2954 | } |
| 3068 | | 2955 | |
| 3069 | /// This function normalizes values to a canonical representation | 2956 | /// This function normalizes values to a canonical representation |
| ... | @@ -3083,14 +2970,14 @@ fn normalize(cg: *CodeGen, value: Temporary, info: ArithmeticTypeInfo) !Temporar | ... | @@ -3083,14 +2970,14 @@ fn normalize(cg: *CodeGen, value: Temporary, info: ArithmeticTypeInfo) !Temporar |
| 3083 | .unsigned => { | 2970 | .unsigned => { |
| 3084 | const mask_value = if (info.bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @as(u6, @intCast(info.bits))) - 1; | 2971 | const mask_value = if (info.bits == 64) 0xFFFF_FFFF_FFFF_FFFF else (@as(u64, 1) << @as(u6, @intCast(info.bits))) - 1; |
| 3085 | const mask_id = try cg.constInt(ty.scalarType(zcu), mask_value); | 2972 | const mask_id = try cg.constInt(ty.scalarType(zcu), mask_value); |
| 3086 | return try cg.buildBinary(.bit_and, value, Temporary.init(ty.scalarType(zcu), mask_id)); | 2973 | return try cg.buildBinary(.OpBitwiseAnd, value, Temporary.init(ty.scalarType(zcu), mask_id)); |
| 3087 | }, | 2974 | }, |
| 3088 | .signed => { | 2975 | .signed => { |
| 3089 | // Shift left and right so that we can copy the sight bit that way. | 2976 | // Shift left and right so that we can copy the sight bit that way. |
| 3090 | const shift_amt_id = try cg.constInt(ty.scalarType(zcu), info.backing_bits - info.bits); | 2977 | const shift_amt_id = try cg.constInt(ty.scalarType(zcu), info.backing_bits - info.bits); |
| 3091 | const shift_amt: Temporary = .init(ty.scalarType(zcu), shift_amt_id); | 2978 | const shift_amt: Temporary = .init(ty.scalarType(zcu), shift_amt_id); |
| 3092 | const left = try cg.buildBinary(.sll, value, shift_amt); | 2979 | const left = try cg.buildBinary(.OpShiftLeftLogical, value, shift_amt); |
| 3093 | return try cg.buildBinary(.sra, left, shift_amt); | 2980 | return try cg.buildBinary(.OpShiftRightArithmetic, left, shift_amt); |
| 3094 | }, | 2981 | }, |
| 3095 | }, | 2982 | }, |
| 3096 | } | 2983 | } |
| ... | @@ -3108,7 +2995,7 @@ fn airDivFloor(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | ... | @@ -3108,7 +2995,7 @@ fn airDivFloor(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 3108 | .integer, .strange_integer => { | 2995 | .integer, .strange_integer => { |
| 3109 | switch (info.signedness) { | 2996 | switch (info.signedness) { |
| 3110 | .unsigned => { | 2997 | .unsigned => { |
| 3111 | const result = try cg.buildBinary(.u_div, lhs, rhs); | 2998 | const result = try cg.buildBinary(.OpUDiv, lhs, rhs); |
| 3112 | return try result.materialize(cg); | 2999 | return try result.materialize(cg); |
| 3113 | }, | 3000 | }, |
| 3114 | .signed => {}, | 3001 | .signed => {}, |
| ... | @@ -3118,26 +3005,26 @@ fn airDivFloor(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | ... | @@ -3118,26 +3005,26 @@ fn airDivFloor(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 3118 | // (a / b) - (a % b != 0 && a < 0 != b < 0); | 3005 | // (a / b) - (a % b != 0 && a < 0 != b < 0); |
| 3119 | // There shouldn't be any overflow issues. | 3006 | // There shouldn't be any overflow issues. |
| 3120 | | 3007 | |
| 3121 | const div = try cg.buildBinary(.s_div, lhs, rhs); | 3008 | const div = try cg.buildBinary(.OpSDiv, lhs, rhs); |
| 3122 | const rem = try cg.buildBinary(.s_rem, lhs, rhs); | 3009 | const rem = try cg.buildBinary(.OpSRem, lhs, rhs); |
| 3123 | | 3010 | |
| 3124 | const zero: Temporary = .init(lhs.ty, try cg.constInt(lhs.ty, 0)); | 3011 | const zero: Temporary = .init(lhs.ty, try cg.constInt(lhs.ty, 0)); |
| 3125 | | 3012 | |
| 3126 | const rem_is_not_zero = try cg.buildCmp(.i_ne, rem, zero); | 3013 | const rem_is_not_zero = try cg.buildCmp(.OpINotEqual, rem, zero); |
| 3127 | | 3014 | |
| 3128 | const result_negative = try cg.buildCmp( | 3015 | const result_negative = try cg.buildCmp( |
| 3129 | .l_ne, | 3016 | .OpLogicalNotEqual, |
| 3130 | try cg.buildCmp(.s_lt, lhs, zero), | 3017 | try cg.buildCmp(.OpSLessThan, lhs, zero), |
| 3131 | try cg.buildCmp(.s_lt, rhs, zero), | 3018 | try cg.buildCmp(.OpSLessThan, rhs, zero), |
| 3132 | ); | 3019 | ); |
| 3133 | const rem_is_not_zero_and_result_is_negative = try cg.buildBinary( | 3020 | const rem_is_not_zero_and_result_is_negative = try cg.buildBinary( |
| 3134 | .l_and, | 3021 | .OpLogicalAnd, |
| 3135 | rem_is_not_zero, | 3022 | rem_is_not_zero, |
| 3136 | result_negative, | 3023 | result_negative, |
| 3137 | ); | 3024 | ); |
| 3138 | | 3025 | |
| 3139 | const result = try cg.buildBinary( | 3026 | const result = try cg.buildBinary( |
| 3140 | .i_sub, | 3027 | .OpISub, |
| 3141 | div, | 3028 | div, |
| 3142 | try cg.intFromBool2(rem_is_not_zero_and_result_is_negative, div.ty), | 3029 | try cg.intFromBool2(rem_is_not_zero_and_result_is_negative, div.ty), |
| 3143 | ); | 3030 | ); |
| ... | @@ -3145,7 +3032,7 @@ fn airDivFloor(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | ... | @@ -3145,7 +3032,7 @@ fn airDivFloor(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 3145 | return try result.materialize(cg); | 3032 | return try result.materialize(cg); |
| 3146 | }, | 3033 | }, |
| 3147 | .float => { | 3034 | .float => { |
| 3148 | const div = try cg.buildBinary(.f_div, lhs, rhs); | 3035 | const div = try cg.buildBinary(.OpFDiv, lhs, rhs); |
| 3149 | const result = try cg.buildUnary(.floor, div); | 3036 | const result = try cg.buildUnary(.floor, div); |
| 3150 | return try result.materialize(cg); | 3037 | return try result.materialize(cg); |
| 3151 | }, | 3038 | }, |
| ... | @@ -3164,16 +3051,16 @@ fn airDivTrunc(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | ... | @@ -3164,16 +3051,16 @@ fn airDivTrunc(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 3164 | .composite_integer => unreachable, // TODO | 3051 | .composite_integer => unreachable, // TODO |
| 3165 | .integer, .strange_integer => switch (info.signedness) { | 3052 | .integer, .strange_integer => switch (info.signedness) { |
| 3166 | .unsigned => { | 3053 | .unsigned => { |
| 3167 | const result = try cg.buildBinary(.u_div, lhs, rhs); | 3054 | const result = try cg.buildBinary(.OpUDiv, lhs, rhs); |
| 3168 | return try result.materialize(cg); | 3055 | return try result.materialize(cg); |
| 3169 | }, | 3056 | }, |
| 3170 | .signed => { | 3057 | .signed => { |
| 3171 | const result = try cg.buildBinary(.s_div, lhs, rhs); | 3058 | const result = try cg.buildBinary(.OpSDiv, lhs, rhs); |
| 3172 | return try result.materialize(cg); | 3059 | return try result.materialize(cg); |
| 3173 | }, | 3060 | }, |
| 3174 | }, | 3061 | }, |
| 3175 | .float => { | 3062 | .float => { |
| 3176 | const div = try cg.buildBinary(.f_div, lhs, rhs); | 3063 | const div = try cg.buildBinary(.OpFDiv, lhs, rhs); |
| 3177 | const result = try cg.buildUnary(.trunc, div); | 3064 | const result = try cg.buildUnary(.trunc, div); |
| 3178 | return try result.materialize(cg); | 3065 | return try result.materialize(cg); |
| 3179 | }, | 3066 | }, |
| ... | @@ -3191,9 +3078,9 @@ fn airUnOpSimple(cg: *CodeGen, inst: Air.Inst.Index, op: UnaryOp) !?Id { | ... | @@ -3191,9 +3078,9 @@ fn airUnOpSimple(cg: *CodeGen, inst: Air.Inst.Index, op: UnaryOp) !?Id { |
| 3191 | fn airArithOp( | 3078 | fn airArithOp( |
| 3192 | cg: *CodeGen, | 3079 | cg: *CodeGen, |
| 3193 | inst: Air.Inst.Index, | 3080 | inst: Air.Inst.Index, |
| 3194 | comptime fop: BinaryOp, | 3081 | comptime fop: Opcode, |
| 3195 | comptime sop: BinaryOp, | 3082 | comptime sop: Opcode, |
| 3196 | comptime uop: BinaryOp, | 3083 | comptime uop: Opcode, |
| 3197 | ) !?Id { | 3084 | ) !?Id { |
| 3198 | const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; | 3085 | const bin_op = cg.air.instructions.items(.data)[@intFromEnum(inst)].bin_op; |
| 3199 | | 3086 | |
| ... | @@ -3253,11 +3140,11 @@ fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary { | ... | @@ -3253,11 +3140,11 @@ fn abs(cg: *CodeGen, result_ty: Type, value: Temporary) !Temporary { |
| 3253 | fn airAddSubOverflow( | 3140 | fn airAddSubOverflow( |
| 3254 | cg: *CodeGen, | 3141 | cg: *CodeGen, |
| 3255 | inst: Air.Inst.Index, | 3142 | inst: Air.Inst.Index, |
| 3256 | comptime add: BinaryOp, | 3143 | comptime add: Opcode, |
| 3257 | comptime ucmp: CmpPredicate, | 3144 | u_opcode: Opcode, |
| 3258 | comptime scmp: CmpPredicate, | 3145 | s_opcode: Opcode, |
| 3259 | ) !?Id { | 3146 | ) !?Id { |
| 3260 | _ = scmp; | 3147 | _ = s_opcode; |
| 3261 | // Note: OpIAddCarry and OpISubBorrow are not really useful here: For unsigned numbers, | 3148 | // Note: OpIAddCarry and OpISubBorrow are not really useful here: For unsigned numbers, |
| 3262 | // there is in both cases only one extra operation required. For signed operations, | 3149 | // there is in both cases only one extra operation required. For signed operations, |
| 3263 | // the overflow bit is set then going from 0x80.. to 0x00.., but this doesn't actually | 3150 | // the overflow bit is set then going from 0x80.. to 0x00.., but this doesn't actually |
| ... | @@ -3285,7 +3172,7 @@ fn airAddSubOverflow( | ... | @@ -3285,7 +3172,7 @@ fn airAddSubOverflow( |
| 3285 | const overflowed = switch (info.signedness) { | 3172 | const overflowed = switch (info.signedness) { |
| 3286 | // Overflow happened if the result is smaller than either of the operands. It doesn't matter which. | 3173 | // Overflow happened if the result is smaller than either of the operands. It doesn't matter which. |
| 3287 | // For subtraction the conditions need to be swapped. | 3174 | // For subtraction the conditions need to be swapped. |
| 3288 | .unsigned => try cg.buildCmp(ucmp, result, lhs), | 3175 | .unsigned => try cg.buildCmp(u_opcode, result, lhs), |
| 3289 | // For signed operations, we check the signs of the operands and the result. | 3176 | // For signed operations, we check the signs of the operands and the result. |
| 3290 | .signed => blk: { | 3177 | .signed => blk: { |
| 3291 | // Signed overflow detection using the sign bits of the operands and the result. | 3178 | // Signed overflow detection using the sign bits of the operands and the result. |
| ... | @@ -3297,19 +3184,19 @@ fn airAddSubOverflow( | ... | @@ -3297,19 +3184,19 @@ fn airAddSubOverflow( |
| 3297 | // (sign(a) != sign(b)) && (sign(a) != sign(result)) | 3184 | // (sign(a) != sign(b)) && (sign(a) != sign(result)) |
| 3298 | const zero: Temporary = .init(rhs.ty, try cg.constInt(rhs.ty, 0)); | 3185 | const zero: Temporary = .init(rhs.ty, try cg.constInt(rhs.ty, 0)); |
| 3299 | | 3186 | |
| 3300 | const lhs_is_neg = try cg.buildCmp(.s_lt, lhs, zero); | 3187 | const lhs_is_neg = try cg.buildCmp(.OpSLessThan, lhs, zero); |
| 3301 | const rhs_is_neg = try cg.buildCmp(.s_lt, rhs, zero); | 3188 | const rhs_is_neg = try cg.buildCmp(.OpSLessThan, rhs, zero); |
| 3302 | const result_is_neg = try cg.buildCmp(.s_lt, result, zero); | 3189 | const result_is_neg = try cg.buildCmp(.OpSLessThan, result, zero); |
| 3303 | | 3190 | |
| 3304 | const signs_match = try cg.buildCmp(.l_eq, lhs_is_neg, rhs_is_neg); | 3191 | const signs_match = try cg.buildCmp(.OpLogicalEqual, lhs_is_neg, rhs_is_neg); |
| 3305 | const result_sign_differs = try cg.buildCmp(.l_ne, lhs_is_neg, result_is_neg); | 3192 | const result_sign_differs = try cg.buildCmp(.OpLogicalNotEqual, lhs_is_neg, result_is_neg); |
| 3306 | | 3193 | |
| 3307 | const overflow_condition = if (add == .i_add) | 3194 | const overflow_condition = if (add == .OpIAdd) |
| 3308 | signs_match | 3195 | signs_match |
| 3309 | else // .i_sub | 3196 | else // .OpISub |
| 3310 | try cg.buildUnary(.l_not, signs_match); | 3197 | try cg.buildUnary(.l_not, signs_match); |
| 3311 | | 3198 | |
| 3312 | break :blk try cg.buildBinary(.l_and, overflow_condition, result_sign_differs); | 3199 | break :blk try cg.buildCmp(.OpLogicalAnd, overflow_condition, result_sign_differs); |
| 3313 | }, | 3200 | }, |
| 3314 | }; | 3201 | }; |
| 3315 | | 3202 | |
| ... | @@ -3361,23 +3248,23 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | ... | @@ -3361,23 +3248,23 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 3361 | const casted_lhs = try cg.buildConvert(op_ty, lhs); | 3248 | const casted_lhs = try cg.buildConvert(op_ty, lhs); |
| 3362 | const casted_rhs = try cg.buildConvert(op_ty, rhs); | 3249 | const casted_rhs = try cg.buildConvert(op_ty, rhs); |
| 3363 | | 3250 | |
| 3364 | const full_result = try cg.buildBinary(.i_mul, casted_lhs, casted_rhs); | 3251 | const full_result = try cg.buildBinary(.OpIMul, casted_lhs, casted_rhs); |
| 3365 | | 3252 | |
| 3366 | const low_bits = try cg.buildConvert(lhs.ty, full_result); | 3253 | const low_bits = try cg.buildConvert(lhs.ty, full_result); |
| 3367 | const result = try cg.normalize(low_bits, info); | 3254 | const result = try cg.normalize(low_bits, info); |
| 3368 | | 3255 | |
| 3369 | // Shift the result bits away to get the overflow bits. | 3256 | // Shift the result bits away to get the overflow bits. |
| 3370 | const shift: Temporary = .init(full_result.ty, try cg.constInt(full_result.ty, info.bits)); | 3257 | const shift: Temporary = .init(full_result.ty, try cg.constInt(full_result.ty, info.bits)); |
| 3371 | const overflow = try cg.buildBinary(.srl, full_result, shift); | 3258 | const overflow = try cg.buildBinary(.OpShiftRightLogical, full_result, shift); |
| 3372 | | 3259 | |
| 3373 | // Directly check if its zero in the op_ty without converting first. | 3260 | // Directly check if its zero in the op_ty without converting first. |
| 3374 | const zero: Temporary = .init(full_result.ty, try cg.constInt(full_result.ty, 0)); | 3261 | const zero: Temporary = .init(full_result.ty, try cg.constInt(full_result.ty, 0)); |
| 3375 | const overflowed = try cg.buildCmp(.i_ne, zero, overflow); | 3262 | const overflowed = try cg.buildCmp(.OpINotEqual, zero, overflow); |
| 3376 | | 3263 | |
| 3377 | break :blk .{ result, overflowed }; | 3264 | break :blk .{ result, overflowed }; |
| 3378 | } | 3265 | } |
| 3379 | | 3266 | |
| 3380 | const low_bits, const high_bits = try cg.buildWideMul(.u_mul_extended, lhs, rhs); | 3267 | const low_bits, const high_bits = try cg.buildWideMul(.unsigned, lhs, rhs); |
| 3381 | | 3268 | |
| 3382 | // Truncate the result, if required. | 3269 | // Truncate the result, if required. |
| 3383 | const result = try cg.normalize(low_bits, info); | 3270 | const result = try cg.normalize(low_bits, info); |
| ... | @@ -3386,17 +3273,17 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | ... | @@ -3386,17 +3273,17 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 3386 | // high bits of the low word of the result (those outside the range of the | 3273 | // high bits of the low word of the result (those outside the range of the |
| 3387 | // int) are nonzero. | 3274 | // int) are nonzero. |
| 3388 | const zero: Temporary = .init(lhs.ty, try cg.constInt(lhs.ty, 0)); | 3275 | const zero: Temporary = .init(lhs.ty, try cg.constInt(lhs.ty, 0)); |
| 3389 | const high_overflowed = try cg.buildCmp(.i_ne, zero, high_bits); | 3276 | const high_overflowed = try cg.buildCmp(.OpINotEqual, zero, high_bits); |
| 3390 | | 3277 | |
| 3391 | // If no overflow bits in low_bits, no extra work needs to be done. | 3278 | // If no overflow bits in low_bits, no extra work needs to be done. |
| 3392 | if (info.backing_bits == info.bits) break :blk .{ result, high_overflowed }; | 3279 | if (info.backing_bits == info.bits) break :blk .{ result, high_overflowed }; |
| 3393 | | 3280 | |
| 3394 | // Shift the result bits away to get the overflow bits. | 3281 | // Shift the result bits away to get the overflow bits. |
| 3395 | const shift: Temporary = .init(lhs.ty, try cg.constInt(lhs.ty, info.bits)); | 3282 | const shift: Temporary = .init(lhs.ty, try cg.constInt(lhs.ty, info.bits)); |
| 3396 | const low_overflow = try cg.buildBinary(.srl, low_bits, shift); | 3283 | const low_overflow = try cg.buildBinary(.OpShiftRightLogical, low_bits, shift); |
| 3397 | const low_overflowed = try cg.buildCmp(.i_ne, zero, low_overflow); | 3284 | const low_overflowed = try cg.buildCmp(.OpINotEqual, zero, low_overflow); |
| 3398 | | 3285 | |
| 3399 | const overflowed = try cg.buildBinary(.l_or, low_overflowed, high_overflowed); | 3286 | const overflowed = try cg.buildCmp(.OpLogicalOr, low_overflowed, high_overflowed); |
| 3400 | | 3287 | |
| 3401 | break :blk .{ result, overflowed }; | 3288 | break :blk .{ result, overflowed }; |
| 3402 | }, | 3289 | }, |
| ... | @@ -3412,16 +3299,16 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | ... | @@ -3412,16 +3299,16 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 3412 | // (lhs > 0 && rhs < 0) || (lhs < 0 && rhs > 0) | 3299 | // (lhs > 0 && rhs < 0) || (lhs < 0 && rhs > 0) |
| 3413 | | 3300 | |
| 3414 | const zero: Temporary = .init(lhs.ty, try cg.constInt(lhs.ty, 0)); | 3301 | const zero: Temporary = .init(lhs.ty, try cg.constInt(lhs.ty, 0)); |
| 3415 | const lhs_negative = try cg.buildCmp(.s_lt, lhs, zero); | 3302 | const lhs_negative = try cg.buildCmp(.OpSLessThan, lhs, zero); |
| 3416 | const rhs_negative = try cg.buildCmp(.s_lt, rhs, zero); | 3303 | const rhs_negative = try cg.buildCmp(.OpSLessThan, rhs, zero); |
| 3417 | const lhs_positive = try cg.buildCmp(.s_gt, lhs, zero); | 3304 | const lhs_positive = try cg.buildCmp(.OpSGreaterThan, lhs, zero); |
| 3418 | const rhs_positive = try cg.buildCmp(.s_gt, rhs, zero); | 3305 | const rhs_positive = try cg.buildCmp(.OpSGreaterThan, rhs, zero); |
| 3419 | | 3306 | |
| 3420 | // Set to `true` if we expect -1. | 3307 | // Set to `true` if we expect -1. |
| 3421 | const expected_overflow_bit = try cg.buildBinary( | 3308 | const expected_overflow_bit = try cg.buildBinary( |
| 3422 | .l_or, | 3309 | .OpLogicalOr, |
| 3423 | try cg.buildBinary(.l_and, lhs_positive, rhs_negative), | 3310 | try cg.buildCmp(.OpLogicalAnd, lhs_positive, rhs_negative), |
| 3424 | try cg.buildBinary(.l_and, lhs_negative, rhs_positive), | 3311 | try cg.buildCmp(.OpLogicalAnd, lhs_negative, rhs_positive), |
| 3425 | ); | 3312 | ); |
| 3426 | | 3313 | |
| 3427 | if (maybe_op_ty_bits) |op_ty_bits| { | 3314 | if (maybe_op_ty_bits) |op_ty_bits| { |
| ... | @@ -3430,7 +3317,7 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | ... | @@ -3430,7 +3317,7 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 3430 | const casted_lhs = try cg.buildConvert(op_ty, lhs); | 3317 | const casted_lhs = try cg.buildConvert(op_ty, lhs); |
| 3431 | const casted_rhs = try cg.buildConvert(op_ty, rhs); | 3318 | const casted_rhs = try cg.buildConvert(op_ty, rhs); |
| 3432 | | 3319 | |
| 3433 | const full_result = try cg.buildBinary(.i_mul, casted_lhs, casted_rhs); | 3320 | const full_result = try cg.buildBinary(.OpIMul, casted_lhs, casted_rhs); |
| 3434 | | 3321 | |
| 3435 | // Truncate to the result type. | 3322 | // Truncate to the result type. |
| 3436 | const low_bits = try cg.buildConvert(lhs.ty, full_result); | 3323 | const low_bits = try cg.buildConvert(lhs.ty, full_result); |
| ... | @@ -3443,18 +3330,18 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | ... | @@ -3443,18 +3330,18 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 3443 | const shift: Temporary = .init(full_result.ty, try cg.constInt(full_result.ty, info.bits - 1)); | 3330 | const shift: Temporary = .init(full_result.ty, try cg.constInt(full_result.ty, info.bits - 1)); |
| 3444 | // Use SRA so that any sign bits are duplicated. Now we can just check if ALL bits are set | 3331 | // Use SRA so that any sign bits are duplicated. Now we can just check if ALL bits are set |
| 3445 | // for negative cases. | 3332 | // for negative cases. |
| 3446 | const overflow = try cg.buildBinary(.sra, full_result, shift); | 3333 | const overflow = try cg.buildBinary(.OpShiftRightArithmetic, full_result, shift); |
| 3447 | | 3334 | |
| 3448 | const long_all_set: Temporary = .init(full_result.ty, try cg.constInt(full_result.ty, -1)); | 3335 | const long_all_set: Temporary = .init(full_result.ty, try cg.constInt(full_result.ty, -1)); |
| 3449 | const long_zero: Temporary = .init(full_result.ty, try cg.constInt(full_result.ty, 0)); | 3336 | const long_zero: Temporary = .init(full_result.ty, try cg.constInt(full_result.ty, 0)); |
| 3450 | const mask = try cg.buildSelect(expected_overflow_bit, long_all_set, long_zero); | 3337 | const mask = try cg.buildSelect(expected_overflow_bit, long_all_set, long_zero); |
| 3451 | | 3338 | |
| 3452 | const overflowed = try cg.buildCmp(.i_ne, mask, overflow); | 3339 | const overflowed = try cg.buildCmp(.OpINotEqual, mask, overflow); |
| 3453 | | 3340 | |
| 3454 | break :blk .{ result, overflowed }; | 3341 | break :blk .{ result, overflowed }; |
| 3455 | } | 3342 | } |
| 3456 | | 3343 | |
| 3457 | const low_bits, const high_bits = try cg.buildWideMul(.s_mul_extended, lhs, rhs); | 3344 | const low_bits, const high_bits = try cg.buildWideMul(.signed, lhs, rhs); |
| 3458 | | 3345 | |
| 3459 | // Truncate result if required. | 3346 | // Truncate result if required. |
| 3460 | const result = try cg.normalize(low_bits, info); | 3347 | const result = try cg.normalize(low_bits, info); |
| ... | @@ -3465,7 +3352,7 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | ... | @@ -3465,7 +3352,7 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 3465 | // Like with unsigned, overflow happened if high_bits are not the ones we expect, | 3352 | // Like with unsigned, overflow happened if high_bits are not the ones we expect, |
| 3466 | // and we also need to check some ones from the low bits. | 3353 | // and we also need to check some ones from the low bits. |
| 3467 | | 3354 | |
| 3468 | const high_overflowed = try cg.buildCmp(.i_ne, mask, high_bits); | 3355 | const high_overflowed = try cg.buildCmp(.OpINotEqual, mask, high_bits); |
| 3469 | | 3356 | |
| 3470 | // If no overflow bits in low_bits, no extra work needs to be done. | 3357 | // If no overflow bits in low_bits, no extra work needs to be done. |
| 3471 | // Careful, we still have to check the sign bit, so this branch | 3358 | // Careful, we still have to check the sign bit, so this branch |
| ... | @@ -3476,10 +3363,10 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | ... | @@ -3476,10 +3363,10 @@ fn airMulOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 3476 | const shift: Temporary = .init(lhs.ty, try cg.constInt(lhs.ty, info.bits - 1)); | 3363 | const shift: Temporary = .init(lhs.ty, try cg.constInt(lhs.ty, info.bits - 1)); |
| 3477 | // Use SRA so that any sign bits are duplicated. Now we can just check if ALL bits are set | 3364 | // Use SRA so that any sign bits are duplicated. Now we can just check if ALL bits are set |
| 3478 | // for negative cases. | 3365 | // for negative cases. |
| 3479 | const low_overflow = try cg.buildBinary(.sra, low_bits, shift); | 3366 | const low_overflow = try cg.buildBinary(.OpShiftRightArithmetic, low_bits, shift); |
| 3480 | const low_overflowed = try cg.buildCmp(.i_ne, mask, low_overflow); | 3367 | const low_overflowed = try cg.buildCmp(.OpINotEqual, mask, low_overflow); |
| 3481 | | 3368 | |
| 3482 | const overflowed = try cg.buildBinary(.l_or, low_overflowed, high_overflowed); | 3369 | const overflowed = try cg.buildCmp(.OpLogicalOr, low_overflowed, high_overflowed); |
| 3483 | | 3370 | |
| 3484 | break :blk .{ result, overflowed }; | 3371 | break :blk .{ result, overflowed }; |
| 3485 | }, | 3372 | }, |
| ... | @@ -3517,15 +3404,15 @@ fn airShlOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | ... | @@ -3517,15 +3404,15 @@ fn airShlOverflow(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 3517 | // so just manually upcast it if required. | 3404 | // so just manually upcast it if required. |
| 3518 | const casted_shift = try cg.buildConvert(base.ty.scalarType(zcu), shift); | 3405 | const casted_shift = try cg.buildConvert(base.ty.scalarType(zcu), shift); |
| 3519 | | 3406 | |
| 3520 | const left = try cg.buildBinary(.sll, base, casted_shift); | 3407 | const left = try cg.buildBinary(.OpShiftLeftLogical, base, casted_shift); |
| 3521 | const result = try cg.normalize(left, info); | 3408 | const result = try cg.normalize(left, info); |
| 3522 | | 3409 | |
| 3523 | const right = switch (info.signedness) { | 3410 | const right = switch (info.signedness) { |
| 3524 | .unsigned => try cg.buildBinary(.srl, result, casted_shift), | 3411 | .unsigned => try cg.buildBinary(.OpShiftRightLogical, result, casted_shift), |
| 3525 | .signed => try cg.buildBinary(.sra, result, casted_shift), | 3412 | .signed => try cg.buildBinary(.OpShiftRightArithmetic, result, casted_shift), |
| 3526 | }; | 3413 | }; |
| 3527 | | 3414 | |
| 3528 | const overflowed = try cg.buildCmp(.i_ne, base, right); | 3415 | const overflowed = try cg.buildCmp(.OpINotEqual, base, right); |
| 3529 | const ov = try cg.intFromBool(overflowed); | 3416 | const ov = try cg.intFromBool(overflowed); |
| 3530 | | 3417 | |
| 3531 | const result_ty_id = try cg.resolveType(result_ty, .direct); | 3418 | const result_ty_id = try cg.resolveType(result_ty, .direct); |
| ... | @@ -3957,19 +3844,19 @@ fn cmp( | ... | @@ -3957,19 +3844,19 @@ fn cmp( |
| 3957 | | 3844 | |
| 3958 | return switch (op) { | 3845 | return switch (op) { |
| 3959 | .eq => try cg.buildBinary( | 3846 | .eq => try cg.buildBinary( |
| 3960 | .l_and, | 3847 | .OpLogicalAnd, |
| 3961 | try cg.cmp(.eq, lhs_valid, rhs_valid), | 3848 | try cg.cmp(.eq, lhs_valid, rhs_valid), |
| 3962 | try cg.buildBinary( | 3849 | try cg.buildBinary( |
| 3963 | .l_or, | 3850 | .OpLogicalOr, |
| 3964 | try cg.buildUnary(.l_not, lhs_valid), | 3851 | try cg.buildUnary(.l_not, lhs_valid), |
| 3965 | try cg.cmp(.eq, lhs_pl, rhs_pl), | 3852 | try cg.cmp(.eq, lhs_pl, rhs_pl), |
| 3966 | ), | 3853 | ), |
| 3967 | ), | 3854 | ), |
| 3968 | .neq => try cg.buildBinary( | 3855 | .neq => try cg.buildBinary( |
| 3969 | .l_or, | 3856 | .OpLogicalOr, |
| 3970 | try cg.cmp(.neq, lhs_valid, rhs_valid), | 3857 | try cg.cmp(.neq, lhs_valid, rhs_valid), |
| 3971 | try cg.buildBinary( | 3858 | try cg.buildBinary( |
| 3972 | .l_and, | 3859 | .OpLogicalAnd, |
| 3973 | lhs_valid, | 3860 | lhs_valid, |
| 3974 | try cg.cmp(.neq, lhs_pl, rhs_pl), | 3861 | try cg.cmp(.neq, lhs_pl, rhs_pl), |
| 3975 | ), | 3862 | ), |
| ... | @@ -3981,37 +3868,37 @@ fn cmp( | ... | @@ -3981,37 +3868,37 @@ fn cmp( |
| 3981 | } | 3868 | } |
| 3982 | | 3869 | |
| 3983 | const info = cg.arithmeticTypeInfo(scalar_ty); | 3870 | const info = cg.arithmeticTypeInfo(scalar_ty); |
| 3984 | const pred: CmpPredicate = switch (info.class) { | 3871 | const pred: Opcode = switch (info.class) { |
| 3985 | .composite_integer => unreachable, // TODO | 3872 | .composite_integer => unreachable, // TODO |
| 3986 | .float => switch (op) { | 3873 | .float => switch (op) { |
| 3987 | .eq => .f_oeq, | 3874 | .eq => .OpFOrdEqual, |
| 3988 | .neq => .f_une, | 3875 | .neq => .OpFUnordNotEqual, |
| 3989 | .lt => .f_olt, | 3876 | .lt => .OpFOrdLessThan, |
| 3990 | .lte => .f_ole, | 3877 | .lte => .OpFOrdLessThanEqual, |
| 3991 | .gt => .f_ogt, | 3878 | .gt => .OpFOrdGreaterThan, |
| 3992 | .gte => .f_oge, | 3879 | .gte => .OpFOrdGreaterThanEqual, |
| 3993 | }, | 3880 | }, |
| 3994 | .bool => switch (op) { | 3881 | .bool => switch (op) { |
| 3995 | .eq => .l_eq, | 3882 | .eq => .OpLogicalEqual, |
| 3996 | .neq => .l_ne, | 3883 | .neq => .OpLogicalNotEqual, |
| 3997 | else => unreachable, | 3884 | else => unreachable, |
| 3998 | }, | 3885 | }, |
| 3999 | .integer, .strange_integer => switch (info.signedness) { | 3886 | .integer, .strange_integer => switch (info.signedness) { |
| 4000 | .signed => switch (op) { | 3887 | .signed => switch (op) { |
| 4001 | .eq => .i_eq, | 3888 | .eq => .OpIEqual, |
| 4002 | .neq => .i_ne, | 3889 | .neq => .OpINotEqual, |
| 4003 | .lt => .s_lt, | 3890 | .lt => .OpSLessThan, |
| 4004 | .lte => .s_le, | 3891 | .lte => .OpSLessThanEqual, |
| 4005 | .gt => .s_gt, | 3892 | .gt => .OpSGreaterThan, |
| 4006 | .gte => .s_ge, | 3893 | .gte => .OpSGreaterThanEqual, |
| 4007 | }, | 3894 | }, |
| 4008 | .unsigned => switch (op) { | 3895 | .unsigned => switch (op) { |
| 4009 | .eq => .i_eq, | 3896 | .eq => .OpIEqual, |
| 4010 | .neq => .i_ne, | 3897 | .neq => .OpINotEqual, |
| 4011 | .lt => .u_lt, | 3898 | .lt => .OpULessThan, |
| 4012 | .lte => .u_le, | 3899 | .lte => .OpULessThanEqual, |
| 4013 | .gt => .u_gt, | 3900 | .gt => .OpUGreaterThan, |
| 4014 | .gte => .u_ge, | 3901 | .gte => .OpUGreaterThanEqual, |
| 4015 | }, | 3902 | }, |
| 4016 | }, | 3903 | }, |
| 4017 | }; | 3904 | }; |
| ... | @@ -4312,12 +4199,12 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | ... | @@ -4312,12 +4199,12 @@ fn airAggregateInit(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 4312 | .ty = field_int_ty, | 4199 | .ty = field_int_ty, |
| 4313 | .value = .{ .singleton = field_int_id }, | 4200 | .value = .{ .singleton = field_int_id }, |
| 4314 | }); | 4201 | }); |
| 4315 | const shifted = try cg.buildBinary(.sll, extended_int_conv, .{ | 4202 | const shifted = try cg.buildBinary(.OpShiftLeftLogical, extended_int_conv, .{ |
| 4316 | .ty = backing_int_ty, | 4203 | .ty = backing_int_ty, |
| 4317 | .value = .{ .singleton = shift_rhs }, | 4204 | .value = .{ .singleton = shift_rhs }, |
| 4318 | }); | 4205 | }); |
| 4319 | const running_int_tmp = try cg.buildBinary( | 4206 | const running_int_tmp = try cg.buildBinary( |
| 4320 | .bit_or, | 4207 | .OpBitwiseOr, |
| 4321 | .{ .ty = backing_int_ty, .value = .{ .singleton = running_int_id } }, | 4208 | .{ .ty = backing_int_ty, .value = .{ .singleton = running_int_id } }, |
| 4322 | shifted, | 4209 | shifted, |
| 4323 | ); | 4210 | ); |
| ... | @@ -4770,17 +4657,20 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | ... | @@ -4770,17 +4657,20 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 4770 | .@"struct" => switch (object_ty.containerLayout(zcu)) { | 4657 | .@"struct" => switch (object_ty.containerLayout(zcu)) { |
| 4771 | .@"packed" => { | 4658 | .@"packed" => { |
| 4772 | const struct_ty = zcu.typeToPackedStruct(object_ty).?; | 4659 | const struct_ty = zcu.typeToPackedStruct(object_ty).?; |
| | 4660 | const struct_backing_int_bits = cg.module.backingIntBits(@intCast(object_ty.bitSize(zcu))).@"0"; |
| 4773 | const bit_offset = zcu.structPackedFieldBitOffset(struct_ty, field_index); | 4661 | const bit_offset = zcu.structPackedFieldBitOffset(struct_ty, field_index); |
| 4774 | const bit_offset_id = try cg.constInt(.u16, bit_offset); | 4662 | // We use the same int type the packed struct is backed by, because even though it would |
| | 4663 | // be valid SPIR-V to use an smaller type like u16, some implementations like PoCL will complain. |
| | 4664 | const bit_offset_id = try cg.constInt(object_ty, bit_offset); |
| 4775 | const signedness = if (field_ty.isInt(zcu)) field_ty.intInfo(zcu).signedness else .unsigned; | 4665 | const signedness = if (field_ty.isInt(zcu)) field_ty.intInfo(zcu).signedness else .unsigned; |
| 4776 | const field_bit_size: u16 = @intCast(field_ty.bitSize(zcu)); | 4666 | const field_bit_size: u16 = @intCast(field_ty.bitSize(zcu)); |
| 4777 | const field_int_ty = try pt.intType(signedness, field_bit_size); | 4667 | const field_int_ty = try pt.intType(signedness, field_bit_size); |
| 4778 | const shift_lhs: Temporary = .{ .ty = object_ty, .value = .{ .singleton = object_id } }; | 4668 | const shift_lhs: Temporary = .{ .ty = object_ty, .value = .{ .singleton = object_id } }; |
| 4779 | const shift = try cg.buildBinary(.srl, shift_lhs, .{ .ty = .u16, .value = .{ .singleton = bit_offset_id } }); | 4669 | const shift = try cg.buildBinary(.OpShiftRightLogical, shift_lhs, .{ .ty = object_ty, .value = .{ .singleton = bit_offset_id } }); |
| 4780 | const mask_id = try cg.constInt(object_ty, (@as(u64, 1) << @as(u6, @intCast(field_bit_size))) - 1); | 4670 | const mask_id = try cg.constInt(object_ty, (@as(u64, 1) << @as(u6, @intCast(field_bit_size))) - 1); |
| 4781 | const masked = try cg.buildBinary(.bit_and, shift, .{ .ty = object_ty, .value = .{ .singleton = mask_id } }); | 4671 | const masked = try cg.buildBinary(.OpBitwiseAnd, shift, .{ .ty = object_ty, .value = .{ .singleton = mask_id } }); |
| 4782 | const result_id = blk: { | 4672 | const result_id = blk: { |
| 4783 | if (cg.module.backingIntBits(field_bit_size).@"0" == cg.module.backingIntBits(@intCast(object_ty.bitSize(zcu))).@"0") | 4673 | if (cg.module.backingIntBits(field_bit_size).@"0" == struct_backing_int_bits) |
| 4784 | break :blk try cg.bitCast(field_int_ty, object_ty, try masked.materialize(cg)); | 4674 | break :blk try cg.bitCast(field_int_ty, object_ty, try masked.materialize(cg)); |
| 4785 | const trunc = try cg.buildConvert(field_int_ty, masked); | 4675 | const trunc = try cg.buildConvert(field_int_ty, masked); |
| 4786 | break :blk try trunc.materialize(cg); | 4676 | break :blk try trunc.materialize(cg); |
| ... | @@ -4799,7 +4689,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | ... | @@ -4799,7 +4689,7 @@ fn airStructFieldVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 4799 | const int_ty = try pt.intType(signedness, field_bit_size); | 4689 | const int_ty = try pt.intType(signedness, field_bit_size); |
| 4800 | const mask_id = try cg.constInt(backing_int_ty, (@as(u64, 1) << @as(u6, @intCast(field_bit_size))) - 1); | 4690 | const mask_id = try cg.constInt(backing_int_ty, (@as(u64, 1) << @as(u6, @intCast(field_bit_size))) - 1); |
| 4801 | const masked = try cg.buildBinary( | 4691 | const masked = try cg.buildBinary( |
| 4802 | .bit_and, | 4692 | .OpBitwiseAnd, |
| 4803 | .{ .ty = backing_int_ty, .value = .{ .singleton = object_id } }, | 4693 | .{ .ty = backing_int_ty, .value = .{ .singleton = object_id } }, |
| 4804 | .{ .ty = backing_int_ty, .value = .{ .singleton = mask_id } }, | 4694 | .{ .ty = backing_int_ty, .value = .{ .singleton = mask_id } }, |
| 4805 | ); | 4695 | ); |
| ... | @@ -4858,7 +4748,7 @@ fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | ... | @@ -4858,7 +4748,7 @@ fn airFieldParentPtr(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |
| 4858 | const field_offset_id = try cg.constInt(.usize, field_offset); | 4748 | const field_offset_id = try cg.constInt(.usize, field_offset); |
| 4859 | const field_ptr_tmp: Temporary = .init(.usize, field_ptr_int); | 4749 | const field_ptr_tmp: Temporary = .init(.usize, field_ptr_int); |
| 4860 | const field_offset_tmp: Temporary = .init(.usize, field_offset_id); | 4750 | const field_offset_tmp: Temporary = .init(.usize, field_offset_id); |
| 4861 | const result = try cg.buildBinary(.i_sub, field_ptr_tmp, field_offset_tmp); | 4751 | const result = try cg.buildBinary(.OpISub, field_ptr_tmp, field_offset_tmp); |
| 4862 | break :base_ptr_int try result.materialize(cg); | 4752 | break :base_ptr_int try result.materialize(cg); |
| 4863 | }; | 4753 | }; |
| 4864 | | 4754 | |
| ... | @@ -4947,7 +4837,6 @@ fn alloc( | ... | @@ -4947,7 +4837,6 @@ fn alloc( |
| 4947 | ty: Type, | 4837 | ty: Type, |
| 4948 | options: AllocOptions, | 4838 | options: AllocOptions, |
| 4949 | ) !Id { | 4839 | ) !Id { |
| 4950 | const target = cg.module.zcu.getTarget(); | | |
| 4951 | const ty_id = try cg.resolveType(ty, .indirect); | 4840 | const ty_id = try cg.resolveType(ty, .indirect); |
| 4952 | const ptr_fn_ty_id = try cg.module.ptrType(ty_id, .function); | 4841 | const ptr_fn_ty_id = try cg.module.ptrType(ty_id, .function); |
| 4953 | | 4842 | |
| ... | @@ -4961,20 +4850,7 @@ fn alloc( | ... | @@ -4961,20 +4850,7 @@ fn alloc( |
| 4961 | .initializer = options.initializer, | 4850 | .initializer = options.initializer, |
| 4962 | }); | 4851 | }); |
| 4963 | | 4852 | |
| 4964 | switch (target.os.tag) { | 4853 | return var_id; |
| 4965 | .vulkan, .opengl => return var_id, | | |
| 4966 | else => {}, | | |
| 4967 | } | | |
| 4968 | | | |
| 4969 | switch (options.storage_class) { | | |
| 4970 | .generic => { | | |
| 4971 | const ptr_gn_ty_id = try cg.module.ptrType(ty_id, .generic); | | |
| 4972 | // Convert to a generic pointer | | |
| 4973 | return cg.castToGeneric(ptr_gn_ty_id, var_id); | | |
| 4974 | }, | | |
| 4975 | .function => return var_id, | | |
| 4976 | else => unreachable, | | |
| 4977 | } | | |
| 4978 | } | 4854 | } |
| 4979 | | 4855 | |
| 4980 | fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) !?Id { | 4856 | fn airAlloc(cg: *CodeGen, inst: Air.Inst.Index) !?Id { |