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