Skip to content

Commit 421bc43

Browse files
committed
Legalize: implement soft-float legalizations
A new `Legalize.Feature` tag is introduced for each float bit width (16/32/64/80/128). When e.g. `soft_f16` is enabled, all arithmetic and comparison operations on `f16` are converted to calls to the appropriate compiler_rt function using the new AIR tag `.legalize_compiler_rt_call`. This includes casts where the source *or* target type is `f16`, or integer<=>float conversions to or from `f16`. Occasionally, operations are legalized to blocks because there is extra code required; for instance, legalizing `@floatFromInt` where the integer type is larger than 64 bits requires calling an arbitrary-width integer conversion function which accepts a pointer to the integer, so we need to use `alloc` to create such a pointer, and store the integer there (after possibly zero-extending or sign-extending it). No backend currently uses these new legalizations (and as such, no backend currently needs to implement `.legalize_compiler_rt_call`). However, for testing purposes, I tried modifying the self-hosted x86_64 backend to enable all of the soft-float features (and implement the AIR instruction). This modified backend was able to pass all of the behavior tests (except for one `@mod` test where the LLVM backend has a bug resulting in incorrect compiler-rt behavior!), including the tests specific to the self-hosted x86_64 backend. `f16` and `f80` legalizations are likely of particular interest to backend developers, because most architectures do not have instructions to operate on these types. However, enabling *all* of these legalization passes can be useful when developing a new backend to hit the ground running and pass a good amount of tests more easily.
1 parent 49c7653 commit 421bc43

File tree

14 files changed

+1366
-73
lines changed

14 files changed

+1366
-73
lines changed

src/Air.zig

Lines changed: 354 additions & 0 deletions
Large diffs are not rendered by default.

src/Air/Legalize.zig

Lines changed: 940 additions & 68 deletions
Large diffs are not rendered by default.

src/Air/Liveness.zig

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,24 @@ fn analyzeInst(
776776
const bin = a.air.extraData(Air.Bin, pl_op.payload).data;
777777
return analyzeOperands(a, pass, data, inst, .{ pl_op.operand, bin.lhs, bin.rhs });
778778
},
779+
780+
.legalize_compiler_rt_call => {
781+
const extra = a.air.extraData(Air.Call, inst_datas[@intFromEnum(inst)].legalize_compiler_rt_call.payload);
782+
const args: []const Air.Inst.Ref = @ptrCast(a.air.extra.items[extra.end..][0..extra.data.args_len]);
783+
if (args.len <= bpi - 1) {
784+
var buf: [bpi - 1]Air.Inst.Ref = @splat(.none);
785+
@memcpy(buf[0..args.len], args);
786+
return analyzeOperands(a, pass, data, inst, buf);
787+
}
788+
var big = try AnalyzeBigOperands(pass).init(a, data, inst, args.len + 1);
789+
defer big.deinit();
790+
var i: usize = args.len;
791+
while (i > 0) {
792+
i -= 1;
793+
try big.feed(args[i]);
794+
}
795+
return big.finish();
796+
},
779797
}
780798
}
781799

src/Air/Liveness/Verify.zig

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,15 @@ fn verifyBody(self: *Verify, body: []const Air.Inst.Index) Error!void {
583583
const bin = self.air.extraData(Air.Bin, pl_op.payload).data;
584584
try self.verifyInstOperands(inst, .{ pl_op.operand, bin.lhs, bin.rhs });
585585
},
586+
.legalize_compiler_rt_call => {
587+
const extra = self.air.extraData(Air.Call, data[@intFromEnum(inst)].legalize_compiler_rt_call.payload);
588+
const args: []const Air.Inst.Ref = @ptrCast(self.air.extra.items[extra.end..][0..extra.data.args_len]);
589+
var bt = self.liveness.iterateBigTomb(inst);
590+
for (args) |arg| {
591+
try self.verifyOperand(inst, arg, bt.feed());
592+
}
593+
try self.verifyInst(inst);
594+
},
586595
}
587596
}
588597
}

src/Air/print.zig

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,7 @@ const Writer = struct {
333333
.cmp_vector, .cmp_vector_optimized => try w.writeCmpVector(s, inst),
334334
.runtime_nav_ptr => try w.writeRuntimeNavPtr(s, inst),
335335
.legalize_vec_store_elem => try w.writeLegalizeVecStoreElem(s, inst),
336+
.legalize_compiler_rt_call => try w.writeLegalizeCompilerRtCall(s, inst),
336337

337338
.work_item_id,
338339
.work_group_size,
@@ -522,6 +523,19 @@ const Writer = struct {
522523
try s.writeAll(", ");
523524
}
524525

526+
fn writeLegalizeCompilerRtCall(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
527+
const inst_data = w.air.instructions.items(.data)[@intFromEnum(inst)].legalize_compiler_rt_call;
528+
const extra = w.air.extraData(Air.Call, inst_data.payload);
529+
const args: []const Air.Inst.Ref = @ptrCast(w.air.extra.items[extra.end..][0..extra.data.args_len]);
530+
531+
try s.print("{t}, [", .{inst_data.func});
532+
for (args, 0..) |arg, i| {
533+
if (i != 0) try s.writeAll(", ");
534+
try w.writeOperand(s, inst, i, arg);
535+
}
536+
try s.writeByte(']');
537+
}
538+
525539
fn writeShuffleOne(w: *Writer, s: *std.Io.Writer, inst: Air.Inst.Index) Error!void {
526540
const unwrapped = w.air.unwrapShuffleOne(w.pt.zcu, inst);
527541
try w.writeType(s, unwrapped.result_ty);

src/Air/types_resolved.zig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,12 @@ fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool {
418418
for (inputs) |input| if (input != .none and !checkRef(input, zcu)) return false;
419419
},
420420

421+
.legalize_compiler_rt_call => {
422+
const extra = air.extraData(Air.Call, data.legalize_compiler_rt_call.payload);
423+
const args: []const Air.Inst.Ref = @ptrCast(air.extra.items[extra.end..][0..extra.data.args_len]);
424+
for (args) |arg| if (!checkRef(arg, zcu)) return false;
425+
},
426+
421427
.trap,
422428
.breakpoint,
423429
.ret_addr,

src/codegen/aarch64/Select.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ pub fn analyze(isel: *Select, air_body: []const Air.Inst.Index) !void {
137137
// No "scalarize" legalizations are enabled, so these instructions never appear.
138138
.legalize_vec_elem_val => unreachable,
139139
.legalize_vec_store_elem => unreachable,
140+
// No soft float legalizations are enabled.
141+
.legalize_compiler_rt_call => unreachable,
140142

141143
.arg,
142144
.ret_addr,

src/codegen/c.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3328,6 +3328,8 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) Error!void {
33283328
// No "scalarize" legalizations are enabled, so these instructions never appear.
33293329
.legalize_vec_elem_val => unreachable,
33303330
.legalize_vec_store_elem => unreachable,
3331+
// No soft float legalizations are enabled.
3332+
.legalize_compiler_rt_call => unreachable,
33313333
33323334
.arg => try airArg(f, inst),
33333335

src/codegen/llvm.zig

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4889,6 +4889,8 @@ pub const FuncGen = struct {
48894889
// No "scalarize" legalizations are enabled, so these instructions never appear.
48904890
.legalize_vec_elem_val => unreachable,
48914891
.legalize_vec_store_elem => unreachable,
4892+
// No soft float legalizations are enabled.
4893+
.legalize_compiler_rt_call => unreachable,
48924894

48934895
.add => try self.airAdd(inst, .normal),
48944896
.add_optimized => try self.airAdd(inst, .fast),
@@ -6670,7 +6672,9 @@ pub const FuncGen = struct {
66706672
"",
66716673
);
66726674

6673-
const rt_int_bits = compilerRtIntBits(@intCast(operand_scalar_ty.bitSize(zcu)));
6675+
const rt_int_bits = compilerRtIntBits(@intCast(operand_scalar_ty.bitSize(zcu))) orelse {
6676+
return self.todo("float_from_int from '{f}' without intrinsics", .{operand_scalar_ty.fmt(pt)});
6677+
};
66746678
const rt_int_ty = try o.builder.intType(rt_int_bits);
66756679
var extended = try self.wip.conv(
66766680
if (is_signed_int) .signed else .unsigned,
@@ -6739,7 +6743,9 @@ pub const FuncGen = struct {
67396743
);
67406744
}
67416745

6742-
const rt_int_bits = compilerRtIntBits(@intCast(dest_scalar_ty.bitSize(zcu)));
6746+
const rt_int_bits = compilerRtIntBits(@intCast(dest_scalar_ty.bitSize(zcu))) orelse {
6747+
return self.todo("int_from_float to '{f}' without intrinsics", .{dest_scalar_ty.fmt(pt)});
6748+
};
67436749
const ret_ty = try o.builder.intType(rt_int_bits);
67446750
const libc_ret_ty = if (rt_int_bits == 128 and (target.os.tag == .windows and target.cpu.arch == .x86_64)) b: {
67456751
// On Windows x86-64, "ti" functions must use Vector(2, u64) instead of the standard
@@ -12823,13 +12829,13 @@ const optional_layout_version = 3;
1282312829

1282412830
const lt_errors_fn_name = "__zig_lt_errors_len";
1282512831

12826-
fn compilerRtIntBits(bits: u16) u16 {
12832+
fn compilerRtIntBits(bits: u16) ?u16 {
1282712833
inline for (.{ 32, 64, 128 }) |b| {
1282812834
if (bits <= b) {
1282912835
return b;
1283012836
}
1283112837
}
12832-
return bits;
12838+
return null;
1283312839
}
1283412840

1283512841
fn buildAllocaInner(

src/codegen/riscv64/CodeGen.zig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1395,6 +1395,8 @@ fn genBody(func: *Func, body: []const Air.Inst.Index) InnerError!void {
13951395
// No "scalarize" legalizations are enabled, so these instructions never appear.
13961396
.legalize_vec_elem_val => unreachable,
13971397
.legalize_vec_store_elem => unreachable,
1398+
// No soft float legalizations are enabled.
1399+
.legalize_compiler_rt_call => unreachable,
13981400

13991401
.add,
14001402
.add_wrap,

0 commit comments

Comments
 (0)