Skip to content

Commit 6e72026

Browse files
committed
Legalize: make the feature set comptime-known in zig1
This allows legalizations to be added that aren't used by zig1 without affecting the size of zig1.
1 parent 1ca213d commit 6e72026

File tree

2 files changed

+78
-42
lines changed

2 files changed

+78
-42
lines changed

src/Air/Legalize.zig

Lines changed: 65 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,36 @@
11
pt: Zcu.PerThread,
22
air_instructions: std.MultiArrayList(Air.Inst),
33
air_extra: std.ArrayListUnmanaged(u32),
4-
features: *const Features,
4+
features: if (switch (dev.env) {
5+
.bootstrap => @import("../codegen/c.zig").legalizeFeatures(undefined),
6+
else => null,
7+
}) |bootstrap_features| struct {
8+
fn init(features: *const Features) @This() {
9+
assert(features.eql(bootstrap_features.*));
10+
return .{};
11+
}
12+
/// `inline` to propagate comptime-known result.
13+
inline fn has(_: @This(), comptime feature: Feature) bool {
14+
return comptime bootstrap_features.contains(feature);
15+
}
16+
/// `inline` to propagate comptime-known result.
17+
fn hasAny(_: @This(), comptime features: []const Feature) bool {
18+
return comptime !bootstrap_features.intersectWith(.initMany(features)).eql(.initEmpty());
19+
}
20+
} else struct {
21+
features: *const Features,
22+
/// `inline` to propagate whether `dev.check` returns.
23+
inline fn init(features: *const Features) @This() {
24+
dev.check(.legalize);
25+
return .{ .features = features };
26+
}
27+
fn has(rt: @This(), comptime feature: Feature) bool {
28+
return rt.features.contains(feature);
29+
}
30+
fn hasAny(rt: @This(), comptime features: []const Feature) bool {
31+
return !rt.features.intersectWith(comptime .initMany(features)).eql(comptime .initEmpty());
32+
}
33+
},
534

635
pub const Feature = enum {
736
scalarize_add,
@@ -199,7 +228,7 @@ pub const Feature = enum {
199228
.float_from_int => .scalarize_float_from_int,
200229
.shuffle_one => .scalarize_shuffle_one,
201230
.shuffle_two => .scalarize_shuffle_two,
202-
.select => .scalarize_selects,
231+
.select => .scalarize_select,
203232
.mul_add => .scalarize_mul_add,
204233
};
205234
}
@@ -210,13 +239,12 @@ pub const Features = std.enums.EnumSet(Feature);
210239
pub const Error = std.mem.Allocator.Error;
211240

212241
pub fn legalize(air: *Air, pt: Zcu.PerThread, features: *const Features) Error!void {
213-
dev.check(.legalize);
214242
assert(!features.eql(comptime .initEmpty())); // backend asked to run legalize, but no features were enabled
215243
var l: Legalize = .{
216244
.pt = pt,
217245
.air_instructions = air.instructions.toMultiArrayList(),
218246
.air_extra = air.extra,
219-
.features = features,
247+
.features = .init(features),
220248
};
221249
defer air.* = l.getTmpAir();
222250
const main_extra = l.extraData(Air.Block, l.air_extra.items[@intFromEnum(Air.ExtraIndex.main_block)]);
@@ -278,28 +306,28 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void {
278306
.bit_and,
279307
.bit_or,
280308
.xor,
281-
=> |air_tag| if (l.features.contains(comptime .scalarize(air_tag))) {
309+
=> |air_tag| if (l.features.has(comptime .scalarize(air_tag))) {
282310
const bin_op = l.air_instructions.items(.data)[@intFromEnum(inst)].bin_op;
283311
if (l.typeOf(bin_op.lhs).isVector(zcu)) continue :inst try l.scalarize(inst, .bin_op);
284312
},
285-
.add_safe => if (l.features.contains(.expand_add_safe)) {
286-
assert(!l.features.contains(.scalarize_add_safe)); // it doesn't make sense to do both
313+
.add_safe => if (l.features.has(.expand_add_safe)) {
314+
assert(!l.features.has(.scalarize_add_safe)); // it doesn't make sense to do both
287315
continue :inst l.replaceInst(inst, .block, try l.safeArithmeticBlockPayload(inst, .add_with_overflow));
288-
} else if (l.features.contains(.scalarize_add_safe)) {
316+
} else if (l.features.has(.scalarize_add_safe)) {
289317
const bin_op = l.air_instructions.items(.data)[@intFromEnum(inst)].bin_op;
290318
if (l.typeOf(bin_op.lhs).isVector(zcu)) continue :inst try l.scalarize(inst, .bin_op);
291319
},
292-
.sub_safe => if (l.features.contains(.expand_sub_safe)) {
293-
assert(!l.features.contains(.scalarize_sub_safe)); // it doesn't make sense to do both
320+
.sub_safe => if (l.features.has(.expand_sub_safe)) {
321+
assert(!l.features.has(.scalarize_sub_safe)); // it doesn't make sense to do both
294322
continue :inst l.replaceInst(inst, .block, try l.safeArithmeticBlockPayload(inst, .sub_with_overflow));
295-
} else if (l.features.contains(.scalarize_sub_safe)) {
323+
} else if (l.features.has(.scalarize_sub_safe)) {
296324
const bin_op = l.air_instructions.items(.data)[@intFromEnum(inst)].bin_op;
297325
if (l.typeOf(bin_op.lhs).isVector(zcu)) continue :inst try l.scalarize(inst, .bin_op);
298326
},
299-
.mul_safe => if (l.features.contains(.expand_mul_safe)) {
300-
assert(!l.features.contains(.scalarize_mul_safe)); // it doesn't make sense to do both
327+
.mul_safe => if (l.features.has(.expand_mul_safe)) {
328+
assert(!l.features.has(.scalarize_mul_safe)); // it doesn't make sense to do both
301329
continue :inst l.replaceInst(inst, .block, try l.safeArithmeticBlockPayload(inst, .mul_with_overflow));
302-
} else if (l.features.contains(.scalarize_mul_safe)) {
330+
} else if (l.features.has(.scalarize_mul_safe)) {
303331
const bin_op = l.air_instructions.items(.data)[@intFromEnum(inst)].bin_op;
304332
if (l.typeOf(bin_op.lhs).isVector(zcu)) continue :inst try l.scalarize(inst, .bin_op);
305333
},
@@ -308,7 +336,7 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void {
308336
.sub_with_overflow,
309337
.mul_with_overflow,
310338
.shl_with_overflow,
311-
=> |air_tag| if (l.features.contains(comptime .scalarize(air_tag))) {
339+
=> |air_tag| if (l.features.has(comptime .scalarize(air_tag))) {
312340
const ty_pl = l.air_instructions.items(.data)[@intFromEnum(inst)].ty_pl;
313341
if (ty_pl.ty.toType().fieldType(0, zcu).isVector(zcu)) continue :inst l.replaceInst(inst, .block, try l.scalarizeOverflowBlockPayload(inst));
314342
},
@@ -320,13 +348,13 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void {
320348
.shl,
321349
.shl_exact,
322350
.shl_sat,
323-
=> |air_tag| if (!l.features.intersectWith(comptime .initMany(&.{
351+
=> |air_tag| if (l.features.hasAny(&.{
324352
.unsplat_shift_rhs,
325353
.scalarize(air_tag),
326-
})).eql(comptime .initEmpty())) {
354+
})) {
327355
const bin_op = l.air_instructions.items(.data)[@intFromEnum(inst)].bin_op;
328356
if (l.typeOf(bin_op.rhs).isVector(zcu)) {
329-
if (l.features.contains(.unsplat_shift_rhs)) {
357+
if (l.features.has(.unsplat_shift_rhs)) {
330358
if (bin_op.rhs.toInterned()) |rhs_ip_index| switch (ip.indexToKey(rhs_ip_index)) {
331359
else => {},
332360
.aggregate => |aggregate| switch (aggregate.storage) {
@@ -347,7 +375,7 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void {
347375
}
348376
}
349377
}
350-
if (l.features.contains(comptime .scalarize(air_tag))) continue :inst try l.scalarize(inst, .bin_op);
378+
if (l.features.has(comptime .scalarize(air_tag))) continue :inst try l.scalarize(inst, .bin_op);
351379
}
352380
},
353381
inline .not,
@@ -364,11 +392,11 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void {
364392
.int_from_float,
365393
.int_from_float_optimized,
366394
.float_from_int,
367-
=> |air_tag| if (l.features.contains(comptime .scalarize(air_tag))) {
395+
=> |air_tag| if (l.features.has(comptime .scalarize(air_tag))) {
368396
const ty_op = l.air_instructions.items(.data)[@intFromEnum(inst)].ty_op;
369397
if (ty_op.ty.toType().isVector(zcu)) continue :inst try l.scalarize(inst, .ty_op);
370398
},
371-
.bitcast => if (l.features.contains(.scalarize_bitcast)) {
399+
.bitcast => if (l.features.has(.scalarize_bitcast)) {
372400
const ty_op = l.air_instructions.items(.data)[@intFromEnum(inst)].ty_op;
373401

374402
const to_ty = ty_op.ty.toType();
@@ -404,10 +432,10 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void {
404432
};
405433
if (!from_ty_legal) continue :inst l.replaceInst(inst, .block, try l.scalarizeBitcastOperandBlockPayload(inst));
406434
},
407-
.intcast_safe => if (l.features.contains(.expand_intcast_safe)) {
408-
assert(!l.features.contains(.scalarize_intcast_safe)); // it doesn't make sense to do both
435+
.intcast_safe => if (l.features.has(.expand_intcast_safe)) {
436+
assert(!l.features.has(.scalarize_intcast_safe)); // it doesn't make sense to do both
409437
continue :inst l.replaceInst(inst, .block, try l.safeIntcastBlockPayload(inst));
410-
} else if (l.features.contains(.scalarize_intcast_safe)) {
438+
} else if (l.features.has(.scalarize_intcast_safe)) {
411439
const ty_op = l.air_instructions.items(.data)[@intFromEnum(inst)].ty_op;
412440
if (ty_op.ty.toType().isVector(zcu)) continue :inst try l.scalarize(inst, .ty_op);
413441
},
@@ -442,7 +470,7 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void {
442470
.trunc_float,
443471
.neg,
444472
.neg_optimized,
445-
=> |air_tag| if (l.features.contains(comptime .scalarize(air_tag))) {
473+
=> |air_tag| if (l.features.has(comptime .scalarize(air_tag))) {
446474
const un_op = l.air_instructions.items(.data)[@intFromEnum(inst)].un_op;
447475
if (l.typeOf(un_op).isVector(zcu)) continue :inst try l.scalarize(inst, .un_op);
448476
},
@@ -459,7 +487,7 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void {
459487
.cmp_neq,
460488
.cmp_neq_optimized,
461489
=> {},
462-
inline .cmp_vector, .cmp_vector_optimized => |air_tag| if (l.features.contains(comptime .scalarize(air_tag))) {
490+
inline .cmp_vector, .cmp_vector_optimized => |air_tag| if (l.features.has(comptime .scalarize(air_tag))) {
463491
const ty_pl = l.air_instructions.items(.data)[@intFromEnum(inst)].ty_pl;
464492
if (ty_pl.ty.toType().isVector(zcu)) continue :inst try l.scalarize(inst, .cmp_vector);
465493
},
@@ -513,13 +541,13 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void {
513541
.bool_and,
514542
.bool_or,
515543
=> {},
516-
.load => if (l.features.contains(.expand_packed_load)) {
544+
.load => if (l.features.has(.expand_packed_load)) {
517545
const ty_op = l.air_instructions.items(.data)[@intFromEnum(inst)].ty_op;
518546
const ptr_info = l.typeOf(ty_op.operand).ptrInfo(zcu);
519547
if (ptr_info.packed_offset.host_size > 0 and ptr_info.flags.vector_index == .none) continue :inst l.replaceInst(inst, .block, try l.packedLoadBlockPayload(inst));
520548
},
521549
.ret, .ret_safe, .ret_load => {},
522-
.store, .store_safe => if (l.features.contains(.expand_packed_store)) {
550+
.store, .store_safe => if (l.features.has(.expand_packed_store)) {
523551
const bin_op = l.air_instructions.items(.data)[@intFromEnum(inst)].bin_op;
524552
const ptr_info = l.typeOf(bin_op.lhs).ptrInfo(zcu);
525553
if (ptr_info.packed_offset.host_size > 0 and ptr_info.flags.vector_index == .none) continue :inst l.replaceInst(inst, .block, try l.packedStoreBlockPayload(inst));
@@ -542,7 +570,7 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void {
542570
.struct_field_ptr_index_2,
543571
.struct_field_ptr_index_3,
544572
=> {},
545-
.struct_field_val => if (l.features.contains(.expand_packed_struct_field_val)) {
573+
.struct_field_val => if (l.features.has(.expand_packed_struct_field_val)) {
546574
const ty_pl = l.air_instructions.items(.data)[@intFromEnum(inst)].ty_pl;
547575
const extra = l.extraData(Air.StructField, ty_pl.payload).data;
548576
switch (l.typeOf(extra.struct_operand).containerLayout(zcu)) {
@@ -564,7 +592,7 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void {
564592
.ptr_elem_ptr,
565593
.array_to_slice,
566594
=> {},
567-
.reduce, .reduce_optimized => if (l.features.contains(.reduce_one_elem_to_bitcast)) {
595+
.reduce, .reduce_optimized => if (l.features.has(.reduce_one_elem_to_bitcast)) {
568596
const reduce = l.air_instructions.items(.data)[@intFromEnum(inst)].reduce;
569597
const vector_ty = l.typeOf(reduce.operand);
570598
switch (vector_ty.vectorLen(zcu)) {
@@ -577,9 +605,9 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void {
577605
}
578606
},
579607
.splat => {},
580-
.shuffle_one => if (l.features.contains(.scalarize_shuffle_one)) continue :inst try l.scalarize(inst, .shuffle_one),
581-
.shuffle_two => if (l.features.contains(.scalarize_shuffle_two)) continue :inst try l.scalarize(inst, .shuffle_two),
582-
.select => if (l.features.contains(.scalarize_select)) continue :inst try l.scalarize(inst, .select),
608+
.shuffle_one => if (l.features.has(.scalarize_shuffle_one)) continue :inst try l.scalarize(inst, .shuffle_one),
609+
.shuffle_two => if (l.features.has(.scalarize_shuffle_two)) continue :inst try l.scalarize(inst, .shuffle_two),
610+
.select => if (l.features.has(.scalarize_select)) continue :inst try l.scalarize(inst, .select),
583611
.memset,
584612
.memset_safe,
585613
.memcpy,
@@ -597,7 +625,7 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void {
597625
.error_name,
598626
.error_set_has_value,
599627
=> {},
600-
.aggregate_init => if (l.features.contains(.expand_packed_aggregate_init)) {
628+
.aggregate_init => if (l.features.has(.expand_packed_aggregate_init)) {
601629
const ty_pl = l.air_instructions.items(.data)[@intFromEnum(inst)].ty_pl;
602630
const agg_ty = ty_pl.ty.toType();
603631
switch (agg_ty.zigTypeTag(zcu)) {
@@ -609,7 +637,7 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void {
609637
}
610638
},
611639
.union_init, .prefetch => {},
612-
.mul_add => if (l.features.contains(.scalarize_mul_add)) {
640+
.mul_add => if (l.features.has(.scalarize_mul_add)) {
613641
const pl_op = l.air_instructions.items(.data)[@intFromEnum(inst)].pl_op;
614642
if (l.typeOf(pl_op.operand).isVector(zcu)) continue :inst try l.scalarize(inst, .pl_op_bin);
615643
},
@@ -636,6 +664,7 @@ fn legalizeBody(l: *Legalize, body_start: usize, body_len: usize) Error!void {
636664
}
637665

638666
const ScalarizeForm = enum { un_op, ty_op, bin_op, pl_op_bin, bitcast, cmp_vector, shuffle_one, shuffle_two, select };
667+
/// inline to propagate comptime-known `replaceInst` result.
639668
inline fn scalarize(l: *Legalize, orig_inst: Air.Inst.Index, comptime form: ScalarizeForm) Error!Air.Inst.Tag {
640669
return l.replaceInst(orig_inst, .block, try l.scalarizeBlockPayload(orig_inst, form));
641670
}
@@ -2691,7 +2720,7 @@ fn addBlockBody(l: *Legalize, body: []const Air.Inst.Index) Error!u32 {
26912720
}
26922721

26932722
/// Returns `tag` to remind the caller to `continue :inst` the result.
2694-
/// This is inline to propagate the comptime-known `tag`.
2723+
/// `inline` to propagate the comptime-known `tag` result.
26952724
inline fn replaceInst(l: *Legalize, inst: Air.Inst.Index, comptime tag: Air.Inst.Tag, data: Air.Inst.Data) Air.Inst.Tag {
26962725
const orig_ty = if (std.debug.runtime_safety) l.typeOfIndex(inst) else {};
26972726
l.air_instructions.set(@intFromEnum(inst), .{ .tag = tag, .data = data });

src/codegen/c.zig

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,12 +23,19 @@ const BigIntLimb = std.math.big.Limb;
2323
const BigInt = std.math.big.int;
2424

2525
pub fn legalizeFeatures(_: *const std.Target) ?*const Air.Legalize.Features {
26-
return if (dev.env.supports(.legalize)) comptime &.initMany(&.{
27-
.expand_intcast_safe,
28-
.expand_add_safe,
29-
.expand_sub_safe,
30-
.expand_mul_safe,
31-
}) else null; // we don't currently ask zig1 to use safe optimization modes
26+
return comptime switch (dev.env.supports(.legalize)) {
27+
inline false, true => |supports_legalize| &.init(.{
28+
// we don't currently ask zig1 to use safe optimization modes
29+
.expand_intcast_safe = supports_legalize,
30+
.expand_add_safe = supports_legalize,
31+
.expand_sub_safe = supports_legalize,
32+
.expand_mul_safe = supports_legalize,
33+
34+
.expand_packed_load = true,
35+
.expand_packed_store = true,
36+
.expand_packed_struct_field_val = true,
37+
}),
38+
};
3239
}
3340

3441
/// For most backends, MIR is basically a sequence of machine code instructions, perhaps with some

0 commit comments

Comments
 (0)