| ... | ... | @@ -50,8 +50,6 @@ pub const CValue = union(enum) { |
| 50 | 50 | /// Render these bytes literally. |
| 51 | 51 | /// TODO make this a [*:0]const u8 to save memory |
| 52 | 52 | bytes: []const u8, |
| 53 | | /// Index of an instruction that should later be rendered inline. |
| 54 | | inline_index: Air.Inst.Index, |
| 55 | 53 | }; |
| 56 | 54 | |
| 57 | 55 | const BlockData = struct { |
| ... | ... | @@ -81,7 +79,6 @@ const ValueRenderLocation = enum { |
| 81 | 79 | FunctionArgument, |
| 82 | 80 | Initializer, |
| 83 | 81 | Other, |
| 84 | | condition, |
| 85 | 82 | }; |
| 86 | 83 | |
| 87 | 84 | const BuiltinInfo = enum { |
| ... | ... | @@ -281,19 +278,6 @@ pub const Function = struct { |
| 281 | 278 | return result; |
| 282 | 279 | } |
| 283 | 280 | |
| 284 | | fn resolveInstNoInline(f: *Function, inst: Air.Inst.Ref) !CValue { |
| 285 | | const operand = try f.resolveInst(inst); |
| 286 | | if (operand != .inline_index) return operand; |
| 287 | | |
| 288 | | const inst_ty = f.air.typeOf(inst); |
| 289 | | const writer = f.object.writer(); |
| 290 | | const local = try f.allocLocal(inst_ty, .Const); |
| 291 | | try writer.writeAll(" = "); |
| 292 | | try f.writeCValueInline(operand.inline_index); |
| 293 | | try writer.writeAll(";\n"); |
| 294 | | return local; |
| 295 | | } |
| 296 | | |
| 297 | 281 | fn wantSafety(f: *Function) bool { |
| 298 | 282 | return switch (f.object.dg.module.optimizeMode()) { |
| 299 | 283 | .Debug, .ReleaseSafe => true, |
| ... | ... | @@ -329,74 +313,10 @@ pub const Function = struct { |
| 329 | 313 | .constant => |inst| { |
| 330 | 314 | const ty = f.air.typeOf(inst); |
| 331 | 315 | const val = f.air.value(inst).?; |
| 332 | | try f.object.dg.renderValue(w, ty, val, location); |
| 333 | | }, |
| 334 | | .undef => |ty| try f.object.dg.renderValue(w, ty, Value.undef, location), |
| 335 | | .inline_index => |node| { |
| 336 | | if (location != .condition) try w.writeByte('('); |
| 337 | | try f.writeCValueInline(node); |
| 338 | | if (location != .condition) try w.writeByte(')'); |
| 339 | | }, |
| 340 | | else => try f.object.dg.writeCValue(w, c_value), |
| 341 | | } |
| 342 | | } |
| 343 | | |
| 344 | | const E = error{ OutOfMemory, AnalysisFail }; |
| 345 | | |
| 346 | | fn writeCValueInline(f: *Function, inst: Air.Inst.Index) E!void { |
| 347 | | switch (f.air.instructions.items(.tag)[inst]) { |
| 348 | | // zig fmt: off |
| 349 | | // TODO use a different strategy for add, sub, mul, div |
| 350 | | // that communicates to the optimizer that wrapping is UB. |
| 351 | | .add => try airBinOp(f, inst, "+", "add", .None), |
| 352 | | .sub => try airBinOp(f, inst, "-", "sub", .None), |
| 353 | | .mul => try airBinOp(f, inst, "*", "mul", .None), |
| 354 | | |
| 355 | | .div_float => try airBinBuiltinCall(f, inst, "div", .None), |
| 356 | | |
| 357 | | .div_trunc, .div_exact => try airBinOp(f, inst, "/", "div_trunc", .None), |
| 358 | | .rem => { |
| 359 | | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 360 | | const lhs_ty = f.air.typeOf(bin_op.lhs); |
| 361 | | // For binary operations @TypeOf(lhs)==@TypeOf(rhs), |
| 362 | | // so we only check one. |
| 363 | | if (lhs_ty.isInt()) |
| 364 | | try airBinOp(f, inst, "%", "rem", .None) |
| 365 | | else |
| 366 | | try airBinFloatOp(f, inst, "fmod"); |
| 316 | return f.object.dg.renderValue(w, ty, val, location); |
| 367 | 317 | }, |
| 368 | | .div_floor => try airBinBuiltinCall(f, inst, "div_floor", .None), |
| 369 | | .mod => try airBinBuiltinCall(f, inst, "mod", .None), |
| 370 | | |
| 371 | | .addwrap => try airBinBuiltinCall(f, inst, "addw", .Bits), |
| 372 | | .subwrap => try airBinBuiltinCall(f, inst, "subw", .Bits), |
| 373 | | .mulwrap => try airBinBuiltinCall(f, inst, "mulw", .Bits), |
| 374 | | |
| 375 | | .add_sat => try airBinBuiltinCall(f, inst, "adds", .Bits), |
| 376 | | .sub_sat => try airBinBuiltinCall(f, inst, "subs", .Bits), |
| 377 | | .mul_sat => try airBinBuiltinCall(f, inst, "muls", .Bits), |
| 378 | | .shl_sat => try airBinBuiltinCall(f, inst, "shls", .Bits), |
| 379 | | |
| 380 | | .min => try airMinMax(f, inst, '<', "fmin"), |
| 381 | | .max => try airMinMax(f, inst, '>', "fmax"), |
| 382 | | |
| 383 | | .cmp_gt => try airCmpOp(f, inst, ">", "gt"), |
| 384 | | .cmp_gte => try airCmpOp(f, inst, ">=", "ge"), |
| 385 | | .cmp_lt => try airCmpOp(f, inst, "<", "lt"), |
| 386 | | .cmp_lte => try airCmpOp(f, inst, "<=", "le"), |
| 387 | | |
| 388 | | .cmp_eq => try airEquality(f, inst, "((", "==", "eq"), |
| 389 | | .cmp_neq => try airEquality(f, inst, "!((", "!=", "ne"), |
| 390 | | |
| 391 | | .bool_and, .bit_and => try airBinOp(f, inst, "&", "and", .None), |
| 392 | | .bool_or, .bit_or => try airBinOp(f, inst, "|", "or", .None), |
| 393 | | .xor => try airBinOp(f, inst, "^", "xor", .None), |
| 394 | | .shr, .shr_exact => try airBinBuiltinCall(f, inst, "shr", .None), |
| 395 | | .shl, => try airBinBuiltinCall(f, inst, "shlw", .Bits), |
| 396 | | .shl_exact => try airBinOp(f, inst, "<<", "shl", .None), |
| 397 | | .not => try airNot (f, inst), |
| 398 | | else => unreachable, |
| 399 | | // zig fmt: on |
| 318 | .undef => |ty| return f.object.dg.renderValue(w, ty, Value.undef, location), |
| 319 | else => return f.object.dg.writeCValue(w, c_value), |
| 400 | 320 | } |
| 401 | 321 | } |
| 402 | 322 | |
| ... | ... | @@ -2245,7 +2165,7 @@ pub const DeclGen = struct { |
| 2245 | 2165 | |
| 2246 | 2166 | fn writeCValue(dg: *DeclGen, w: anytype, c_value: CValue) !void { |
| 2247 | 2167 | switch (c_value) { |
| 2248 | | .none, .inline_index => unreachable, |
| 2168 | .none => unreachable, |
| 2249 | 2169 | .local => |i| return w.print("t{d}", .{i}), |
| 2250 | 2170 | .local_ref => |i| return w.print("&t{d}", .{i}), |
| 2251 | 2171 | .constant => unreachable, |
| ... | ... | @@ -2264,7 +2184,7 @@ pub const DeclGen = struct { |
| 2264 | 2184 | |
| 2265 | 2185 | fn writeCValueDeref(dg: *DeclGen, w: anytype, c_value: CValue) !void { |
| 2266 | 2186 | switch (c_value) { |
| 2267 | | .none, .inline_index => unreachable, |
| 2187 | .none => unreachable, |
| 2268 | 2188 | .local => |i| return w.print("(*t{d})", .{i}), |
| 2269 | 2189 | .local_ref => |i| return w.print("t{d}", .{i}), |
| 2270 | 2190 | .constant => unreachable, |
| ... | ... | @@ -2294,7 +2214,7 @@ pub const DeclGen = struct { |
| 2294 | 2214 | |
| 2295 | 2215 | fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void { |
| 2296 | 2216 | switch (c_value) { |
| 2297 | | .none, .constant, .field, .undef, .inline_index => unreachable, |
| 2217 | .none, .constant, .field, .undef => unreachable, |
| 2298 | 2218 | .local, .arg, .decl, .identifier, .bytes => { |
| 2299 | 2219 | try dg.writeCValue(writer, c_value); |
| 2300 | 2220 | try writer.writeAll("->"); |
| ... | ... | @@ -2633,26 +2553,37 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, |
| 2633 | 2553 | .ptr_add => try airPtrAddSub(f, inst, '+'), |
| 2634 | 2554 | .ptr_sub => try airPtrAddSub(f, inst, '-'), |
| 2635 | 2555 | |
| 2636 | | .add => CValue{ .inline_index = inst }, |
| 2637 | | .sub => CValue{ .inline_index = inst }, |
| 2638 | | .mul => CValue{ .inline_index = inst }, |
| 2556 | // TODO use a different strategy for add, sub, mul, div |
| 2557 | // that communicates to the optimizer that wrapping is UB. |
| 2558 | .add => try airBinOp(f, inst, "+", "add", .None), |
| 2559 | .sub => try airBinOp(f, inst, "-", "sub", .None), |
| 2560 | .mul => try airBinOp(f, inst, "*", "mul", .None), |
| 2639 | 2561 | |
| 2640 | 2562 | .neg => try airFloatNeg(f, inst), |
| 2641 | | .div_float => CValue{ .inline_index = inst }, |
| 2563 | .div_float => try airBinBuiltinCall(f, inst, "div", .None), |
| 2642 | 2564 | |
| 2643 | | .div_trunc, .div_exact => CValue{ .inline_index = inst }, |
| 2644 | | .rem => CValue{ .inline_index = inst }, |
| 2645 | | .div_floor => CValue{ .inline_index = inst }, |
| 2646 | | .mod => CValue{ .inline_index = inst }, |
| 2565 | .div_trunc, .div_exact => try airBinOp(f, inst, "/", "div_trunc", .None), |
| 2566 | .rem => blk: { |
| 2567 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 2568 | const lhs_ty = f.air.typeOf(bin_op.lhs); |
| 2569 | // For binary operations @TypeOf(lhs)==@TypeOf(rhs), |
| 2570 | // so we only check one. |
| 2571 | break :blk if (lhs_ty.isInt()) |
| 2572 | try airBinOp(f, inst, "%", "rem", .None) |
| 2573 | else |
| 2574 | try airBinFloatOp(f, inst, "fmod"); |
| 2575 | }, |
| 2576 | .div_floor => try airBinBuiltinCall(f, inst, "div_floor", .None), |
| 2577 | .mod => try airBinBuiltinCall(f, inst, "mod", .None), |
| 2647 | 2578 | |
| 2648 | | .addwrap => CValue{ .inline_index = inst }, |
| 2649 | | .subwrap => CValue{ .inline_index = inst }, |
| 2650 | | .mulwrap => CValue{ .inline_index = inst }, |
| 2579 | .addwrap => try airBinBuiltinCall(f, inst, "addw", .Bits), |
| 2580 | .subwrap => try airBinBuiltinCall(f, inst, "subw", .Bits), |
| 2581 | .mulwrap => try airBinBuiltinCall(f, inst, "mulw", .Bits), |
| 2651 | 2582 | |
| 2652 | | .add_sat => CValue{ .inline_index = inst }, |
| 2653 | | .sub_sat => CValue{ .inline_index = inst }, |
| 2654 | | .mul_sat => CValue{ .inline_index = inst }, |
| 2655 | | .shl_sat => CValue{ .inline_index = inst }, |
| 2583 | .add_sat => try airBinBuiltinCall(f, inst, "adds", .Bits), |
| 2584 | .sub_sat => try airBinBuiltinCall(f, inst, "subs", .Bits), |
| 2585 | .mul_sat => try airBinBuiltinCall(f, inst, "muls", .Bits), |
| 2586 | .shl_sat => try airBinBuiltinCall(f, inst, "shls", .Bits), |
| 2656 | 2587 | |
| 2657 | 2588 | .sqrt, |
| 2658 | 2589 | .sin, |
| ... | ... | @@ -2677,30 +2608,30 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, |
| 2677 | 2608 | .mul_with_overflow => try airOverflow(f, inst, "mul", .Bits), |
| 2678 | 2609 | .shl_with_overflow => try airOverflow(f, inst, "shl", .Bits), |
| 2679 | 2610 | |
| 2680 | | .min => CValue{ .inline_index = inst }, |
| 2681 | | .max => CValue{ .inline_index = inst }, |
| 2611 | .min => try airMinMax(f, inst, '<', "fmin"), |
| 2612 | .max => try airMinMax(f, inst, '>', "fmax"), |
| 2682 | 2613 | |
| 2683 | 2614 | .slice => try airSlice(f, inst), |
| 2684 | 2615 | |
| 2685 | | .cmp_gt => CValue{ .inline_index = inst }, |
| 2686 | | .cmp_gte => CValue{ .inline_index = inst }, |
| 2687 | | .cmp_lt => CValue{ .inline_index = inst }, |
| 2688 | | .cmp_lte => CValue{ .inline_index = inst }, |
| 2616 | .cmp_gt => try airCmpOp(f, inst, ">", "gt"), |
| 2617 | .cmp_gte => try airCmpOp(f, inst, ">=", "ge"), |
| 2618 | .cmp_lt => try airCmpOp(f, inst, "<", "lt"), |
| 2619 | .cmp_lte => try airCmpOp(f, inst, "<=", "le"), |
| 2689 | 2620 | |
| 2690 | | .cmp_eq => CValue{ .inline_index = inst }, |
| 2691 | | .cmp_neq => CValue{ .inline_index = inst }, |
| 2621 | .cmp_eq => try airEquality(f, inst, "((", "==", "eq"), |
| 2622 | .cmp_neq => try airEquality(f, inst, "!((", "!=", "ne"), |
| 2692 | 2623 | |
| 2693 | 2624 | .cmp_vector => return f.fail("TODO: C backend: implement cmp_vector", .{}), |
| 2694 | 2625 | .cmp_lt_errors_len => try airCmpLtErrorsLen(f, inst), |
| 2695 | 2626 | |
| 2696 | 2627 | // bool_and and bool_or are non-short-circuit operations |
| 2697 | | .bool_and, .bit_and => CValue{ .inline_index = inst }, |
| 2698 | | .bool_or, .bit_or => CValue{ .inline_index = inst }, |
| 2699 | | .xor => CValue{ .inline_index = inst }, |
| 2700 | | .shr, .shr_exact => CValue{ .inline_index = inst }, |
| 2701 | | .shl, => CValue{ .inline_index = inst }, |
| 2702 | | .shl_exact => CValue{ .inline_index = inst }, |
| 2703 | | .not => CValue{ .inline_index = inst }, |
| 2628 | .bool_and, .bit_and => try airBinOp(f, inst, "&", "and", .None), |
| 2629 | .bool_or, .bit_or => try airBinOp(f, inst, "|", "or", .None), |
| 2630 | .xor => try airBinOp(f, inst, "^", "xor", .None), |
| 2631 | .shr, .shr_exact => try airBinBuiltinCall(f, inst, "shr", .None), |
| 2632 | .shl, => try airBinBuiltinCall(f, inst, "shlw", .Bits), |
| 2633 | .shl_exact => try airBinOp(f, inst, "<<", "shl", .None), |
| 2634 | .not => try airNot (f, inst), |
| 2704 | 2635 | |
| 2705 | 2636 | .optional_payload => try airOptionalPayload(f, inst), |
| 2706 | 2637 | .optional_payload_ptr => try airOptionalPayloadPtr(f, inst), |
| ... | ... | @@ -3449,21 +3380,22 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: |
| 3449 | 3380 | return local; |
| 3450 | 3381 | } |
| 3451 | 3382 | |
| 3452 | | fn airNot(f: *Function, inst: Air.Inst.Index) !void { |
| 3383 | fn airNot(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3384 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 3385 | |
| 3453 | 3386 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 3454 | 3387 | const op = try f.resolveInst(ty_op.operand); |
| 3455 | 3388 | |
| 3456 | 3389 | const writer = f.object.writer(); |
| 3457 | 3390 | const inst_ty = f.air.typeOfIndex(inst); |
| 3391 | const local = try f.allocLocal(inst_ty, .Const); |
| 3458 | 3392 | |
| 3459 | | const target = f.object.dg.module.getTarget(); |
| 3460 | | if (inst_ty.bitSize(target) > 64) {} |
| 3461 | | |
| 3462 | | try writer.writeByte('('); |
| 3463 | | try f.renderTypecast(writer, inst_ty); |
| 3464 | | try writer.writeByte(')'); |
| 3393 | try writer.writeAll(" = "); |
| 3465 | 3394 | try writer.writeByte(if (inst_ty.tag() == .bool) '!' else '~'); |
| 3466 | 3395 | try f.writeCValue(writer, op, .Other); |
| 3396 | try writer.writeAll(";\n"); |
| 3397 | |
| 3398 | return local; |
| 3467 | 3399 | } |
| 3468 | 3400 | |
| 3469 | 3401 | fn airBinOp( |
| ... | ... | @@ -3472,54 +3404,62 @@ fn airBinOp( |
| 3472 | 3404 | operator: []const u8, |
| 3473 | 3405 | operation: []const u8, |
| 3474 | 3406 | info: BuiltinInfo, |
| 3475 | | ) !void { |
| 3407 | ) !CValue { |
| 3408 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 3409 | |
| 3476 | 3410 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 3477 | 3411 | |
| 3478 | 3412 | const operand_ty = f.air.typeOf(bin_op.lhs); |
| 3479 | 3413 | const target = f.object.dg.module.getTarget(); |
| 3480 | 3414 | if ((operand_ty.isInt() and operand_ty.bitSize(target) > 64) or operand_ty.isRuntimeFloat()) |
| 3481 | | return airBinBuiltinCall(f, inst, operation, info); |
| 3415 | return try airBinBuiltinCall(f, inst, operation, info); |
| 3482 | 3416 | |
| 3483 | 3417 | const inst_ty = f.air.typeOfIndex(inst); |
| 3484 | 3418 | const lhs = try f.resolveInst(bin_op.lhs); |
| 3485 | 3419 | const rhs = try f.resolveInst(bin_op.rhs); |
| 3486 | 3420 | |
| 3487 | 3421 | const writer = f.object.writer(); |
| 3488 | | try writer.writeByte('('); |
| 3489 | | try f.renderTypecast(writer, inst_ty); |
| 3490 | | try writer.writeAll(")("); |
| 3422 | const local = try f.allocLocal(inst_ty, .Const); |
| 3423 | |
| 3424 | try writer.writeAll(" = "); |
| 3491 | 3425 | try f.writeCValue(writer, lhs, .Other); |
| 3492 | 3426 | try writer.writeByte(' '); |
| 3493 | 3427 | try writer.writeAll(operator); |
| 3494 | 3428 | try writer.writeByte(' '); |
| 3495 | 3429 | try f.writeCValue(writer, rhs, .Other); |
| 3496 | | try writer.writeByte(')'); |
| 3430 | try writer.writeAll(";\n"); |
| 3431 | |
| 3432 | return local; |
| 3497 | 3433 | } |
| 3498 | 3434 | |
| 3499 | | fn airCmpOp( |
| 3500 | | f: *Function, |
| 3501 | | inst: Air.Inst.Index, |
| 3502 | | operator: []const u8, |
| 3503 | | operation: []const u8, |
| 3504 | | ) !void { |
| 3435 | fn airCmpOp(f: *Function, inst: Air.Inst.Index, operator: []const u8, operation: []const u8) !CValue { |
| 3436 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 3437 | |
| 3505 | 3438 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 3506 | 3439 | |
| 3507 | 3440 | const operand_ty = f.air.typeOf(bin_op.lhs); |
| 3508 | 3441 | const target = f.object.dg.module.getTarget(); |
| 3509 | 3442 | if (operand_ty.isInt() and operand_ty.bitSize(target) > 64) |
| 3510 | | return airCmpBuiltinCall(f, inst, operator, "cmp"); |
| 3443 | return try airCmpBuiltinCall(f, inst, operator, "cmp"); |
| 3511 | 3444 | if (operand_ty.isRuntimeFloat()) |
| 3512 | | return airCmpBuiltinCall(f, inst, operator, operation); |
| 3445 | return try airCmpBuiltinCall(f, inst, operator, operation); |
| 3513 | 3446 | |
| 3447 | const inst_ty = f.air.typeOfIndex(inst); |
| 3514 | 3448 | const lhs = try f.resolveInst(bin_op.lhs); |
| 3515 | 3449 | const rhs = try f.resolveInst(bin_op.rhs); |
| 3516 | 3450 | |
| 3517 | 3451 | const writer = f.object.writer(); |
| 3452 | const local = try f.allocLocal(inst_ty, .Const); |
| 3453 | |
| 3454 | try writer.writeAll(" = "); |
| 3518 | 3455 | try f.writeCValue(writer, lhs, .Other); |
| 3519 | 3456 | try writer.writeByte(' '); |
| 3520 | 3457 | try writer.writeAll(operator); |
| 3521 | 3458 | try writer.writeByte(' '); |
| 3522 | 3459 | try f.writeCValue(writer, rhs, .Other); |
| 3460 | try writer.writeAll(";\n"); |
| 3461 | |
| 3462 | return local; |
| 3523 | 3463 | } |
| 3524 | 3464 | |
| 3525 | 3465 | fn airEquality( |
| ... | ... | @@ -3528,20 +3468,27 @@ fn airEquality( |
| 3528 | 3468 | negate_prefix: []const u8, |
| 3529 | 3469 | operator: []const u8, |
| 3530 | 3470 | operation: []const u8, |
| 3531 | | ) !void { |
| 3471 | ) !CValue { |
| 3472 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 3473 | |
| 3532 | 3474 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 3533 | 3475 | |
| 3534 | 3476 | const operand_ty = f.air.typeOf(bin_op.lhs); |
| 3535 | 3477 | const target = f.object.dg.module.getTarget(); |
| 3536 | 3478 | if (operand_ty.isInt() and operand_ty.bitSize(target) > 64) |
| 3537 | | return airCmpBuiltinCall(f, inst, operator, "cmp"); |
| 3479 | return try airCmpBuiltinCall(f, inst, operator, "cmp"); |
| 3538 | 3480 | if (operand_ty.isRuntimeFloat()) |
| 3539 | | return airCmpBuiltinCall(f, inst, operator, operation); |
| 3481 | return try airCmpBuiltinCall(f, inst, operator, operation); |
| 3540 | 3482 | |
| 3541 | 3483 | const lhs = try f.resolveInst(bin_op.lhs); |
| 3542 | 3484 | const rhs = try f.resolveInst(bin_op.rhs); |
| 3543 | 3485 | |
| 3544 | 3486 | const writer = f.object.writer(); |
| 3487 | const inst_ty = f.air.typeOfIndex(inst); |
| 3488 | const local = try f.allocLocal(inst_ty, .Const); |
| 3489 | |
| 3490 | try writer.writeAll(" = "); |
| 3491 | |
| 3545 | 3492 | if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) { |
| 3546 | 3493 | // (A && B) || (C && (A == B)) |
| 3547 | 3494 | // A = lhs.is_null ; B = rhs.is_null ; C = rhs.payload == lhs.payload |
| ... | ... | @@ -3558,8 +3505,9 @@ fn airEquality( |
| 3558 | 3505 | try f.writeCValue(writer, lhs, .Other); |
| 3559 | 3506 | try writer.writeAll(".is_null == "); |
| 3560 | 3507 | try f.writeCValue(writer, rhs, .Other); |
| 3561 | | try writer.writeAll(".is_null))"); |
| 3562 | | return; |
| 3508 | try writer.writeAll(".is_null));\n"); |
| 3509 | |
| 3510 | return local; |
| 3563 | 3511 | } |
| 3564 | 3512 | |
| 3565 | 3513 | try f.writeCValue(writer, lhs, .Other); |
| ... | ... | @@ -3567,6 +3515,9 @@ fn airEquality( |
| 3567 | 3515 | try writer.writeAll(operator); |
| 3568 | 3516 | try writer.writeByte(' '); |
| 3569 | 3517 | try f.writeCValue(writer, rhs, .Other); |
| 3518 | try writer.writeAll(";\n"); |
| 3519 | |
| 3520 | return local; |
| 3570 | 3521 | } |
| 3571 | 3522 | |
| 3572 | 3523 | fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue { |
| ... | ... | @@ -3620,23 +3571,26 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue { |
| 3620 | 3571 | return local; |
| 3621 | 3572 | } |
| 3622 | 3573 | |
| 3623 | | fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []const u8) !void { |
| 3574 | fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []const u8) !CValue { |
| 3575 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 3576 | |
| 3624 | 3577 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 3625 | 3578 | |
| 3626 | 3579 | const inst_ty = f.air.typeOfIndex(inst); |
| 3627 | 3580 | const target = f.object.dg.module.getTarget(); |
| 3628 | 3581 | if (inst_ty.isInt() and inst_ty.bitSize(target) > 64) |
| 3629 | | return airBinBuiltinCall(f, inst, operation[1..], .None); |
| 3582 | return try airBinBuiltinCall(f, inst, operation[1..], .None); |
| 3630 | 3583 | if (inst_ty.isRuntimeFloat()) |
| 3631 | | return airBinFloatOp(f, inst, operation); |
| 3584 | return try airBinFloatOp(f, inst, operation); |
| 3632 | 3585 | |
| 3633 | 3586 | const lhs = try f.resolveInst(bin_op.lhs); |
| 3634 | 3587 | const rhs = try f.resolveInst(bin_op.rhs); |
| 3635 | 3588 | |
| 3636 | 3589 | const writer = f.object.writer(); |
| 3590 | const local = try f.allocLocal(inst_ty, .Const); |
| 3637 | 3591 | |
| 3638 | 3592 | // (lhs <> rhs) ? lhs : rhs |
| 3639 | | try writer.writeAll("("); |
| 3593 | try writer.writeAll(" = ("); |
| 3640 | 3594 | try f.writeCValue(writer, lhs, .Other); |
| 3641 | 3595 | try writer.writeByte(' '); |
| 3642 | 3596 | try writer.writeByte(operator); |
| ... | ... | @@ -3646,6 +3600,9 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons |
| 3646 | 3600 | try f.writeCValue(writer, lhs, .Other); |
| 3647 | 3601 | try writer.writeAll(" : "); |
| 3648 | 3602 | try f.writeCValue(writer, rhs, .Other); |
| 3603 | try writer.writeAll(";\n"); |
| 3604 | |
| 3605 | return local; |
| 3649 | 3606 | } |
| 3650 | 3607 | |
| 3651 | 3608 | fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue { |
| ... | ... | @@ -3961,7 +3918,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3961 | 3918 | if (f.liveness.isUnused(inst) or !src_ty.hasRuntimeBits()) return CValue.none; |
| 3962 | 3919 | |
| 3963 | 3920 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 3964 | | const operand = try f.resolveInstNoInline(ty_op.operand); |
| 3921 | const operand = try f.resolveInst(ty_op.operand); |
| 3965 | 3922 | const dest_ty = f.air.typeOf(ty_op.operand); |
| 3966 | 3923 | const target = f.object.dg.module.getTarget(); |
| 3967 | 3924 | |
| ... | ... | @@ -4067,7 +4024,7 @@ fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4067 | 4024 | const body = f.air.extra[loop.end..][0..loop.data.body_len]; |
| 4068 | 4025 | const writer = f.object.writer(); |
| 4069 | 4026 | try writer.writeAll("while ("); |
| 4070 | | try f.object.dg.renderValue(writer, Type.bool, Value.true, .condition); |
| 4027 | try f.object.dg.renderValue(writer, Type.bool, Value.true, .Other); |
| 4071 | 4028 | try writer.writeAll(") "); |
| 4072 | 4029 | try genBody(f, body); |
| 4073 | 4030 | try writer.writeByte('\n'); |
| ... | ... | @@ -4083,7 +4040,7 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4083 | 4040 | const writer = f.object.writer(); |
| 4084 | 4041 | |
| 4085 | 4042 | try writer.writeAll("if ("); |
| 4086 | | try f.writeCValue(writer, cond, .condition); |
| 4043 | try f.writeCValue(writer, cond, .Other); |
| 4087 | 4044 | try writer.writeAll(") "); |
| 4088 | 4045 | try genBody(f, then_body); |
| 4089 | 4046 | try writer.writeAll(" else "); |
| ... | ... | @@ -5174,12 +5131,16 @@ fn airBinBuiltinCall( |
| 5174 | 5131 | inst: Air.Inst.Index, |
| 5175 | 5132 | operation: []const u8, |
| 5176 | 5133 | info: BuiltinInfo, |
| 5177 | | ) !void { |
| 5134 | ) !CValue { |
| 5135 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 5136 | |
| 5137 | const inst_ty = f.air.typeOfIndex(inst); |
| 5178 | 5138 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 5179 | 5139 | const operand_ty = f.air.typeOf(bin_op.lhs); |
| 5180 | 5140 | |
| 5141 | const local = try f.allocLocal(inst_ty, .Const); |
| 5181 | 5142 | const writer = f.object.writer(); |
| 5182 | | try writer.writeAll("zig_"); |
| 5143 | try writer.writeAll(" = zig_"); |
| 5183 | 5144 | try writer.writeAll(operation); |
| 5184 | 5145 | try writer.writeByte('_'); |
| 5185 | 5146 | try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty); |
| ... | ... | @@ -5188,7 +5149,8 @@ fn airBinBuiltinCall( |
| 5188 | 5149 | try writer.writeAll(", "); |
| 5189 | 5150 | try f.writeCValue(writer, try f.resolveInst(bin_op.rhs), .FunctionArgument); |
| 5190 | 5151 | try f.object.dg.renderBuiltinInfo(writer, operand_ty, info); |
| 5191 | | try writer.writeAll(")"); |
| 5152 | try writer.writeAll(");\n"); |
| 5153 | return local; |
| 5192 | 5154 | } |
| 5193 | 5155 | |
| 5194 | 5156 | fn airCmpBuiltinCall( |
| ... | ... | @@ -5196,12 +5158,16 @@ fn airCmpBuiltinCall( |
| 5196 | 5158 | inst: Air.Inst.Index, |
| 5197 | 5159 | operator: []const u8, |
| 5198 | 5160 | operation: []const u8, |
| 5199 | | ) !void { |
| 5161 | ) !CValue { |
| 5162 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 5163 | |
| 5164 | const inst_ty = f.air.typeOfIndex(inst); |
| 5200 | 5165 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 5201 | 5166 | const operand_ty = f.air.typeOf(bin_op.lhs); |
| 5202 | 5167 | |
| 5168 | const local = try f.allocLocal(inst_ty, .Const); |
| 5203 | 5169 | const writer = f.object.writer(); |
| 5204 | | try writer.writeAll("zig_"); |
| 5170 | try writer.writeAll(" = zig_"); |
| 5205 | 5171 | try writer.writeAll(operation); |
| 5206 | 5172 | try writer.writeByte('_'); |
| 5207 | 5173 | try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty); |
| ... | ... | @@ -5209,7 +5175,8 @@ fn airCmpBuiltinCall( |
| 5209 | 5175 | try f.writeCValue(writer, try f.resolveInst(bin_op.lhs), .FunctionArgument); |
| 5210 | 5176 | try writer.writeAll(", "); |
| 5211 | 5177 | try f.writeCValue(writer, try f.resolveInst(bin_op.rhs), .FunctionArgument); |
| 5212 | | try writer.print(") {s} {}", .{ operator, try f.fmtIntLiteral(Type.initTag(.i32), Value.zero) }); |
| 5178 | try writer.print(") {s} {};\n", .{ operator, try f.fmtIntLiteral(Type.initTag(.i32), Value.zero) }); |
| 5179 | return local; |
| 5213 | 5180 | } |
| 5214 | 5181 | |
| 5215 | 5182 | fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue { |
| ... | ... | @@ -5946,18 +5913,15 @@ fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVal |
| 5946 | 5913 | return local; |
| 5947 | 5914 | } |
| 5948 | 5915 | |
| 5949 | | fn airBinFloatOp( |
| 5950 | | f: *Function, |
| 5951 | | inst: Air.Inst.Index, |
| 5952 | | operation: []const u8, |
| 5953 | | ) !void { |
| 5916 | fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue { |
| 5917 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 5954 | 5918 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 5955 | 5919 | const writer = f.object.writer(); |
| 5956 | 5920 | const inst_ty = f.air.typeOfIndex(inst); |
| 5957 | 5921 | const lhs = try f.resolveInst(bin_op.lhs); |
| 5958 | 5922 | const rhs = try f.resolveInst(bin_op.rhs); |
| 5959 | | |
| 5960 | | try writer.writeAll("zig_libc_name_"); |
| 5923 | const local = try f.allocLocal(inst_ty, .Const); |
| 5924 | try writer.writeAll(" = zig_libc_name_"); |
| 5961 | 5925 | try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty); |
| 5962 | 5926 | try writer.writeByte('('); |
| 5963 | 5927 | try writer.writeAll(operation); |
| ... | ... | @@ -5965,7 +5929,8 @@ fn airBinFloatOp( |
| 5965 | 5929 | try f.writeCValue(writer, lhs, .FunctionArgument); |
| 5966 | 5930 | try writer.writeAll(", "); |
| 5967 | 5931 | try f.writeCValue(writer, rhs, .FunctionArgument); |
| 5968 | | try writer.writeAll(")"); |
| 5932 | try writer.writeAll(");\n"); |
| 5933 | return local; |
| 5969 | 5934 | } |
| 5970 | 5935 | |
| 5971 | 5936 | fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue { |