| ... | @@ -50,6 +50,8 @@ pub const CValue = union(enum) { | ... | @@ -50,6 +50,8 @@ 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, |
| 53 | }; | 55 | }; |
| 54 | | 56 | |
| 55 | const BlockData = struct { | 57 | const BlockData = struct { |
| ... | @@ -79,6 +81,7 @@ const ValueRenderLocation = enum { | ... | @@ -79,6 +81,7 @@ const ValueRenderLocation = enum { |
| 79 | FunctionArgument, | 81 | FunctionArgument, |
| 80 | Initializer, | 82 | Initializer, |
| 81 | Other, | 83 | Other, |
| | 84 | condition, |
| 82 | }; | 85 | }; |
| 83 | | 86 | |
| 84 | const BuiltinInfo = enum { | 87 | const BuiltinInfo = enum { |
| ... | @@ -278,6 +281,19 @@ pub const Function = struct { | ... | @@ -278,6 +281,19 @@ pub const Function = struct { |
| 278 | return result; | 281 | return result; |
| 279 | } | 282 | } |
| 280 | | 283 | |
| | 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 | |
| 281 | fn wantSafety(f: *Function) bool { | 297 | fn wantSafety(f: *Function) bool { |
| 282 | return switch (f.object.dg.module.optimizeMode()) { | 298 | return switch (f.object.dg.module.optimizeMode()) { |
| 283 | .Debug, .ReleaseSafe => true, | 299 | .Debug, .ReleaseSafe => true, |
| ... | @@ -313,10 +329,74 @@ pub const Function = struct { | ... | @@ -313,10 +329,74 @@ pub const Function = struct { |
| 313 | .constant => |inst| { | 329 | .constant => |inst| { |
| 314 | const ty = f.air.typeOf(inst); | 330 | const ty = f.air.typeOf(inst); |
| 315 | const val = f.air.value(inst).?; | 331 | const val = f.air.value(inst).?; |
| 316 | return f.object.dg.renderValue(w, ty, val, location); | 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"); |
| 317 | }, | 367 | }, |
| 318 | .undef => |ty| return f.object.dg.renderValue(w, ty, Value.undef, location), | 368 | .div_floor => try airBinBuiltinCall(f, inst, "div_floor", .None), |
| 319 | else => return f.object.dg.writeCValue(w, c_value), | 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 |
| 320 | } | 400 | } |
| 321 | } | 401 | } |
| 322 | | 402 | |
| ... | @@ -2072,7 +2152,7 @@ pub const DeclGen = struct { | ... | @@ -2072,7 +2152,7 @@ pub const DeclGen = struct { |
| 2072 | | 2152 | |
| 2073 | fn writeCValue(dg: *DeclGen, w: anytype, c_value: CValue) !void { | 2153 | fn writeCValue(dg: *DeclGen, w: anytype, c_value: CValue) !void { |
| 2074 | switch (c_value) { | 2154 | switch (c_value) { |
| 2075 | .none => unreachable, | 2155 | .none, .inline_index => unreachable, |
| 2076 | .local => |i| return w.print("t{d}", .{i}), | 2156 | .local => |i| return w.print("t{d}", .{i}), |
| 2077 | .local_ref => |i| return w.print("&t{d}", .{i}), | 2157 | .local_ref => |i| return w.print("&t{d}", .{i}), |
| 2078 | .constant => unreachable, | 2158 | .constant => unreachable, |
| ... | @@ -2091,7 +2171,7 @@ pub const DeclGen = struct { | ... | @@ -2091,7 +2171,7 @@ pub const DeclGen = struct { |
| 2091 | | 2171 | |
| 2092 | fn writeCValueDeref(dg: *DeclGen, w: anytype, c_value: CValue) !void { | 2172 | fn writeCValueDeref(dg: *DeclGen, w: anytype, c_value: CValue) !void { |
| 2093 | switch (c_value) { | 2173 | switch (c_value) { |
| 2094 | .none => unreachable, | 2174 | .none, .inline_index => unreachable, |
| 2095 | .local => |i| return w.print("(*t{d})", .{i}), | 2175 | .local => |i| return w.print("(*t{d})", .{i}), |
| 2096 | .local_ref => |i| return w.print("t{d}", .{i}), | 2176 | .local_ref => |i| return w.print("t{d}", .{i}), |
| 2097 | .constant => unreachable, | 2177 | .constant => unreachable, |
| ... | @@ -2121,7 +2201,7 @@ pub const DeclGen = struct { | ... | @@ -2121,7 +2201,7 @@ pub const DeclGen = struct { |
| 2121 | | 2201 | |
| 2122 | fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void { | 2202 | fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void { |
| 2123 | switch (c_value) { | 2203 | switch (c_value) { |
| 2124 | .none, .constant, .field, .undef => unreachable, | 2204 | .none, .constant, .field, .undef, .inline_index => unreachable, |
| 2125 | .local, .arg, .decl, .identifier, .bytes => { | 2205 | .local, .arg, .decl, .identifier, .bytes => { |
| 2126 | try dg.writeCValue(writer, c_value); | 2206 | try dg.writeCValue(writer, c_value); |
| 2127 | try writer.writeAll("->"); | 2207 | try writer.writeAll("->"); |
| ... | @@ -2437,37 +2517,26 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO | ... | @@ -2437,37 +2517,26 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 2437 | .ptr_add => try airPtrAddSub(f, inst, '+'), | 2517 | .ptr_add => try airPtrAddSub(f, inst, '+'), |
| 2438 | .ptr_sub => try airPtrAddSub(f, inst, '-'), | 2518 | .ptr_sub => try airPtrAddSub(f, inst, '-'), |
| 2439 | | 2519 | |
| 2440 | // TODO use a different strategy for add, sub, mul, div | 2520 | .add => CValue{ .inline_index = inst }, |
| 2441 | // that communicates to the optimizer that wrapping is UB. | 2521 | .sub => CValue{ .inline_index = inst }, |
| 2442 | .add => try airBinOp(f, inst, "+", "add", .None), | 2522 | .mul => CValue{ .inline_index = inst }, |
| 2443 | .sub => try airBinOp(f, inst, "-", "sub", .None), | | |
| 2444 | .mul => try airBinOp(f, inst, "*", "mul", .None), | | |
| 2445 | | 2523 | |
| 2446 | .neg => try airFloatNeg(f, inst), | 2524 | .neg => try airFloatNeg(f, inst), |
| 2447 | .div_float => try airBinBuiltinCall(f, inst, "div", .None), | 2525 | .div_float => CValue{ .inline_index = inst }, |
| 2448 | | 2526 | |
| 2449 | .div_trunc, .div_exact => try airBinOp(f, inst, "/", "div_trunc", .None), | 2527 | .div_trunc, .div_exact => CValue{ .inline_index = inst }, |
| 2450 | .rem => blk: { | 2528 | .rem => CValue{ .inline_index = inst }, |
| 2451 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 2529 | .div_floor => CValue{ .inline_index = inst }, |
| 2452 | const lhs_ty = f.air.typeOf(bin_op.lhs); | 2530 | .mod => CValue{ .inline_index = inst }, |
| 2453 | // For binary operations @TypeOf(lhs)==@TypeOf(rhs), | | |
| 2454 | // so we only check one. | | |
| 2455 | break :blk if (lhs_ty.isInt()) | | |
| 2456 | try airBinOp(f, inst, "%", "rem", .None) | | |
| 2457 | else | | |
| 2458 | try airBinFloatOp(f, inst, "fmod"); | | |
| 2459 | }, | | |
| 2460 | .div_floor => try airBinBuiltinCall(f, inst, "div_floor", .None), | | |
| 2461 | .mod => try airBinBuiltinCall(f, inst, "mod", .None), | | |
| 2462 | | 2531 | |
| 2463 | .addwrap => try airBinBuiltinCall(f, inst, "addw", .Bits), | 2532 | .addwrap => CValue{ .inline_index = inst }, |
| 2464 | .subwrap => try airBinBuiltinCall(f, inst, "subw", .Bits), | 2533 | .subwrap => CValue{ .inline_index = inst }, |
| 2465 | .mulwrap => try airBinBuiltinCall(f, inst, "mulw", .Bits), | 2534 | .mulwrap => CValue{ .inline_index = inst }, |
| 2466 | | 2535 | |
| 2467 | .add_sat => try airBinBuiltinCall(f, inst, "adds", .Bits), | 2536 | .add_sat => CValue{ .inline_index = inst }, |
| 2468 | .sub_sat => try airBinBuiltinCall(f, inst, "subs", .Bits), | 2537 | .sub_sat => CValue{ .inline_index = inst }, |
| 2469 | .mul_sat => try airBinBuiltinCall(f, inst, "muls", .Bits), | 2538 | .mul_sat => CValue{ .inline_index = inst }, |
| 2470 | .shl_sat => try airBinBuiltinCall(f, inst, "shls", .Bits), | 2539 | .shl_sat => CValue{ .inline_index = inst }, |
| 2471 | | 2540 | |
| 2472 | .sqrt, | 2541 | .sqrt, |
| 2473 | .sin, | 2542 | .sin, |
| ... | @@ -2492,30 +2561,30 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO | ... | @@ -2492,30 +2561,30 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO |
| 2492 | .mul_with_overflow => try airOverflow(f, inst, "mul", .Bits), | 2561 | .mul_with_overflow => try airOverflow(f, inst, "mul", .Bits), |
| 2493 | .shl_with_overflow => try airOverflow(f, inst, "shl", .Bits), | 2562 | .shl_with_overflow => try airOverflow(f, inst, "shl", .Bits), |
| 2494 | | 2563 | |
| 2495 | .min => try airMinMax(f, inst, '<', "fmin"), | 2564 | .min => CValue{ .inline_index = inst }, |
| 2496 | .max => try airMinMax(f, inst, '>', "fmax"), | 2565 | .max => CValue{ .inline_index = inst }, |
| 2497 | | 2566 | |
| 2498 | .slice => try airSlice(f, inst), | 2567 | .slice => try airSlice(f, inst), |
| 2499 | | 2568 | |
| 2500 | .cmp_gt => try airCmpOp(f, inst, ">", "gt"), | 2569 | .cmp_gt => CValue{ .inline_index = inst }, |
| 2501 | .cmp_gte => try airCmpOp(f, inst, ">=", "ge"), | 2570 | .cmp_gte => CValue{ .inline_index = inst }, |
| 2502 | .cmp_lt => try airCmpOp(f, inst, "<", "lt"), | 2571 | .cmp_lt => CValue{ .inline_index = inst }, |
| 2503 | .cmp_lte => try airCmpOp(f, inst, "<=", "le"), | 2572 | .cmp_lte => CValue{ .inline_index = inst }, |
| 2504 | | 2573 | |
| 2505 | .cmp_eq => try airEquality(f, inst, "((", "==", "eq"), | 2574 | .cmp_eq => CValue{ .inline_index = inst }, |
| 2506 | .cmp_neq => try airEquality(f, inst, "!((", "!=", "ne"), | 2575 | .cmp_neq => CValue{ .inline_index = inst }, |
| 2507 | | 2576 | |
| 2508 | .cmp_vector => return f.fail("TODO: C backend: implement cmp_vector", .{}), | 2577 | .cmp_vector => return f.fail("TODO: C backend: implement cmp_vector", .{}), |
| 2509 | .cmp_lt_errors_len => try airCmpLtErrorsLen(f, inst), | 2578 | .cmp_lt_errors_len => try airCmpLtErrorsLen(f, inst), |
| 2510 | | 2579 | |
| 2511 | // bool_and and bool_or are non-short-circuit operations | 2580 | // bool_and and bool_or are non-short-circuit operations |
| 2512 | .bool_and, .bit_and => try airBinOp(f, inst, "&", "and", .None), | 2581 | .bool_and, .bit_and => CValue{ .inline_index = inst }, |
| 2513 | .bool_or, .bit_or => try airBinOp(f, inst, "|", "or", .None), | 2582 | .bool_or, .bit_or => CValue{ .inline_index = inst }, |
| 2514 | .xor => try airBinOp(f, inst, "^", "xor", .None), | 2583 | .xor => CValue{ .inline_index = inst }, |
| 2515 | .shr, .shr_exact => try airBinBuiltinCall(f, inst, "shr", .None), | 2584 | .shr, .shr_exact => CValue{ .inline_index = inst }, |
| 2516 | .shl, => try airBinBuiltinCall(f, inst, "shlw", .Bits), | 2585 | .shl, => CValue{ .inline_index = inst }, |
| 2517 | .shl_exact => try airBinOp(f, inst, "<<", "shl", .None), | 2586 | .shl_exact => CValue{ .inline_index = inst }, |
| 2518 | .not => try airNot (f, inst), | 2587 | .not => CValue{ .inline_index = inst }, |
| 2519 | | 2588 | |
| 2520 | .optional_payload => try airOptionalPayload(f, inst), | 2589 | .optional_payload => try airOptionalPayload(f, inst), |
| 2521 | .optional_payload_ptr => try airOptionalPayloadPtr(f, inst), | 2590 | .optional_payload_ptr => try airOptionalPayloadPtr(f, inst), |
| ... | @@ -3260,25 +3329,18 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: | ... | @@ -3260,25 +3329,18 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info: |
| 3260 | return local; | 3329 | return local; |
| 3261 | } | 3330 | } |
| 3262 | | 3331 | |
| 3263 | fn airNot(f: *Function, inst: Air.Inst.Index) !CValue { | 3332 | fn airNot(f: *Function, inst: Air.Inst.Index) !void { |
| 3264 | if (f.liveness.isUnused(inst)) return CValue.none; | | |
| 3265 | | | |
| 3266 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 3333 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 3267 | const op = try f.resolveInst(ty_op.operand); | 3334 | const op = try f.resolveInst(ty_op.operand); |
| 3268 | | 3335 | |
| 3269 | const writer = f.object.writer(); | 3336 | const writer = f.object.writer(); |
| 3270 | const inst_ty = f.air.typeOfIndex(inst); | 3337 | const inst_ty = f.air.typeOfIndex(inst); |
| 3271 | const local = try f.allocLocal(inst_ty, .Const); | | |
| 3272 | | 3338 | |
| 3273 | const target = f.object.dg.module.getTarget(); | 3339 | const target = f.object.dg.module.getTarget(); |
| 3274 | if (inst_ty.bitSize(target) > 64) {} | 3340 | if (inst_ty.bitSize(target) > 64) {} |
| 3275 | | 3341 | |
| 3276 | try writer.writeAll(" = "); | | |
| 3277 | try writer.writeByte(if (inst_ty.tag() == .bool) '!' else '~'); | 3342 | try writer.writeByte(if (inst_ty.tag() == .bool) '!' else '~'); |
| 3278 | try f.writeCValue(writer, op, .Other); | 3343 | try f.writeCValue(writer, op, .Other); |
| 3279 | try writer.writeAll(";\n"); | | |
| 3280 | | | |
| 3281 | return local; | | |
| 3282 | } | 3344 | } |
| 3283 | | 3345 | |
| 3284 | fn airBinOp( | 3346 | fn airBinOp( |
| ... | @@ -3287,62 +3349,49 @@ fn airBinOp( | ... | @@ -3287,62 +3349,49 @@ fn airBinOp( |
| 3287 | operator: []const u8, | 3349 | operator: []const u8, |
| 3288 | operation: []const u8, | 3350 | operation: []const u8, |
| 3289 | info: BuiltinInfo, | 3351 | info: BuiltinInfo, |
| 3290 | ) !CValue { | 3352 | ) !void { |
| 3291 | if (f.liveness.isUnused(inst)) return CValue.none; | | |
| 3292 | | | |
| 3293 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 3353 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 3294 | | 3354 | |
| 3295 | const operand_ty = f.air.typeOf(bin_op.lhs); | 3355 | const operand_ty = f.air.typeOf(bin_op.lhs); |
| 3296 | const target = f.object.dg.module.getTarget(); | 3356 | const target = f.object.dg.module.getTarget(); |
| 3297 | if ((operand_ty.isInt() and operand_ty.bitSize(target) > 64) or operand_ty.isRuntimeFloat()) | 3357 | if ((operand_ty.isInt() and operand_ty.bitSize(target) > 64) or operand_ty.isRuntimeFloat()) |
| 3298 | return try airBinBuiltinCall(f, inst, operation, info); | 3358 | return airBinBuiltinCall(f, inst, operation, info); |
| 3299 | | 3359 | |
| 3300 | const inst_ty = f.air.typeOfIndex(inst); | | |
| 3301 | const lhs = try f.resolveInst(bin_op.lhs); | 3360 | const lhs = try f.resolveInst(bin_op.lhs); |
| 3302 | const rhs = try f.resolveInst(bin_op.rhs); | 3361 | const rhs = try f.resolveInst(bin_op.rhs); |
| 3303 | | 3362 | |
| 3304 | const writer = f.object.writer(); | 3363 | const writer = f.object.writer(); |
| 3305 | const local = try f.allocLocal(inst_ty, .Const); | | |
| 3306 | | | |
| 3307 | try writer.writeAll(" = "); | | |
| 3308 | try f.writeCValue(writer, lhs, .Other); | 3364 | try f.writeCValue(writer, lhs, .Other); |
| 3309 | try writer.writeByte(' '); | 3365 | try writer.writeByte(' '); |
| 3310 | try writer.writeAll(operator); | 3366 | try writer.writeAll(operator); |
| 3311 | try writer.writeByte(' '); | 3367 | try writer.writeByte(' '); |
| 3312 | try f.writeCValue(writer, rhs, .Other); | 3368 | try f.writeCValue(writer, rhs, .Other); |
| 3313 | try writer.writeAll(";\n"); | | |
| 3314 | | | |
| 3315 | return local; | | |
| 3316 | } | 3369 | } |
| 3317 | | 3370 | |
| 3318 | fn airCmpOp(f: *Function, inst: Air.Inst.Index, operator: []const u8, operation: []const u8) !CValue { | 3371 | fn airCmpOp( |
| 3319 | if (f.liveness.isUnused(inst)) return CValue.none; | 3372 | f: *Function, |
| 3320 | | 3373 | inst: Air.Inst.Index, |
| | 3374 | operator: []const u8, |
| | 3375 | operation: []const u8, |
| | 3376 | ) !void { |
| 3321 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 3377 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 3322 | | 3378 | |
| 3323 | const operand_ty = f.air.typeOf(bin_op.lhs); | 3379 | const operand_ty = f.air.typeOf(bin_op.lhs); |
| 3324 | const target = f.object.dg.module.getTarget(); | 3380 | const target = f.object.dg.module.getTarget(); |
| 3325 | if (operand_ty.isInt() and operand_ty.bitSize(target) > 64) | 3381 | if (operand_ty.isInt() and operand_ty.bitSize(target) > 64) |
| 3326 | return try airCmpBuiltinCall(f, inst, operator, "cmp"); | 3382 | return airCmpBuiltinCall(f, inst, operator, "cmp"); |
| 3327 | if (operand_ty.isRuntimeFloat()) | 3383 | if (operand_ty.isRuntimeFloat()) |
| 3328 | return try airCmpBuiltinCall(f, inst, operator, operation); | 3384 | return airCmpBuiltinCall(f, inst, operator, operation); |
| 3329 | | 3385 | |
| 3330 | const inst_ty = f.air.typeOfIndex(inst); | | |
| 3331 | const lhs = try f.resolveInst(bin_op.lhs); | 3386 | const lhs = try f.resolveInst(bin_op.lhs); |
| 3332 | const rhs = try f.resolveInst(bin_op.rhs); | 3387 | const rhs = try f.resolveInst(bin_op.rhs); |
| 3333 | | 3388 | |
| 3334 | const writer = f.object.writer(); | 3389 | const writer = f.object.writer(); |
| 3335 | const local = try f.allocLocal(inst_ty, .Const); | | |
| 3336 | | | |
| 3337 | try writer.writeAll(" = "); | | |
| 3338 | try f.writeCValue(writer, lhs, .Other); | 3390 | try f.writeCValue(writer, lhs, .Other); |
| 3339 | try writer.writeByte(' '); | 3391 | try writer.writeByte(' '); |
| 3340 | try writer.writeAll(operator); | 3392 | try writer.writeAll(operator); |
| 3341 | try writer.writeByte(' '); | 3393 | try writer.writeByte(' '); |
| 3342 | try f.writeCValue(writer, rhs, .Other); | 3394 | try f.writeCValue(writer, rhs, .Other); |
| 3343 | try writer.writeAll(";\n"); | | |
| 3344 | | | |
| 3345 | return local; | | |
| 3346 | } | 3395 | } |
| 3347 | | 3396 | |
| 3348 | fn airEquality( | 3397 | fn airEquality( |
| ... | @@ -3351,27 +3400,20 @@ fn airEquality( | ... | @@ -3351,27 +3400,20 @@ fn airEquality( |
| 3351 | negate_prefix: []const u8, | 3400 | negate_prefix: []const u8, |
| 3352 | operator: []const u8, | 3401 | operator: []const u8, |
| 3353 | operation: []const u8, | 3402 | operation: []const u8, |
| 3354 | ) !CValue { | 3403 | ) !void { |
| 3355 | if (f.liveness.isUnused(inst)) return CValue.none; | | |
| 3356 | | | |
| 3357 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 3404 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 3358 | | 3405 | |
| 3359 | const operand_ty = f.air.typeOf(bin_op.lhs); | 3406 | const operand_ty = f.air.typeOf(bin_op.lhs); |
| 3360 | const target = f.object.dg.module.getTarget(); | 3407 | const target = f.object.dg.module.getTarget(); |
| 3361 | if (operand_ty.isInt() and operand_ty.bitSize(target) > 64) | 3408 | if (operand_ty.isInt() and operand_ty.bitSize(target) > 64) |
| 3362 | return try airCmpBuiltinCall(f, inst, operator, "cmp"); | 3409 | return airCmpBuiltinCall(f, inst, operator, "cmp"); |
| 3363 | if (operand_ty.isRuntimeFloat()) | 3410 | if (operand_ty.isRuntimeFloat()) |
| 3364 | return try airCmpBuiltinCall(f, inst, operator, operation); | 3411 | return airCmpBuiltinCall(f, inst, operator, operation); |
| 3365 | | 3412 | |
| 3366 | const lhs = try f.resolveInst(bin_op.lhs); | 3413 | const lhs = try f.resolveInst(bin_op.lhs); |
| 3367 | const rhs = try f.resolveInst(bin_op.rhs); | 3414 | const rhs = try f.resolveInst(bin_op.rhs); |
| 3368 | | 3415 | |
| 3369 | const writer = f.object.writer(); | 3416 | const writer = f.object.writer(); |
| 3370 | const inst_ty = f.air.typeOfIndex(inst); | | |
| 3371 | const local = try f.allocLocal(inst_ty, .Const); | | |
| 3372 | | | |
| 3373 | try writer.writeAll(" = "); | | |
| 3374 | | | |
| 3375 | if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) { | 3417 | if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) { |
| 3376 | // (A && B) || (C && (A == B)) | 3418 | // (A && B) || (C && (A == B)) |
| 3377 | // A = lhs.is_null ; B = rhs.is_null ; C = rhs.payload == lhs.payload | 3419 | // A = lhs.is_null ; B = rhs.is_null ; C = rhs.payload == lhs.payload |
| ... | @@ -3388,9 +3430,8 @@ fn airEquality( | ... | @@ -3388,9 +3430,8 @@ fn airEquality( |
| 3388 | try f.writeCValue(writer, lhs, .Other); | 3430 | try f.writeCValue(writer, lhs, .Other); |
| 3389 | try writer.writeAll(".is_null == "); | 3431 | try writer.writeAll(".is_null == "); |
| 3390 | try f.writeCValue(writer, rhs, .Other); | 3432 | try f.writeCValue(writer, rhs, .Other); |
| 3391 | try writer.writeAll(".is_null));\n"); | 3433 | try writer.writeAll(".is_null))"); |
| 3392 | | 3434 | return; |
| 3393 | return local; | | |
| 3394 | } | 3435 | } |
| 3395 | | 3436 | |
| 3396 | try f.writeCValue(writer, lhs, .Other); | 3437 | try f.writeCValue(writer, lhs, .Other); |
| ... | @@ -3398,9 +3439,6 @@ fn airEquality( | ... | @@ -3398,9 +3439,6 @@ fn airEquality( |
| 3398 | try writer.writeAll(operator); | 3439 | try writer.writeAll(operator); |
| 3399 | try writer.writeByte(' '); | 3440 | try writer.writeByte(' '); |
| 3400 | try f.writeCValue(writer, rhs, .Other); | 3441 | try f.writeCValue(writer, rhs, .Other); |
| 3401 | try writer.writeAll(";\n"); | | |
| 3402 | | | |
| 3403 | return local; | | |
| 3404 | } | 3442 | } |
| 3405 | | 3443 | |
| 3406 | fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue { | 3444 | fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue { |
| ... | @@ -3454,26 +3492,23 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue { | ... | @@ -3454,26 +3492,23 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue { |
| 3454 | return local; | 3492 | return local; |
| 3455 | } | 3493 | } |
| 3456 | | 3494 | |
| 3457 | fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []const u8) !CValue { | 3495 | fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []const u8) !void { |
| 3458 | if (f.liveness.isUnused(inst)) return CValue.none; | | |
| 3459 | | | |
| 3460 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 3496 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 3461 | | 3497 | |
| 3462 | const inst_ty = f.air.typeOfIndex(inst); | 3498 | const inst_ty = f.air.typeOfIndex(inst); |
| 3463 | const target = f.object.dg.module.getTarget(); | 3499 | const target = f.object.dg.module.getTarget(); |
| 3464 | if (inst_ty.isInt() and inst_ty.bitSize(target) > 64) | 3500 | if (inst_ty.isInt() and inst_ty.bitSize(target) > 64) |
| 3465 | return try airBinBuiltinCall(f, inst, operation[1..], .None); | 3501 | return airBinBuiltinCall(f, inst, operation[1..], .None); |
| 3466 | if (inst_ty.isRuntimeFloat()) | 3502 | if (inst_ty.isRuntimeFloat()) |
| 3467 | return try airBinFloatOp(f, inst, operation); | 3503 | return airBinFloatOp(f, inst, operation); |
| 3468 | | 3504 | |
| 3469 | const lhs = try f.resolveInst(bin_op.lhs); | 3505 | const lhs = try f.resolveInst(bin_op.lhs); |
| 3470 | const rhs = try f.resolveInst(bin_op.rhs); | 3506 | const rhs = try f.resolveInst(bin_op.rhs); |
| 3471 | | 3507 | |
| 3472 | const writer = f.object.writer(); | 3508 | const writer = f.object.writer(); |
| 3473 | const local = try f.allocLocal(inst_ty, .Const); | | |
| 3474 | | 3509 | |
| 3475 | // (lhs <> rhs) ? lhs : rhs | 3510 | // (lhs <> rhs) ? lhs : rhs |
| 3476 | try writer.writeAll(" = ("); | 3511 | try writer.writeAll("("); |
| 3477 | try f.writeCValue(writer, lhs, .Other); | 3512 | try f.writeCValue(writer, lhs, .Other); |
| 3478 | try writer.writeByte(' '); | 3513 | try writer.writeByte(' '); |
| 3479 | try writer.writeByte(operator); | 3514 | try writer.writeByte(operator); |
| ... | @@ -3483,9 +3518,6 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons | ... | @@ -3483,9 +3518,6 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons |
| 3483 | try f.writeCValue(writer, lhs, .Other); | 3518 | try f.writeCValue(writer, lhs, .Other); |
| 3484 | try writer.writeAll(" : "); | 3519 | try writer.writeAll(" : "); |
| 3485 | try f.writeCValue(writer, rhs, .Other); | 3520 | try f.writeCValue(writer, rhs, .Other); |
| 3486 | try writer.writeAll(";\n"); | | |
| 3487 | | | |
| 3488 | return local; | | |
| 3489 | } | 3521 | } |
| 3490 | | 3522 | |
| 3491 | fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue { | 3523 | fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue { |
| ... | @@ -3801,7 +3833,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3801,7 +3833,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3801 | if (f.liveness.isUnused(inst) or !inst_ty.hasRuntimeBits()) return CValue.none; | 3833 | if (f.liveness.isUnused(inst) or !inst_ty.hasRuntimeBits()) return CValue.none; |
| 3802 | | 3834 | |
| 3803 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; | 3835 | const ty_op = f.air.instructions.items(.data)[inst].ty_op; |
| 3804 | const operand = try f.resolveInst(ty_op.operand); | 3836 | const operand = try f.resolveInstNoInline(ty_op.operand); |
| 3805 | | 3837 | |
| 3806 | const writer = f.object.writer(); | 3838 | const writer = f.object.writer(); |
| 3807 | if (inst_ty.isPtrAtRuntime() and | 3839 | if (inst_ty.isPtrAtRuntime() and |
| ... | @@ -3899,7 +3931,7 @@ fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3899,7 +3931,7 @@ fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3899 | const body = f.air.extra[loop.end..][0..loop.data.body_len]; | 3931 | const body = f.air.extra[loop.end..][0..loop.data.body_len]; |
| 3900 | const writer = f.object.writer(); | 3932 | const writer = f.object.writer(); |
| 3901 | try writer.writeAll("while ("); | 3933 | try writer.writeAll("while ("); |
| 3902 | try f.object.dg.renderValue(writer, Type.bool, Value.true, .Other); | 3934 | try f.object.dg.renderValue(writer, Type.bool, Value.true, .condition); |
| 3903 | try writer.writeAll(") "); | 3935 | try writer.writeAll(") "); |
| 3904 | try genBody(f, body); | 3936 | try genBody(f, body); |
| 3905 | try writer.writeByte('\n'); | 3937 | try writer.writeByte('\n'); |
| ... | @@ -3915,7 +3947,7 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue { | ... | @@ -3915,7 +3947,7 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue { |
| 3915 | const writer = f.object.writer(); | 3947 | const writer = f.object.writer(); |
| 3916 | | 3948 | |
| 3917 | try writer.writeAll("if ("); | 3949 | try writer.writeAll("if ("); |
| 3918 | try f.writeCValue(writer, cond, .Other); | 3950 | try f.writeCValue(writer, cond, .condition); |
| 3919 | try writer.writeAll(") "); | 3951 | try writer.writeAll(") "); |
| 3920 | try genBody(f, then_body); | 3952 | try genBody(f, then_body); |
| 3921 | try writer.writeAll(" else "); | 3953 | try writer.writeAll(" else "); |
| ... | @@ -4945,16 +4977,12 @@ fn airBinBuiltinCall( | ... | @@ -4945,16 +4977,12 @@ fn airBinBuiltinCall( |
| 4945 | inst: Air.Inst.Index, | 4977 | inst: Air.Inst.Index, |
| 4946 | operation: []const u8, | 4978 | operation: []const u8, |
| 4947 | info: BuiltinInfo, | 4979 | info: BuiltinInfo, |
| 4948 | ) !CValue { | 4980 | ) !void { |
| 4949 | if (f.liveness.isUnused(inst)) return CValue.none; | | |
| 4950 | | | |
| 4951 | const inst_ty = f.air.typeOfIndex(inst); | | |
| 4952 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 4981 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 4953 | const operand_ty = f.air.typeOf(bin_op.lhs); | 4982 | const operand_ty = f.air.typeOf(bin_op.lhs); |
| 4954 | | 4983 | |
| 4955 | const local = try f.allocLocal(inst_ty, .Const); | | |
| 4956 | const writer = f.object.writer(); | 4984 | const writer = f.object.writer(); |
| 4957 | try writer.writeAll(" = zig_"); | 4985 | try writer.writeAll("zig_"); |
| 4958 | try writer.writeAll(operation); | 4986 | try writer.writeAll(operation); |
| 4959 | try writer.writeByte('_'); | 4987 | try writer.writeByte('_'); |
| 4960 | try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty); | 4988 | try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty); |
| ... | @@ -4963,8 +4991,7 @@ fn airBinBuiltinCall( | ... | @@ -4963,8 +4991,7 @@ fn airBinBuiltinCall( |
| 4963 | try writer.writeAll(", "); | 4991 | try writer.writeAll(", "); |
| 4964 | try f.writeCValue(writer, try f.resolveInst(bin_op.rhs), .FunctionArgument); | 4992 | try f.writeCValue(writer, try f.resolveInst(bin_op.rhs), .FunctionArgument); |
| 4965 | try f.object.dg.renderBuiltinInfo(writer, operand_ty, info); | 4993 | try f.object.dg.renderBuiltinInfo(writer, operand_ty, info); |
| 4966 | try writer.writeAll(");\n"); | 4994 | try writer.writeAll(")"); |
| 4967 | return local; | | |
| 4968 | } | 4995 | } |
| 4969 | | 4996 | |
| 4970 | fn airCmpBuiltinCall( | 4997 | fn airCmpBuiltinCall( |
| ... | @@ -4972,16 +4999,12 @@ fn airCmpBuiltinCall( | ... | @@ -4972,16 +4999,12 @@ fn airCmpBuiltinCall( |
| 4972 | inst: Air.Inst.Index, | 4999 | inst: Air.Inst.Index, |
| 4973 | operator: []const u8, | 5000 | operator: []const u8, |
| 4974 | operation: []const u8, | 5001 | operation: []const u8, |
| 4975 | ) !CValue { | 5002 | ) !void { |
| 4976 | if (f.liveness.isUnused(inst)) return CValue.none; | | |
| 4977 | | | |
| 4978 | const inst_ty = f.air.typeOfIndex(inst); | | |
| 4979 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 5003 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 4980 | const operand_ty = f.air.typeOf(bin_op.lhs); | 5004 | const operand_ty = f.air.typeOf(bin_op.lhs); |
| 4981 | | 5005 | |
| 4982 | const local = try f.allocLocal(inst_ty, .Const); | | |
| 4983 | const writer = f.object.writer(); | 5006 | const writer = f.object.writer(); |
| 4984 | try writer.writeAll(" = zig_"); | 5007 | try writer.writeAll("zig_"); |
| 4985 | try writer.writeAll(operation); | 5008 | try writer.writeAll(operation); |
| 4986 | try writer.writeByte('_'); | 5009 | try writer.writeByte('_'); |
| 4987 | try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty); | 5010 | try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty); |
| ... | @@ -4989,8 +5012,7 @@ fn airCmpBuiltinCall( | ... | @@ -4989,8 +5012,7 @@ fn airCmpBuiltinCall( |
| 4989 | try f.writeCValue(writer, try f.resolveInst(bin_op.lhs), .FunctionArgument); | 5012 | try f.writeCValue(writer, try f.resolveInst(bin_op.lhs), .FunctionArgument); |
| 4990 | try writer.writeAll(", "); | 5013 | try writer.writeAll(", "); |
| 4991 | try f.writeCValue(writer, try f.resolveInst(bin_op.rhs), .FunctionArgument); | 5014 | try f.writeCValue(writer, try f.resolveInst(bin_op.rhs), .FunctionArgument); |
| 4992 | try writer.print(") {s} {};\n", .{ operator, try f.fmtIntLiteral(Type.initTag(.i32), Value.zero) }); | 5015 | try writer.print(") {s} {}", .{ operator, try f.fmtIntLiteral(Type.initTag(.i32), Value.zero) }); |
| 4993 | return local; | | |
| 4994 | } | 5016 | } |
| 4995 | | 5017 | |
| 4996 | fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue { | 5018 | fn airCmpxchg(f: *Function, inst: Air.Inst.Index, flavor: [*:0]const u8) !CValue { |
| ... | @@ -5727,15 +5749,18 @@ fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVal | ... | @@ -5727,15 +5749,18 @@ fn airUnFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVal |
| 5727 | return local; | 5749 | return local; |
| 5728 | } | 5750 | } |
| 5729 | | 5751 | |
| 5730 | fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue { | 5752 | fn airBinFloatOp( |
| 5731 | if (f.liveness.isUnused(inst)) return CValue.none; | 5753 | f: *Function, |
| | 5754 | inst: Air.Inst.Index, |
| | 5755 | operation: []const u8, |
| | 5756 | ) !void { |
| 5732 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; | 5757 | const bin_op = f.air.instructions.items(.data)[inst].bin_op; |
| 5733 | const writer = f.object.writer(); | 5758 | const writer = f.object.writer(); |
| 5734 | const inst_ty = f.air.typeOfIndex(inst); | 5759 | const inst_ty = f.air.typeOfIndex(inst); |
| 5735 | const lhs = try f.resolveInst(bin_op.lhs); | 5760 | const lhs = try f.resolveInst(bin_op.lhs); |
| 5736 | const rhs = try f.resolveInst(bin_op.rhs); | 5761 | const rhs = try f.resolveInst(bin_op.rhs); |
| 5737 | const local = try f.allocLocal(inst_ty, .Const); | 5762 | |
| 5738 | try writer.writeAll(" = zig_libc_name_"); | 5763 | try writer.writeAll("zig_libc_name_"); |
| 5739 | try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty); | 5764 | try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty); |
| 5740 | try writer.writeByte('('); | 5765 | try writer.writeByte('('); |
| 5741 | try writer.writeAll(operation); | 5766 | try writer.writeAll(operation); |
| ... | @@ -5743,8 +5768,7 @@ fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVa | ... | @@ -5743,8 +5768,7 @@ fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVa |
| 5743 | try f.writeCValue(writer, lhs, .FunctionArgument); | 5768 | try f.writeCValue(writer, lhs, .FunctionArgument); |
| 5744 | try writer.writeAll(", "); | 5769 | try writer.writeAll(", "); |
| 5745 | try f.writeCValue(writer, rhs, .FunctionArgument); | 5770 | try f.writeCValue(writer, rhs, .FunctionArgument); |
| 5746 | try writer.writeAll(");\n"); | 5771 | try writer.writeAll(")"); |
| 5747 | return local; | | |
| 5748 | } | 5772 | } |
| 5749 | | 5773 | |
| 5750 | fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue { | 5774 | fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue { |