| ... | @@ -50,8 +50,6 @@ pub const CValue = union(enum) { | ... | @@ -50,8 +50,6 @@ pub const CValue = union(enum) { |
| 50 | /// Render these bytes literally. | 50 | /// Render these bytes literally. |
| 51 | /// TODO make this a [*:0]const u8 to save memory | 51 | /// TODO make this a [*:0]const u8 to save memory |
| 52 | bytes: []const u8, | 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 | const BlockData = struct { | 55 | const BlockData = struct { |
| ... | @@ -81,7 +79,6 @@ const ValueRenderLocation = enum { | ... | @@ -81,7 +79,6 @@ const ValueRenderLocation = enum { |
| 81 | FunctionArgument, | 79 | FunctionArgument, |
| 82 | Initializer, | 80 | Initializer, |
| 83 | Other, | 81 | Other, |
| 84 | condition, | | |
| 85 | }; | 82 | }; |
| 86 | | 83 | |
| 87 | const BuiltinInfo = enum { | 84 | const BuiltinInfo = enum { |
| ... | @@ -281,19 +278,6 @@ pub const Function = struct { | ... | @@ -281,19 +278,6 @@ pub const Function = struct { |
| 281 | return result; | 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 | fn wantSafety(f: *Function) bool { | 281 | fn wantSafety(f: *Function) bool { |
| 298 | return switch (f.object.dg.module.optimizeMode()) { | 282 | return switch (f.object.dg.module.optimizeMode()) { |
| 299 | .Debug, .ReleaseSafe => true, | 283 | .Debug, .ReleaseSafe => true, |
| ... | @@ -329,74 +313,10 @@ pub const Function = struct { | ... | @@ -329,74 +313,10 @@ pub const Function = struct { |
| 329 | .constant => |inst| { | 313 | .constant => |inst| { |
| 330 | const ty = f.air.typeOf(inst); | 314 | const ty = f.air.typeOf(inst); |
| 331 | const val = f.air.value(inst).?; | 315 | const val = f.air.value(inst).?; |
| 332 | try f.object.dg.renderValue(w, ty, val, location); | 316 | return 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"); | | |
| 367 | }, | 317 | }, |
| 368 | .div_floor => try airBinBuiltinCall(f, inst, "div_floor", .None), | 318 | .undef => |ty| return f.object.dg.renderValue(w, ty, Value.undef, location), |
| 369 | .mod => try airBinBuiltinCall(f, inst, "mod", .None), | 319 | else => return f.object.dg.writeCValue(w, c_value), |
| 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 | | |
| 400 | } | 320 | } |
| 401 | } | 321 | } |
| 402 | | 322 | |
| ... | @@ -2245,7 +2165,7 @@ pub const DeclGen = struct { | ... | @@ -2245,7 +2165,7 @@ pub const DeclGen = struct { |
| 2245 | | 2165 | |
| 2246 | fn writeCValue(dg: *DeclGen, w: anytype, c_value: CValue) !void { | 2166 | fn writeCValue(dg: *DeclGen, w: anytype, c_value: CValue) !void { |
| 2247 | switch (c_value) { | 2167 | switch (c_value) { |
| 2248 | .none, .inline_index => unreachable, | 2168 | .none => unreachable, |
| 2249 | .local => |i| return w.print("t{d}", .{i}), | 2169 | .local => |i| return w.print("t{d}", .{i}), |
| 2250 | .local_ref => |i| return w.print("&t{d}", .{i}), | 2170 | .local_ref => |i| return w.print("&t{d}", .{i}), |
| 2251 | .constant => unreachable, | 2171 | .constant => unreachable, |
| ... | @@ -2264,7 +2184,7 @@ pub const DeclGen = struct { | ... | @@ -2264,7 +2184,7 @@ pub const DeclGen = struct { |
| 2264 | | 2184 | |
| 2265 | fn writeCValueDeref(dg: *DeclGen, w: anytype, c_value: CValue) !void { | 2185 | fn writeCValueDeref(dg: *DeclGen, w: anytype, c_value: CValue) !void { |
| 2266 | switch (c_value) { | 2186 | switch (c_value) { |
| 2267 | .none, .inline_index => unreachable, | 2187 | .none => unreachable, |
| 2268 | .local => |i| return w.print("(*t{d})", .{i}), | 2188 | .local => |i| return w.print("(*t{d})", .{i}), |
| 2269 | .local_ref => |i| return w.print("t{d}", .{i}), | 2189 | .local_ref => |i| return w.print("t{d}", .{i}), |
| 2270 | .constant => unreachable, | 2190 | .constant => unreachable, |
| ... | @@ -2294,7 +2214,7 @@ pub const DeclGen = struct { | ... | @@ -2294,7 +2214,7 @@ pub const DeclGen = struct { |
| 2294 | | 2214 | |
| 2295 | fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void { | 2215 | fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void { |
| 2296 | switch (c_value) { | 2216 | switch (c_value) { |
| 2297 | .none, .constant, .field, .undef, .inline_index => unreachable, | 2217 | .none, .constant, .field, .undef => unreachable, |
| 2298 | .local, .arg, .decl, .identifier, .bytes => { | 2218 | .local, .arg, .decl, .identifier, .bytes => { |
| 2299 | try dg.writeCValue(writer, c_value); | 2219 | try dg.writeCValue(writer, c_value); |
| 2300 | try writer.writeAll("->"); | 2220 | try writer.writeAll("->"); |
| ... | @@ -2633,26 +2553,37 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, | ... | @@ -2633,26 +2553,37 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, |
| 2633 | .ptr_add => try airPtrAddSub(f, inst, '+'), | 2553 | .ptr_add => try airPtrAddSub(f, inst, '+'), |
| 2634 | .ptr_sub => try airPtrAddSub(f, inst, '-'), | 2554 | .ptr_sub => try airPtrAddSub(f, inst, '-'), |
| 2635 | | 2555 | |
| 2636 | .add => CValue{ .inline_index = inst }, | 2556 | // TODO use a different strategy for add, sub, mul, div |
| 2637 | .sub => CValue{ .inline_index = inst }, | 2557 | // that communicates to the optimizer that wrapping is UB. |
| 2638 | .mul => CValue{ .inline_index = inst }, | 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 | .neg => try airFloatNeg(f, inst), | 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 }, | 2565 | .div_trunc, .div_exact => try airBinOp(f, inst, "/", "div_trunc", .None), |
| 2644 | .rem => CValue{ .inline_index = inst }, | 2566 | .rem => blk: { |
| 2645 | .div_floor => CValue{ .inline_index = inst }, | 2567 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 2646 | .mod => CValue{ .inline_index = inst }, | 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 }, | 2579 | .addwrap => try airBinBuiltinCall(f, inst, "addw", .Bits), |
| 2649 | .subwrap => CValue{ .inline_index = inst }, | 2580 | .subwrap => try airBinBuiltinCall(f, inst, "subw", .Bits), |
| 2650 | .mulwrap => CValue{ .inline_index = inst }, | 2581 | .mulwrap => try airBinBuiltinCall(f, inst, "mulw", .Bits), |
| 2651 | | 2582 | |
| 2652 | .add_sat => CValue{ .inline_index = inst }, | 2583 | .add_sat => try airBinBuiltinCall(f, inst, "adds", .Bits), |
| 2653 | .sub_sat => CValue{ .inline_index = inst }, | 2584 | .sub_sat => try airBinBuiltinCall(f, inst, "subs", .Bits), |
| 2654 | .mul_sat => CValue{ .inline_index = inst }, | 2585 | .mul_sat => try airBinBuiltinCall(f, inst, "muls", .Bits), |
| 2655 | .shl_sat => CValue{ .inline_index = inst }, | 2586 | .shl_sat => try airBinBuiltinCall(f, inst, "shls", .Bits), |
| 2656 | | 2587 | |
| 2657 | .sqrt, | 2588 | .sqrt, |
| 2658 | .sin, | 2589 | .sin, |
| ... | @@ -2677,30 +2608,30 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, | ... | @@ -2677,30 +2608,30 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, |
| 2677 | .mul_with_overflow => try airOverflow(f, inst, "mul", .Bits), | 2608 | .mul_with_overflow => try airOverflow(f, inst, "mul", .Bits), |
| 2678 | .shl_with_overflow => try airOverflow(f, inst, "shl", .Bits), | 2609 | .shl_with_overflow => try airOverflow(f, inst, "shl", .Bits), |
| 2679 | | 2610 | |
| 2680 | .min => CValue{ .inline_index = inst }, | 2611 | .min => try airMinMax(f, inst, '<', "fmin"), |
| 2681 | .max => CValue{ .inline_index = inst }, | 2612 | .max => try airMinMax(f, inst, '>', "fmax"), |
| 2682 | | 2613 | |
| 2683 | .slice => try airSlice(f, inst), | 2614 | .slice => try airSlice(f, inst), |
| 2684 | | 2615 | |
| 2685 | .cmp_gt => CValue{ .inline_index = inst }, | 2616 | .cmp_gt => try airCmpOp(f, inst, ">", "gt"), |
| 2686 | .cmp_gte => CValue{ .inline_index = inst }, | 2617 | .cmp_gte => try airCmpOp(f, inst, ">=", "ge"), |
| 2687 | .cmp_lt => CValue{ .inline_index = inst }, | 2618 | .cmp_lt => try airCmpOp(f, inst, "<", "lt"), |
| 2688 | .cmp_lte => CValue{ .inline_index = inst }, | 2619 | .cmp_lte => try airCmpOp(f, inst, "<=", "le"), |
| 2689 | | 2620 | |
| 2690 | .cmp_eq => CValue{ .inline_index = inst }, | 2621 | .cmp_eq => try airEquality(f, inst, "((", "==", "eq"), |
| 2691 | .cmp_neq => CValue{ .inline_index = inst }, | 2622 | .cmp_neq => try airEquality(f, inst, "!((", "!=", "ne"), |
| 2692 | | 2623 | |
| 2693 | .cmp_vector => return f.fail("TODO: C backend: implement cmp_vector", .{}), | 2624 | .cmp_vector => return f.fail("TODO: C backend: implement cmp_vector", .{}), |
| 2694 | .cmp_lt_errors_len => try airCmpLtErrorsLen(f, inst), | 2625 | .cmp_lt_errors_len => try airCmpLtErrorsLen(f, inst), |
| 2695 | | 2626 | |
| 2696 | // bool_and and bool_or are non-short-circuit operations | 2627 | // bool_and and bool_or are non-short-circuit operations |
| 2697 | .bool_and, .bit_and => CValue{ .inline_index = inst }, | 2628 | .bool_and, .bit_and => try airBinOp(f, inst, "&", "and", .None), |
| 2698 | .bool_or, .bit_or => CValue{ .inline_index = inst }, | 2629 | .bool_or, .bit_or => try airBinOp(f, inst, "|", "or", .None), |
| 2699 | .xor => CValue{ .inline_index = inst }, | 2630 | .xor => try airBinOp(f, inst, "^", "xor", .None), |
| 2700 | .shr, .shr_exact => CValue{ .inline_index = inst }, | 2631 | .shr, .shr_exact => try airBinBuiltinCall(f, inst, "shr", .None), |
| 2701 | .shl, => CValue{ .inline_index = inst }, | 2632 | .shl, => try airBinBuiltinCall(f, inst, "shlw", .Bits), |
| 2702 | .shl_exact => CValue{ .inline_index = inst }, | 2633 | .shl_exact => try airBinOp(f, inst, "<<", "shl", .None), |
| 2703 | .not => CValue{ .inline_index = inst }, | 2634 | .not => try airNot (f, inst), |
| 2704 | | 2635 | |
| 2705 | .optional_payload => try airOptionalPayload(f, inst), | 2636 | .optional_payload => try airOptionalPayload(f, inst), |
| 2706 | .optional_payload_ptr => try airOptionalPayloadPtr(f, inst), | 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,21 +3380,22 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: |
| 3449 | return local; | 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 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 3386 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 3454 | const op = try f.resolveInst(ty_op.operand); | 3387 | const op = try f.resolveInst(ty_op.operand); |
| 3455 | | 3388 | |
| 3456 | const writer = f.object.writer(); | 3389 | const writer = f.object.writer(); |
| 3457 | const inst_ty = f.air.typeOfIndex(inst); | 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(); | 3393 | try writer.writeAll(" = "); |
| 3460 | if (inst_ty.bitSize(target) > 64) {} | | |
| 3461 | | | |
| 3462 | try writer.writeByte('('); | | |
| 3463 | try f.renderTypecast(writer, inst_ty); | | |
| 3464 | try writer.writeByte(')'); | | |
| 3465 | try writer.writeByte(if (inst_ty.tag() == .bool) '!' else '~'); | 3394 | try writer.writeByte(if (inst_ty.tag() == .bool) '!' else '~'); |
| 3466 | try f.writeCValue(writer, op, .Other); | 3395 | try f.writeCValue(writer, op, .Other); |
| | 3396 | try writer.writeAll(";\n"); |
| | 3397 | |
| | 3398 | return local; |
| 3467 | } | 3399 | } |
| 3468 | | 3400 | |
| 3469 | fn airBinOp( | 3401 | fn airBinOp( |
| ... | @@ -3472,54 +3404,62 @@ fn airBinOp( | ... | @@ -3472,54 +3404,62 @@ fn airBinOp( |
| 3472 | operator: []const u8, | 3404 | operator: []const u8, |
| 3473 | operation: []const u8, | 3405 | operation: []const u8, |
| 3474 | info: BuiltinInfo, | 3406 | info: BuiltinInfo, |
| 3475 | ) !void { | 3407 | ) !CValue { |
| | 3408 | if (f.liveness.isUnused(inst)) return CValue.none; |
| | 3409 | |
| 3476 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 3410 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 3477 | | 3411 | |
| 3478 | const operand_ty = f.air.typeOf(bin_op.lhs); | 3412 | const operand_ty = f.air.typeOf(bin_op.lhs); |
| 3479 | const target = f.object.dg.module.getTarget(); | 3413 | const target = f.object.dg.module.getTarget(); |
| 3480 | if ((operand_ty.isInt() and operand_ty.bitSize(target) > 64) or operand_ty.isRuntimeFloat()) | 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 | const inst_ty = f.air.typeOfIndex(inst); | 3417 | const inst_ty = f.air.typeOfIndex(inst); |
| 3484 | const lhs = try f.resolveInst(bin_op.lhs); | 3418 | const lhs = try f.resolveInst(bin_op.lhs); |
| 3485 | const rhs = try f.resolveInst(bin_op.rhs); | 3419 | const rhs = try f.resolveInst(bin_op.rhs); |
| 3486 | | 3420 | |
| 3487 | const writer = f.object.writer(); | 3421 | const writer = f.object.writer(); |
| 3488 | try writer.writeByte('('); | 3422 | const local = try f.allocLocal(inst_ty, .Const); |
| 3489 | try f.renderTypecast(writer, inst_ty); | 3423 | |
| 3490 | try writer.writeAll(")("); | 3424 | try writer.writeAll(" = "); |
| 3491 | try f.writeCValue(writer, lhs, .Other); | 3425 | try f.writeCValue(writer, lhs, .Other); |
| 3492 | try writer.writeByte(' '); | 3426 | try writer.writeByte(' '); |
| 3493 | try writer.writeAll(operator); | 3427 | try writer.writeAll(operator); |
| 3494 | try writer.writeByte(' '); | 3428 | try writer.writeByte(' '); |
| 3495 | try f.writeCValue(writer, rhs, .Other); | 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( | 3435 | fn airCmpOp(f: *Function, inst: Air.Inst.Index, operator: []const u8, operation: []const u8) !CValue { |
| 3500 | f: *Function, | 3436 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 3501 | inst: Air.Inst.Index, | 3437 | |
| 3502 | operator: []const u8, | | |
| 3503 | operation: []const u8, | | |
| 3504 | ) !void { | | |
| 3505 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 3438 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 3506 | | 3439 | |
| 3507 | const operand_ty = f.air.typeOf(bin_op.lhs); | 3440 | const operand_ty = f.air.typeOf(bin_op.lhs); |
| 3508 | const target = f.object.dg.module.getTarget(); | 3441 | const target = f.object.dg.module.getTarget(); |
| 3509 | if (operand_ty.isInt() and operand_ty.bitSize(target) > 64) | 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 | if (operand_ty.isRuntimeFloat()) | 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 | const lhs = try f.resolveInst(bin_op.lhs); | 3448 | const lhs = try f.resolveInst(bin_op.lhs); |
| 3515 | const rhs = try f.resolveInst(bin_op.rhs); | 3449 | const rhs = try f.resolveInst(bin_op.rhs); |
| 3516 | | 3450 | |
| 3517 | const writer = f.object.writer(); | 3451 | const writer = f.object.writer(); |
| | 3452 | const local = try f.allocLocal(inst_ty, .Const); |
| | 3453 | |
| | 3454 | try writer.writeAll(" = "); |
| 3518 | try f.writeCValue(writer, lhs, .Other); | 3455 | try f.writeCValue(writer, lhs, .Other); |
| 3519 | try writer.writeByte(' '); | 3456 | try writer.writeByte(' '); |
| 3520 | try writer.writeAll(operator); | 3457 | try writer.writeAll(operator); |
| 3521 | try writer.writeByte(' '); | 3458 | try writer.writeByte(' '); |
| 3522 | try f.writeCValue(writer, rhs, .Other); | 3459 | try f.writeCValue(writer, rhs, .Other); |
| | 3460 | try writer.writeAll(";\n"); |
| | 3461 | |
| | 3462 | return local; |
| 3523 | } | 3463 | } |
| 3524 | | 3464 | |
| 3525 | fn airEquality( | 3465 | fn airEquality( |
| ... | @@ -3528,20 +3468,27 @@ fn airEquality( | ... | @@ -3528,20 +3468,27 @@ fn airEquality( |
| 3528 | negate_prefix: []const u8, | 3468 | negate_prefix: []const u8, |
| 3529 | operator: []const u8, | 3469 | operator: []const u8, |
| 3530 | operation: []const u8, | 3470 | operation: []const u8, |
| 3531 | ) !void { | 3471 | ) !CValue { |
| | 3472 | if (f.liveness.isUnused(inst)) return CValue.none; |
| | 3473 | |
| 3532 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 3474 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 3533 | | 3475 | |
| 3534 | const operand_ty = f.air.typeOf(bin_op.lhs); | 3476 | const operand_ty = f.air.typeOf(bin_op.lhs); |
| 3535 | const target = f.object.dg.module.getTarget(); | 3477 | const target = f.object.dg.module.getTarget(); |
| 3536 | if (operand_ty.isInt() and operand_ty.bitSize(target) > 64) | 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 | if (operand_ty.isRuntimeFloat()) | 3480 | if (operand_ty.isRuntimeFloat()) |
| 3539 | return airCmpBuiltinCall(f, inst, operator, operation); | 3481 | return try airCmpBuiltinCall(f, inst, operator, operation); |
| 3540 | | 3482 | |
| 3541 | const lhs = try f.resolveInst(bin_op.lhs); | 3483 | const lhs = try f.resolveInst(bin_op.lhs); |
| 3542 | const rhs = try f.resolveInst(bin_op.rhs); | 3484 | const rhs = try f.resolveInst(bin_op.rhs); |
| 3543 | | 3485 | |
| 3544 | const writer = f.object.writer(); | 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 | if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) { | 3492 | if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) { |
| 3546 | // (A && B) || (C && (A == B)) | 3493 | // (A && B) || (C && (A == B)) |
| 3547 | // A = lhs.is_null ; B = rhs.is_null ; C = rhs.payload == lhs.payload | 3494 | // A = lhs.is_null ; B = rhs.is_null ; C = rhs.payload == lhs.payload |
| ... | @@ -3558,8 +3505,9 @@ fn airEquality( | ... | @@ -3558,8 +3505,9 @@ fn airEquality( |
| 3558 | try f.writeCValue(writer, lhs, .Other); | 3505 | try f.writeCValue(writer, lhs, .Other); |
| 3559 | try writer.writeAll(".is_null == "); | 3506 | try writer.writeAll(".is_null == "); |
| 3560 | try f.writeCValue(writer, rhs, .Other); | 3507 | try f.writeCValue(writer, rhs, .Other); |
| 3561 | try writer.writeAll(".is_null))"); | 3508 | try writer.writeAll(".is_null));\n"); |
| 3562 | return; | 3509 | |
| | 3510 | return local; |
| 3563 | } | 3511 | } |
| 3564 | | 3512 | |
| 3565 | try f.writeCValue(writer, lhs, .Other); | 3513 | try f.writeCValue(writer, lhs, .Other); |
| ... | @@ -3567,6 +3515,9 @@ fn airEquality( | ... | @@ -3567,6 +3515,9 @@ fn airEquality( |
| 3567 | try writer.writeAll(operator); | 3515 | try writer.writeAll(operator); |
| 3568 | try writer.writeByte(' '); | 3516 | try writer.writeByte(' '); |
| 3569 | try f.writeCValue(writer, rhs, .Other); | 3517 | try f.writeCValue(writer, rhs, .Other); |
| | 3518 | try writer.writeAll(";\n"); |
| | 3519 | |
| | 3520 | return local; |
| 3570 | } | 3521 | } |
| 3571 | | 3522 | |
| 3572 | fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue { | 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,23 +3571,26 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue { |
| 3620 | return local; | 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 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 3577 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 3625 | | 3578 | |
| 3626 | const inst_ty = f.air.typeOfIndex(inst); | 3579 | const inst_ty = f.air.typeOfIndex(inst); |
| 3627 | const target = f.object.dg.module.getTarget(); | 3580 | const target = f.object.dg.module.getTarget(); |
| 3628 | if (inst_ty.isInt() and inst_ty.bitSize(target) > 64) | 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 | if (inst_ty.isRuntimeFloat()) | 3583 | if (inst_ty.isRuntimeFloat()) |
| 3631 | return airBinFloatOp(f, inst, operation); | 3584 | return try airBinFloatOp(f, inst, operation); |
| 3632 | | 3585 | |
| 3633 | const lhs = try f.resolveInst(bin_op.lhs); | 3586 | const lhs = try f.resolveInst(bin_op.lhs); |
| 3634 | const rhs = try f.resolveInst(bin_op.rhs); | 3587 | const rhs = try f.resolveInst(bin_op.rhs); |
| 3635 | | 3588 | |
| 3636 | const writer = f.object.writer(); | 3589 | const writer = f.object.writer(); |
| | 3590 | const local = try f.allocLocal(inst_ty, .Const); |
| 3637 | | 3591 | |
| 3638 | // (lhs <> rhs) ? lhs : rhs | 3592 | // (lhs <> rhs) ? lhs : rhs |
| 3639 | try writer.writeAll("("); | 3593 | try writer.writeAll(" = ("); |
| 3640 | try f.writeCValue(writer, lhs, .Other); | 3594 | try f.writeCValue(writer, lhs, .Other); |
| 3641 | try writer.writeByte(' '); | 3595 | try writer.writeByte(' '); |
| 3642 | try writer.writeByte(operator); | 3596 | try writer.writeByte(operator); |
| ... | @@ -3646,6 +3600,9 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons | ... | @@ -3646,6 +3600,9 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons |
| 3646 | try f.writeCValue(writer, lhs, .Other); | 3600 | try f.writeCValue(writer, lhs, .Other); |
| 3647 | try writer.writeAll(" : "); | 3601 | try writer.writeAll(" : "); |
| 3648 | try f.writeCValue(writer, rhs, .Other); | 3602 | try f.writeCValue(writer, rhs, .Other); |
| | 3603 | try writer.writeAll(";\n"); |
| | 3604 | |
| | 3605 | return local; |
| 3649 | } | 3606 | } |
| 3650 | | 3607 | |
| 3651 | fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue { | 3608 | fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue { |
| ... | @@ -3961,7 +3918,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3961,7 +3918,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3961 | if (f.liveness.isUnused(inst) or !src_ty.hasRuntimeBits()) return CValue.none; | 3918 | if (f.liveness.isUnused(inst) or !src_ty.hasRuntimeBits()) return CValue.none; |
| 3962 | | 3919 | |
| 3963 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 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 | const dest_ty = f.air.typeOf(ty_op.operand); | 3922 | const dest_ty = f.air.typeOf(ty_op.operand); |
| 3966 | const target = f.object.dg.module.getTarget(); | 3923 | const target = f.object.dg.module.getTarget(); |
| 3967 | | 3924 | |
| ... | @@ -4067,7 +4024,7 @@ fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4067,7 +4024,7 @@ fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4067 | const body = f.air.extra[loop.end..][0..loop.data.body_len]; | 4024 | const body = f.air.extra[loop.end..][0..loop.data.body_len]; |
| 4068 | const writer = f.object.writer(); | 4025 | const writer = f.object.writer(); |
| 4069 | try writer.writeAll("while ("); | 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 | try writer.writeAll(") "); | 4028 | try writer.writeAll(") "); |
| 4072 | try genBody(f, body); | 4029 | try genBody(f, body); |
| 4073 | try writer.writeByte('\n'); | 4030 | try writer.writeByte('\n'); |
| ... | @@ -4083,7 +4040,7 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -4083,7 +4040,7 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 4083 | const writer = f.object.writer(); | 4040 | const writer = f.object.writer(); |
| 4084 | | 4041 | |
| 4085 | try writer.writeAll("if ("); | 4042 | try writer.writeAll("if ("); |
| 4086 | try f.writeCValue(writer, cond, .condition); | 4043 | try f.writeCValue(writer, cond, .Other); |
| 4087 | try writer.writeAll(") "); | 4044 | try writer.writeAll(") "); |
| 4088 | try genBody(f, then_body); | 4045 | try genBody(f, then_body); |
| 4089 | try writer.writeAll(" else "); | 4046 | try writer.writeAll(" else "); |
| ... | @@ -5174,12 +5131,16 @@ fn airBinBuiltinCall( | ... | @@ -5174,12 +5131,16 @@ fn airBinBuiltinCall( |
| 5174 | inst: Air.Inst.Index, | 5131 | inst: Air.Inst.Index, |
| 5175 | operation: []const u8, | 5132 | operation: []const u8, |
| 5176 | info: BuiltinInfo, | 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 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 5138 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 5179 | const operand_ty = f.air.typeOf(bin_op.lhs); | 5139 | const operand_ty = f.air.typeOf(bin_op.lhs); |
| 5180 | | 5140 | |
| | 5141 | const local = try f.allocLocal(inst_ty, .Const); |
| 5181 | const writer = f.object.writer(); | 5142 | const writer = f.object.writer(); |
| 5182 | try writer.writeAll("zig_"); | 5143 | try writer.writeAll(" = zig_"); |
| 5183 | try writer.writeAll(operation); | 5144 | try writer.writeAll(operation); |
| 5184 | try writer.writeByte('_'); | 5145 | try writer.writeByte('_'); |
| 5185 | try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty); | 5146 | try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty); |
| ... | @@ -5188,7 +5149,8 @@ fn airBinBuiltinCall( | ... | @@ -5188,7 +5149,8 @@ fn airBinBuiltinCall( |
| 5188 | try writer.writeAll(", "); | 5149 | try writer.writeAll(", "); |
| 5189 | try f.writeCValue(writer, try f.resolveInst(bin_op.rhs), .FunctionArgument); | 5150 | try f.writeCValue(writer, try f.resolveInst(bin_op.rhs), .FunctionArgument); |
| 5190 | try f.object.dg.renderBuiltinInfo(writer, operand_ty, info); | 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 | fn airCmpBuiltinCall( | 5156 | fn airCmpBuiltinCall( |
| ... | @@ -5196,12 +5158,16 @@ fn airCmpBuiltinCall( | ... | @@ -5196,12 +5158,16 @@ fn airCmpBuiltinCall( |
| 5196 | inst: Air.Inst.Index, | 5158 | inst: Air.Inst.Index, |
| 5197 | operator: []const u8, | 5159 | operator: []const u8, |
| 5198 | operation: []const u8, | 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 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 5165 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 5201 | const operand_ty = f.air.typeOf(bin_op.lhs); | 5166 | const operand_ty = f.air.typeOf(bin_op.lhs); |
| 5202 | | 5167 | |
| | 5168 | const local = try f.allocLocal(inst_ty, .Const); |
| 5203 | const writer = f.object.writer(); | 5169 | const writer = f.object.writer(); |
| 5204 | try writer.writeAll("zig_"); | 5170 | try writer.writeAll(" = zig_"); |
| 5205 | try writer.writeAll(operation); | 5171 | try writer.writeAll(operation); |
| 5206 | try writer.writeByte('_'); | 5172 | try writer.writeByte('_'); |
| 5207 | try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty); | 5173 | try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty); |
| ... | @@ -5209,7 +5175,8 @@ fn airCmpBuiltinCall( | ... | @@ -5209,7 +5175,8 @@ fn airCmpBuiltinCall( |
| 5209 | try f.writeCValue(writer, try f.resolveInst(bin_op.lhs), .FunctionArgument); | 5175 | try f.writeCValue(writer, try f.resolveInst(bin_op.lhs), .FunctionArgument); |
| 5210 | try writer.writeAll(", "); | 5176 | try writer.writeAll(", "); |
| 5211 | try f.writeCValue(writer, try f.resolveInst(bin_op.rhs), .FunctionArgument); | 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 | fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue { | 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,18 +5913,15 @@ fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVal |
| 5946 | return local; | 5913 | return local; |
| 5947 | } | 5914 | } |
| 5948 | | 5915 | |
| 5949 | fn airBinFloatOp( | 5916 | fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue { |
| 5950 | f: *Function, | 5917 | if (f.liveness.isUnused(inst)) return CValue.none; |
| 5951 | inst: Air.Inst.Index, | | |
| 5952 | operation: []const u8, | | |
| 5953 | ) !void { | | |
| 5954 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 5918 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 5955 | const writer = f.object.writer(); | 5919 | const writer = f.object.writer(); |
| 5956 | const inst_ty = f.air.typeOfIndex(inst); | 5920 | const inst_ty = f.air.typeOfIndex(inst); |
| 5957 | const lhs = try f.resolveInst(bin_op.lhs); | 5921 | const lhs = try f.resolveInst(bin_op.lhs); |
| 5958 | const rhs = try f.resolveInst(bin_op.rhs); | 5922 | const rhs = try f.resolveInst(bin_op.rhs); |
| 5959 | | 5923 | const local = try f.allocLocal(inst_ty, .Const); |
| 5960 | try writer.writeAll("zig_libc_name_"); | 5924 | try writer.writeAll(" = zig_libc_name_"); |
| 5961 | try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty); | 5925 | try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty); |
| 5962 | try writer.writeByte('('); | 5926 | try writer.writeByte('('); |
| 5963 | try writer.writeAll(operation); | 5927 | try writer.writeAll(operation); |
| ... | @@ -5965,7 +5929,8 @@ fn airBinFloatOp( | ... | @@ -5965,7 +5929,8 @@ fn airBinFloatOp( |
| 5965 | try f.writeCValue(writer, lhs, .FunctionArgument); | 5929 | try f.writeCValue(writer, lhs, .FunctionArgument); |
| 5966 | try writer.writeAll(", "); | 5930 | try writer.writeAll(", "); |
| 5967 | try f.writeCValue(writer, rhs, .FunctionArgument); | 5931 | try f.writeCValue(writer, rhs, .FunctionArgument); |
| 5968 | try writer.writeAll(")"); | 5932 | try writer.writeAll(");\n"); |
| | 5933 | return local; |
| 5969 | } | 5934 | } |
| 5970 | | 5935 | |
| 5971 | fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue { | 5936 | fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue { |