authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-11-30 16:11:27+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2022-11-30 17:11:06+02:00
log15cc83e27ae8a1740d9b7e2ec14044903979a832
tree13a95cac845f3baaa5c6a63fa9bd76cf60976845
parentf4afeb3ffd7f968d2c93839dc5a1f2a744e114ff

cbe: reduce amount of temporary locals


2 files changed, 155 insertions(+), 129 deletions(-)

src/codegen/c.zig+153-129
......@@ -50,6 +50,8 @@ pub const CValue = union(enum) {
5050 /// Render these bytes literally.
5151 /// TODO make this a [*:0]const u8 to save memory
5252 bytes: []const u8,
53 /// Index of an instruction that should later be rendered inline.
54 inline_index: Air.Inst.Index,
5355};
5456
5557const BlockData = struct {
......@@ -79,6 +81,7 @@ const ValueRenderLocation = enum {
7981 FunctionArgument,
8082 Initializer,
8183 Other,
84 condition,
8285};
8386
8487const BuiltinInfo = enum {
......@@ -278,6 +281,19 @@ pub const Function = struct {
278281 return result;
279282 }
280283
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
281297 fn wantSafety(f: *Function) bool {
282298 return switch (f.object.dg.module.optimizeMode()) {
283299 .Debug, .ReleaseSafe => true,
......@@ -313,10 +329,74 @@ pub const Function = struct {
313329 .constant => |inst| {
314330 const ty = f.air.typeOf(inst);
315331 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");
317367 },
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
320400 }
321401 }
322402
......@@ -2072,7 +2152,7 @@ pub const DeclGen = struct {
20722152
20732153 fn writeCValue(dg: *DeclGen, w: anytype, c_value: CValue) !void {
20742154 switch (c_value) {
2075 .none => unreachable,
2155 .none, .inline_index => unreachable,
20762156 .local => |i| return w.print("t{d}", .{i}),
20772157 .local_ref => |i| return w.print("&t{d}", .{i}),
20782158 .constant => unreachable,
......@@ -2091,7 +2171,7 @@ pub const DeclGen = struct {
20912171
20922172 fn writeCValueDeref(dg: *DeclGen, w: anytype, c_value: CValue) !void {
20932173 switch (c_value) {
2094 .none => unreachable,
2174 .none, .inline_index => unreachable,
20952175 .local => |i| return w.print("(*t{d})", .{i}),
20962176 .local_ref => |i| return w.print("t{d}", .{i}),
20972177 .constant => unreachable,
......@@ -2121,7 +2201,7 @@ pub const DeclGen = struct {
21212201
21222202 fn writeCValueDerefMember(dg: *DeclGen, writer: anytype, c_value: CValue, member: CValue) !void {
21232203 switch (c_value) {
2124 .none, .constant, .field, .undef => unreachable,
2204 .none, .constant, .field, .undef, .inline_index => unreachable,
21252205 .local, .arg, .decl, .identifier, .bytes => {
21262206 try dg.writeCValue(writer, c_value);
21272207 try writer.writeAll("->");
......@@ -2437,37 +2517,26 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
24372517 .ptr_add => try airPtrAddSub(f, inst, '+'),
24382518 .ptr_sub => try airPtrAddSub(f, inst, '-'),
24392519
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 },
24452523
24462524 .neg => try airFloatNeg(f, inst),
2447 .div_float => try airBinBuiltinCall(f, inst, "div", .None),
2525 .div_float => CValue{ .inline_index = inst },
24482526
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 },
24622531
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 },
24662535
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 },
24712540
24722541 .sqrt,
24732542 .sin,
......@@ -2492,30 +2561,30 @@ fn genBody(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail, OutO
24922561 .mul_with_overflow => try airOverflow(f, inst, "mul", .Bits),
24932562 .shl_with_overflow => try airOverflow(f, inst, "shl", .Bits),
24942563
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 },
24972566
24982567 .slice => try airSlice(f, inst),
24992568
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 },
25042573
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 },
25072576
25082577 .cmp_vector => return f.fail("TODO: C backend: implement cmp_vector", .{}),
25092578 .cmp_lt_errors_len => try airCmpLtErrorsLen(f, inst),
25102579
25112580 // 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 },
25192588
25202589 .optional_payload => try airOptionalPayload(f, inst),
25212590 .optional_payload_ptr => try airOptionalPayloadPtr(f, inst),
......@@ -3260,25 +3329,18 @@ fn airOverflow(f: *Function, inst: Air.Inst.Index, operation: []const u8, info:
32603329 return local;
32613330}
32623331
3263fn airNot(f: *Function, inst: Air.Inst.Index) !CValue {
3264 if (f.liveness.isUnused(inst)) return CValue.none;
3265
3332fn airNot(f: *Function, inst: Air.Inst.Index) !void {
32663333 const ty_op = f.air.instructions.items(.data)[inst].ty_op;
32673334 const op = try f.resolveInst(ty_op.operand);
32683335
32693336 const writer = f.object.writer();
32703337 const inst_ty = f.air.typeOfIndex(inst);
3271 const local = try f.allocLocal(inst_ty, .Const);
32723338
32733339 const target = f.object.dg.module.getTarget();
32743340 if (inst_ty.bitSize(target) > 64) {}
32753341
3276 try writer.writeAll(" = ");
32773342 try writer.writeByte(if (inst_ty.tag() == .bool) '!' else '~');
32783343 try f.writeCValue(writer, op, .Other);
3279 try writer.writeAll(";\n");
3280
3281 return local;
32823344}
32833345
32843346fn airBinOp(
......@@ -3287,62 +3349,49 @@ fn airBinOp(
32873349 operator: []const u8,
32883350 operation: []const u8,
32893351 info: BuiltinInfo,
3290) !CValue {
3291 if (f.liveness.isUnused(inst)) return CValue.none;
3292
3352) !void {
32933353 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
32943354
32953355 const operand_ty = f.air.typeOf(bin_op.lhs);
32963356 const target = f.object.dg.module.getTarget();
32973357 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);
32993359
3300 const inst_ty = f.air.typeOfIndex(inst);
33013360 const lhs = try f.resolveInst(bin_op.lhs);
33023361 const rhs = try f.resolveInst(bin_op.rhs);
33033362
33043363 const writer = f.object.writer();
3305 const local = try f.allocLocal(inst_ty, .Const);
3306
3307 try writer.writeAll(" = ");
33083364 try f.writeCValue(writer, lhs, .Other);
33093365 try writer.writeByte(' ');
33103366 try writer.writeAll(operator);
33113367 try writer.writeByte(' ');
33123368 try f.writeCValue(writer, rhs, .Other);
3313 try writer.writeAll(";\n");
3314
3315 return local;
33163369}
33173370
3318fn airCmpOp(f: *Function, inst: Air.Inst.Index, operator: []const u8, operation: []const u8) !CValue {
3319 if (f.liveness.isUnused(inst)) return CValue.none;
3320
3371fn airCmpOp(
3372 f: *Function,
3373 inst: Air.Inst.Index,
3374 operator: []const u8,
3375 operation: []const u8,
3376) !void {
33213377 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
33223378
33233379 const operand_ty = f.air.typeOf(bin_op.lhs);
33243380 const target = f.object.dg.module.getTarget();
33253381 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");
33273383 if (operand_ty.isRuntimeFloat())
3328 return try airCmpBuiltinCall(f, inst, operator, operation);
3384 return airCmpBuiltinCall(f, inst, operator, operation);
33293385
3330 const inst_ty = f.air.typeOfIndex(inst);
33313386 const lhs = try f.resolveInst(bin_op.lhs);
33323387 const rhs = try f.resolveInst(bin_op.rhs);
33333388
33343389 const writer = f.object.writer();
3335 const local = try f.allocLocal(inst_ty, .Const);
3336
3337 try writer.writeAll(" = ");
33383390 try f.writeCValue(writer, lhs, .Other);
33393391 try writer.writeByte(' ');
33403392 try writer.writeAll(operator);
33413393 try writer.writeByte(' ');
33423394 try f.writeCValue(writer, rhs, .Other);
3343 try writer.writeAll(";\n");
3344
3345 return local;
33463395}
33473396
33483397fn airEquality(
......@@ -3351,27 +3400,20 @@ fn airEquality(
33513400 negate_prefix: []const u8,
33523401 operator: []const u8,
33533402 operation: []const u8,
3354) !CValue {
3355 if (f.liveness.isUnused(inst)) return CValue.none;
3356
3403) !void {
33573404 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
33583405
33593406 const operand_ty = f.air.typeOf(bin_op.lhs);
33603407 const target = f.object.dg.module.getTarget();
33613408 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");
33633410 if (operand_ty.isRuntimeFloat())
3364 return try airCmpBuiltinCall(f, inst, operator, operation);
3411 return airCmpBuiltinCall(f, inst, operator, operation);
33653412
33663413 const lhs = try f.resolveInst(bin_op.lhs);
33673414 const rhs = try f.resolveInst(bin_op.rhs);
33683415
33693416 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
33753417 if (operand_ty.zigTypeTag() == .Optional and !operand_ty.isPtrLikeOptional()) {
33763418 // (A && B) || (C && (A == B))
33773419 // A = lhs.is_null ; B = rhs.is_null ; C = rhs.payload == lhs.payload
......@@ -3388,9 +3430,8 @@ fn airEquality(
33883430 try f.writeCValue(writer, lhs, .Other);
33893431 try writer.writeAll(".is_null == ");
33903432 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;
33943435 }
33953436
33963437 try f.writeCValue(writer, lhs, .Other);
......@@ -3398,9 +3439,6 @@ fn airEquality(
33983439 try writer.writeAll(operator);
33993440 try writer.writeByte(' ');
34003441 try f.writeCValue(writer, rhs, .Other);
3401 try writer.writeAll(";\n");
3402
3403 return local;
34043442}
34053443
34063444fn airCmpLtErrorsLen(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -3454,26 +3492,23 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
34543492 return local;
34553493}
34563494
3457fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []const u8) !CValue {
3458 if (f.liveness.isUnused(inst)) return CValue.none;
3459
3495fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []const u8) !void {
34603496 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
34613497
34623498 const inst_ty = f.air.typeOfIndex(inst);
34633499 const target = f.object.dg.module.getTarget();
34643500 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);
34663502 if (inst_ty.isRuntimeFloat())
3467 return try airBinFloatOp(f, inst, operation);
3503 return airBinFloatOp(f, inst, operation);
34683504
34693505 const lhs = try f.resolveInst(bin_op.lhs);
34703506 const rhs = try f.resolveInst(bin_op.rhs);
34713507
34723508 const writer = f.object.writer();
3473 const local = try f.allocLocal(inst_ty, .Const);
34743509
34753510 // (lhs <> rhs) ? lhs : rhs
3476 try writer.writeAll(" = (");
3511 try writer.writeAll("(");
34773512 try f.writeCValue(writer, lhs, .Other);
34783513 try writer.writeByte(' ');
34793514 try writer.writeByte(operator);
......@@ -3483,9 +3518,6 @@ fn airMinMax(f: *Function, inst: Air.Inst.Index, operator: u8, operation: []cons
34833518 try f.writeCValue(writer, lhs, .Other);
34843519 try writer.writeAll(" : ");
34853520 try f.writeCValue(writer, rhs, .Other);
3486 try writer.writeAll(";\n");
3487
3488 return local;
34893521}
34903522
34913523fn airSlice(f: *Function, inst: Air.Inst.Index) !CValue {
......@@ -3801,7 +3833,7 @@ fn airBitcast(f: *Function, inst: Air.Inst.Index) !CValue {
38013833 if (f.liveness.isUnused(inst) or !inst_ty.hasRuntimeBits()) return CValue.none;
38023834
38033835 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);
38053837
38063838 const writer = f.object.writer();
38073839 if (inst_ty.isPtrAtRuntime() and
......@@ -3899,7 +3931,7 @@ fn airLoop(f: *Function, inst: Air.Inst.Index) !CValue {
38993931 const body = f.air.extra[loop.end..][0..loop.data.body_len];
39003932 const writer = f.object.writer();
39013933 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);
39033935 try writer.writeAll(") ");
39043936 try genBody(f, body);
39053937 try writer.writeByte('\n');
......@@ -3915,7 +3947,7 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {
39153947 const writer = f.object.writer();
39163948
39173949 try writer.writeAll("if (");
3918 try f.writeCValue(writer, cond, .Other);
3950 try f.writeCValue(writer, cond, .condition);
39193951 try writer.writeAll(") ");
39203952 try genBody(f, then_body);
39213953 try writer.writeAll(" else ");
......@@ -4945,16 +4977,12 @@ fn airBinBuiltinCall(
49454977 inst: Air.Inst.Index,
49464978 operation: []const u8,
49474979 info: BuiltinInfo,
4948) !CValue {
4949 if (f.liveness.isUnused(inst)) return CValue.none;
4950
4951 const inst_ty = f.air.typeOfIndex(inst);
4980) !void {
49524981 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
49534982 const operand_ty = f.air.typeOf(bin_op.lhs);
49544983
4955 const local = try f.allocLocal(inst_ty, .Const);
49564984 const writer = f.object.writer();
4957 try writer.writeAll(" = zig_");
4985 try writer.writeAll("zig_");
49584986 try writer.writeAll(operation);
49594987 try writer.writeByte('_');
49604988 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
......@@ -4963,8 +4991,7 @@ fn airBinBuiltinCall(
49634991 try writer.writeAll(", ");
49644992 try f.writeCValue(writer, try f.resolveInst(bin_op.rhs), .FunctionArgument);
49654993 try f.object.dg.renderBuiltinInfo(writer, operand_ty, info);
4966 try writer.writeAll(");\n");
4967 return local;
4994 try writer.writeAll(")");
49684995}
49694996
49704997fn airCmpBuiltinCall(
......@@ -4972,16 +4999,12 @@ fn airCmpBuiltinCall(
49724999 inst: Air.Inst.Index,
49735000 operator: []const u8,
49745001 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 {
49795003 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
49805004 const operand_ty = f.air.typeOf(bin_op.lhs);
49815005
4982 const local = try f.allocLocal(inst_ty, .Const);
49835006 const writer = f.object.writer();
4984 try writer.writeAll(" = zig_");
5007 try writer.writeAll("zig_");
49855008 try writer.writeAll(operation);
49865009 try writer.writeByte('_');
49875010 try f.object.dg.renderTypeForBuiltinFnName(writer, operand_ty);
......@@ -4989,8 +5012,7 @@ fn airCmpBuiltinCall(
49895012 try f.writeCValue(writer, try f.resolveInst(bin_op.lhs), .FunctionArgument);
49905013 try writer.writeAll(", ");
49915014 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) });
49945016}
49955017
49965018fn 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
57275749 return local;
57285750}
57295751
5730fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CValue {
5731 if (f.liveness.isUnused(inst)) return CValue.none;
5752fn airBinFloatOp(
5753 f: *Function,
5754 inst: Air.Inst.Index,
5755 operation: []const u8,
5756) !void {
57325757 const bin_op = f.air.instructions.items(.data)[inst].bin_op;
57335758 const writer = f.object.writer();
57345759 const inst_ty = f.air.typeOfIndex(inst);
57355760 const lhs = try f.resolveInst(bin_op.lhs);
57365761 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_");
57395764 try f.object.dg.renderTypeForBuiltinFnName(writer, inst_ty);
57405765 try writer.writeByte('(');
57415766 try writer.writeAll(operation);
......@@ -5743,8 +5768,7 @@ fn airBinFloatOp(f: *Function, inst: Air.Inst.Index, operation: []const u8) !CVa
57435768 try f.writeCValue(writer, lhs, .FunctionArgument);
57445769 try writer.writeAll(", ");
57455770 try f.writeCValue(writer, rhs, .FunctionArgument);
5746 try writer.writeAll(");\n");
5747 return local;
5771 try writer.writeAll(")");
57485772}
57495773
57505774fn airMulAdd(f: *Function, inst: Air.Inst.Index) !CValue {
test/behavior/math.zig+2
......@@ -357,6 +357,8 @@ fn comptimeAdd(comptime a: comptime_int, comptime b: comptime_int) comptime_int
357357}
358358
359359test "binary not" {
360 if (builtin.zig_backend == .stage2_c) return error.SkipZigTest; // TODO
361
360362 try expect(comptime x: {
361363 break :x ~@as(u16, 0b1010101010101010) == 0b0101010101010101;
362364 });