aboutsummaryrefslogtreecommitdiff
path: root/src/codegen
diff options
context:
space:
mode:
authorMatthew Lugg <mlugg@mlugg.co.uk>2024-08-27 06:10:56 +0100
committerGitHub <noreply@github.com>2024-08-27 06:10:56 +0100
commitd3c6f7179c7a6086ab9cdbaed231da9a1f0b4dee (patch)
treea75bc8abc129a679fce0673165e04fa7283f2823 /src/codegen
parentd9147b91a601ad2442aaa43f4dba2d01b25d803d (diff)
parent4c0f021c2e4270c7392df7250a5d8f2431dcc54f (diff)
downloadzig-d3c6f7179c7a6086ab9cdbaed231da9a1f0b4dee.tar.gz
zig-d3c6f7179c7a6086ab9cdbaed231da9a1f0b4dee.zip
Merge pull request #21214 from mlugg/branch-hint-and-export
Implement `@branchHint` and new `@export` usage
Diffstat (limited to 'src/codegen')
-rw-r--r--src/codegen/c.zig45
-rw-r--r--src/codegen/llvm.zig235
-rw-r--r--src/codegen/llvm/Builder.zig417
-rw-r--r--src/codegen/llvm/ir.zig227
-rw-r--r--src/codegen/spirv.zig50
5 files changed, 712 insertions, 262 deletions
diff --git a/src/codegen/c.zig b/src/codegen/c.zig
index 754286d80b..8703e9b124 100644
--- a/src/codegen/c.zig
+++ b/src/codegen/c.zig
@@ -626,7 +626,7 @@ pub const DeclGen = struct {
}
fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {
- @setCold(true);
+ @branchHint(.cold);
const zcu = dg.pt.zcu;
const src_loc = zcu.navSrcLoc(dg.pass.nav);
dg.error_msg = try Zcu.ErrorMsg.create(dg.gpa, src_loc, format, args);
@@ -1786,7 +1786,7 @@ pub const DeclGen = struct {
else => unreachable,
}
}
- if (fn_val.getFunction(zcu)) |func| if (func.analysisUnordered(ip).is_cold)
+ if (fn_val.getFunction(zcu)) |func| if (func.analysisUnordered(ip).branch_hint == .cold)
try w.writeAll("zig_cold ");
if (fn_info.return_type == .noreturn_type) try w.writeAll("zig_noreturn ");
@@ -3290,8 +3290,10 @@ fn genBodyInner(f: *Function, body: []const Air.Inst.Index) error{ AnalysisFail,
.prefetch => try airPrefetch(f, inst),
.addrspace_cast => return f.fail("TODO: C backend: implement addrspace_cast", .{}),
- .@"try" => try airTry(f, inst),
- .try_ptr => try airTryPtr(f, inst),
+ .@"try" => try airTry(f, inst),
+ .try_cold => try airTry(f, inst),
+ .try_ptr => try airTryPtr(f, inst),
+ .try_ptr_cold => try airTryPtr(f, inst),
.dbg_stmt => try airDbgStmt(f, inst),
.dbg_inline_block => try airDbgInlineBlock(f, inst),
@@ -4988,11 +4990,10 @@ fn airCondBr(f: *Function, inst: Air.Inst.Index) !CValue {
fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
const pt = f.object.dg.pt;
const zcu = pt.zcu;
- const pl_op = f.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
- const condition = try f.resolveInst(pl_op.operand);
- try reap(f, inst, &.{pl_op.operand});
- const condition_ty = f.typeOf(pl_op.operand);
- const switch_br = f.air.extraData(Air.SwitchBr, pl_op.payload);
+ const switch_br = f.air.unwrapSwitch(inst);
+ const condition = try f.resolveInst(switch_br.operand);
+ try reap(f, inst, &.{switch_br.operand});
+ const condition_ty = f.typeOf(switch_br.operand);
const writer = f.object.writer();
try writer.writeAll("switch (");
@@ -5013,22 +5014,16 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
f.object.indent_writer.pushIndent();
const gpa = f.object.dg.gpa;
- const liveness = try f.liveness.getSwitchBr(gpa, inst, switch_br.data.cases_len + 1);
+ const liveness = try f.liveness.getSwitchBr(gpa, inst, switch_br.cases_len + 1);
defer gpa.free(liveness.deaths);
// On the final iteration we do not need to fix any state. This is because, like in the `else`
// branch of a `cond_br`, our parent has to do it for this entire body anyway.
- const last_case_i = switch_br.data.cases_len - @intFromBool(switch_br.data.else_body_len == 0);
-
- var extra_index: usize = switch_br.end;
- for (0..switch_br.data.cases_len) |case_i| {
- const case = f.air.extraData(Air.SwitchBr.Case, extra_index);
- const items = @as([]const Air.Inst.Ref, @ptrCast(f.air.extra[case.end..][0..case.data.items_len]));
- const case_body: []const Air.Inst.Index =
- @ptrCast(f.air.extra[case.end + items.len ..][0..case.data.body_len]);
- extra_index = case.end + case.data.items_len + case_body.len;
+ const last_case_i = switch_br.cases_len - @intFromBool(switch_br.else_body_len == 0);
- for (items) |item| {
+ var it = switch_br.iterateCases();
+ while (it.next()) |case| {
+ for (case.items) |item| {
try f.object.indent_writer.insertNewline();
try writer.writeAll("case ");
const item_value = try f.air.value(item, pt);
@@ -5046,19 +5041,19 @@ fn airSwitchBr(f: *Function, inst: Air.Inst.Index) !CValue {
}
try writer.writeByte(' ');
- if (case_i != last_case_i) {
- try genBodyResolveState(f, inst, liveness.deaths[case_i], case_body, false);
+ if (case.idx != last_case_i) {
+ try genBodyResolveState(f, inst, liveness.deaths[case.idx], case.body, false);
} else {
- for (liveness.deaths[case_i]) |death| {
+ for (liveness.deaths[case.idx]) |death| {
try die(f, inst, death.toRef());
}
- try genBody(f, case_body);
+ try genBody(f, case.body);
}
// The case body must be noreturn so we don't need to insert a break.
}
- const else_body: []const Air.Inst.Index = @ptrCast(f.air.extra[extra_index..][0..switch_br.data.else_body_len]);
+ const else_body = it.elseBody();
try f.object.indent_writer.insertNewline();
if (else_body.len > 0) {
// Note that this must be the last case (i.e. the `last_case_i` case was not hit above)
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index 1d8667ecb2..eec46b8379 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -898,9 +898,9 @@ pub const Object = struct {
const i32_2 = try builder.intConst(.i32, 2);
const i32_3 = try builder.intConst(.i32, 3);
const debug_info_version = try builder.debugModuleFlag(
- try builder.debugConstant(i32_2),
+ try builder.metadataConstant(i32_2),
try builder.metadataString("Debug Info Version"),
- try builder.debugConstant(i32_3),
+ try builder.metadataConstant(i32_3),
);
switch (comp.config.debug_format) {
@@ -908,9 +908,9 @@ pub const Object = struct {
.dwarf => |f| {
const i32_4 = try builder.intConst(.i32, 4);
const dwarf_version = try builder.debugModuleFlag(
- try builder.debugConstant(i32_2),
+ try builder.metadataConstant(i32_2),
try builder.metadataString("Dwarf Version"),
- try builder.debugConstant(i32_4),
+ try builder.metadataConstant(i32_4),
);
switch (f) {
.@"32" => {
@@ -921,9 +921,9 @@ pub const Object = struct {
},
.@"64" => {
const dwarf64 = try builder.debugModuleFlag(
- try builder.debugConstant(i32_2),
+ try builder.metadataConstant(i32_2),
try builder.metadataString("DWARF64"),
- try builder.debugConstant(.@"1"),
+ try builder.metadataConstant(.@"1"),
);
try builder.debugNamed(try builder.metadataString("llvm.module.flags"), &.{
debug_info_version,
@@ -935,9 +935,9 @@ pub const Object = struct {
},
.code_view => {
const code_view = try builder.debugModuleFlag(
- try builder.debugConstant(i32_2),
+ try builder.metadataConstant(i32_2),
try builder.metadataString("CodeView"),
- try builder.debugConstant(.@"1"),
+ try builder.metadataConstant(.@"1"),
);
try builder.debugNamed(try builder.metadataString("llvm.module.flags"), &.{
debug_info_version,
@@ -1122,12 +1122,12 @@ pub const Object = struct {
self.builder.debugForwardReferenceSetType(
self.debug_enums_fwd_ref,
- try self.builder.debugTuple(self.debug_enums.items),
+ try self.builder.metadataTuple(self.debug_enums.items),
);
self.builder.debugForwardReferenceSetType(
self.debug_globals_fwd_ref,
- try self.builder.debugTuple(self.debug_globals.items),
+ try self.builder.metadataTuple(self.debug_globals.items),
);
}
}
@@ -1369,7 +1369,7 @@ pub const Object = struct {
_ = try attributes.removeFnAttr(.alignstack);
}
- if (func_analysis.is_cold) {
+ if (func_analysis.branch_hint == .cold) {
try attributes.addFnAttr(.cold, &o.builder);
} else {
_ = try attributes.removeFnAttr(.cold);
@@ -1978,7 +1978,7 @@ pub const Object = struct {
try o.lowerDebugType(int_ty),
ty.abiSize(zcu) * 8,
(ty.abiAlignment(zcu).toByteUnits() orelse 0) * 8,
- try o.builder.debugTuple(enumerators),
+ try o.builder.metadataTuple(enumerators),
);
try o.debug_type_map.put(gpa, ty, debug_enum_type);
@@ -2087,7 +2087,7 @@ pub const Object = struct {
.none, // Underlying type
ty.abiSize(zcu) * 8,
(ty.abiAlignment(zcu).toByteUnits() orelse 0) * 8,
- try o.builder.debugTuple(&.{
+ try o.builder.metadataTuple(&.{
debug_ptr_type,
debug_len_type,
}),
@@ -2167,10 +2167,10 @@ pub const Object = struct {
try o.lowerDebugType(ty.childType(zcu)),
ty.abiSize(zcu) * 8,
(ty.abiAlignment(zcu).toByteUnits() orelse 0) * 8,
- try o.builder.debugTuple(&.{
+ try o.builder.metadataTuple(&.{
try o.builder.debugSubrange(
- try o.builder.debugConstant(try o.builder.intConst(.i64, 0)),
- try o.builder.debugConstant(try o.builder.intConst(.i64, ty.arrayLen(zcu))),
+ try o.builder.metadataConstant(try o.builder.intConst(.i64, 0)),
+ try o.builder.metadataConstant(try o.builder.intConst(.i64, ty.arrayLen(zcu))),
),
}),
);
@@ -2210,10 +2210,10 @@ pub const Object = struct {
debug_elem_type,
ty.abiSize(zcu) * 8,
(ty.abiAlignment(zcu).toByteUnits() orelse 0) * 8,
- try o.builder.debugTuple(&.{
+ try o.builder.metadataTuple(&.{
try o.builder.debugSubrange(
- try o.builder.debugConstant(try o.builder.intConst(.i64, 0)),
- try o.builder.debugConstant(try o.builder.intConst(.i64, ty.vectorLen(zcu))),
+ try o.builder.metadataConstant(try o.builder.intConst(.i64, 0)),
+ try o.builder.metadataConstant(try o.builder.intConst(.i64, ty.vectorLen(zcu))),
),
}),
);
@@ -2288,7 +2288,7 @@ pub const Object = struct {
.none, // Underlying type
ty.abiSize(zcu) * 8,
(ty.abiAlignment(zcu).toByteUnits() orelse 0) * 8,
- try o.builder.debugTuple(&.{
+ try o.builder.metadataTuple(&.{
debug_data_type,
debug_some_type,
}),
@@ -2367,7 +2367,7 @@ pub const Object = struct {
.none, // Underlying type
ty.abiSize(zcu) * 8,
(ty.abiAlignment(zcu).toByteUnits() orelse 0) * 8,
- try o.builder.debugTuple(&fields),
+ try o.builder.metadataTuple(&fields),
);
o.builder.debugForwardReferenceSetType(debug_fwd_ref, debug_error_union_type);
@@ -2447,7 +2447,7 @@ pub const Object = struct {
.none, // Underlying type
ty.abiSize(zcu) * 8,
(ty.abiAlignment(zcu).toByteUnits() orelse 0) * 8,
- try o.builder.debugTuple(fields.items),
+ try o.builder.metadataTuple(fields.items),
);
o.builder.debugForwardReferenceSetType(debug_fwd_ref, debug_struct_type);
@@ -2520,7 +2520,7 @@ pub const Object = struct {
.none, // Underlying type
ty.abiSize(zcu) * 8,
(ty.abiAlignment(zcu).toByteUnits() orelse 0) * 8,
- try o.builder.debugTuple(fields.items),
+ try o.builder.metadataTuple(fields.items),
);
o.builder.debugForwardReferenceSetType(debug_fwd_ref, debug_struct_type);
@@ -2561,7 +2561,7 @@ pub const Object = struct {
.none, // Underlying type
ty.abiSize(zcu) * 8,
(ty.abiAlignment(zcu).toByteUnits() orelse 0) * 8,
- try o.builder.debugTuple(
+ try o.builder.metadataTuple(
&.{try o.lowerDebugType(Type.fromInterned(union_type.enum_tag_ty))},
),
);
@@ -2623,7 +2623,7 @@ pub const Object = struct {
.none, // Underlying type
ty.abiSize(zcu) * 8,
(ty.abiAlignment(zcu).toByteUnits() orelse 0) * 8,
- try o.builder.debugTuple(fields.items),
+ try o.builder.metadataTuple(fields.items),
);
o.builder.debugForwardReferenceSetType(debug_union_fwd_ref, debug_union_type);
@@ -2682,7 +2682,7 @@ pub const Object = struct {
.none, // Underlying type
ty.abiSize(zcu) * 8,
(ty.abiAlignment(zcu).toByteUnits() orelse 0) * 8,
- try o.builder.debugTuple(&full_fields),
+ try o.builder.metadataTuple(&full_fields),
);
o.builder.debugForwardReferenceSetType(debug_fwd_ref, debug_tagged_union_type);
@@ -2735,7 +2735,7 @@ pub const Object = struct {
}
const debug_function_type = try o.builder.debugSubroutineType(
- try o.builder.debugTuple(debug_param_types.items),
+ try o.builder.metadataTuple(debug_param_types.items),
);
try o.debug_type_map.put(gpa, ty, debug_function_type);
@@ -4571,7 +4571,7 @@ pub const Object = struct {
const bad_value_block = try wip.block(1, "BadValue");
const tag_int_value = wip.arg(0);
var wip_switch =
- try wip.@"switch"(tag_int_value, bad_value_block, @intCast(enum_type.names.len));
+ try wip.@"switch"(tag_int_value, bad_value_block, @intCast(enum_type.names.len), .none);
defer wip_switch.finish(&wip);
for (0..enum_type.names.len) |field_index| {
@@ -4618,7 +4618,7 @@ pub const NavGen = struct {
}
fn todo(ng: *NavGen, comptime format: []const u8, args: anytype) Error {
- @setCold(true);
+ @branchHint(.cold);
assert(ng.err_msg == null);
const o = ng.object;
const gpa = o.gpa;
@@ -4784,7 +4784,7 @@ pub const FuncGen = struct {
}
fn todo(self: *FuncGen, comptime format: []const u8, args: anytype) Error {
- @setCold(true);
+ @branchHint(.cold);
return self.ng.todo(format, args);
}
@@ -4958,8 +4958,10 @@ pub const FuncGen = struct {
.ret_addr => try self.airRetAddr(inst),
.frame_addr => try self.airFrameAddress(inst),
.cond_br => try self.airCondBr(inst),
- .@"try" => try self.airTry(body[i..]),
- .try_ptr => try self.airTryPtr(inst),
+ .@"try" => try self.airTry(body[i..], false),
+ .try_cold => try self.airTry(body[i..], true),
+ .try_ptr => try self.airTryPtr(inst, false),
+ .try_ptr_cold => try self.airTryPtr(inst, true),
.intcast => try self.airIntCast(inst),
.trunc => try self.airTrunc(inst),
.fptrunc => try self.airFptrunc(inst),
@@ -5506,6 +5508,7 @@ pub const FuncGen = struct {
const panic_nav = ip.getNav(panic_func.owner_nav);
const fn_info = zcu.typeToFunc(Type.fromInterned(panic_nav.typeOf(ip))).?;
const panic_global = try o.resolveLlvmFunction(panic_func.owner_nav);
+ _ = try fg.wip.callIntrinsicAssumeCold();
_ = try fg.wip.call(
.normal,
toLlvmCallConv(fn_info.cc, target),
@@ -5794,7 +5797,7 @@ pub const FuncGen = struct {
const mixed_block = try self.wip.block(1, "Mixed");
const both_pl_block = try self.wip.block(1, "BothNonNull");
const end_block = try self.wip.block(3, "End");
- var wip_switch = try self.wip.@"switch"(lhs_rhs_ored, mixed_block, 2);
+ var wip_switch = try self.wip.@"switch"(lhs_rhs_ored, mixed_block, 2, .none);
defer wip_switch.finish(&self.wip);
try wip_switch.addCase(
try o.builder.intConst(llvm_i2, 0b00),
@@ -5948,21 +5951,62 @@ pub const FuncGen = struct {
const then_body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.then_body_len]);
const else_body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end + then_body.len ..][0..extra.data.else_body_len]);
+ const Hint = enum {
+ none,
+ unpredictable,
+ then_likely,
+ else_likely,
+ then_cold,
+ else_cold,
+ };
+ const hint: Hint = switch (extra.data.branch_hints.true) {
+ .none => switch (extra.data.branch_hints.false) {
+ .none => .none,
+ .likely => .else_likely,
+ .unlikely => .then_likely,
+ .cold => .else_cold,
+ .unpredictable => .unpredictable,
+ },
+ .likely => switch (extra.data.branch_hints.false) {
+ .none => .then_likely,
+ .likely => .unpredictable,
+ .unlikely => .then_likely,
+ .cold => .else_cold,
+ .unpredictable => .unpredictable,
+ },
+ .unlikely => switch (extra.data.branch_hints.false) {
+ .none => .else_likely,
+ .likely => .else_likely,
+ .unlikely => .unpredictable,
+ .cold => .else_cold,
+ .unpredictable => .unpredictable,
+ },
+ .cold => .then_cold,
+ .unpredictable => .unpredictable,
+ };
+
const then_block = try self.wip.block(1, "Then");
const else_block = try self.wip.block(1, "Else");
- _ = try self.wip.brCond(cond, then_block, else_block);
+ _ = try self.wip.brCond(cond, then_block, else_block, switch (hint) {
+ .none, .then_cold, .else_cold => .none,
+ .unpredictable => .unpredictable,
+ .then_likely => .then_likely,
+ .else_likely => .else_likely,
+ });
self.wip.cursor = .{ .block = then_block };
+ if (hint == .then_cold) _ = try self.wip.callIntrinsicAssumeCold();
try self.genBodyDebugScope(null, then_body);
self.wip.cursor = .{ .block = else_block };
+ if (hint == .else_cold) _ = try self.wip.callIntrinsicAssumeCold();
try self.genBodyDebugScope(null, else_body);
// No need to reset the insert cursor since this instruction is noreturn.
return .none;
}
- fn airTry(self: *FuncGen, body_tail: []const Air.Inst.Index) !Builder.Value {
+ fn airTry(self: *FuncGen, body_tail: []const Air.Inst.Index, err_cold: bool) !Builder.Value {
const o = self.ng.object;
const pt = o.pt;
const zcu = pt.zcu;
@@ -5975,10 +6019,10 @@ pub const FuncGen = struct {
const payload_ty = self.typeOfIndex(inst);
const can_elide_load = if (isByRef(payload_ty, zcu)) self.canElideLoad(body_tail) else false;
const is_unused = self.liveness.isUnused(inst);
- return lowerTry(self, err_union, body, err_union_ty, false, can_elide_load, is_unused);
+ return lowerTry(self, err_union, body, err_union_ty, false, can_elide_load, is_unused, err_cold);
}
- fn airTryPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
+ fn airTryPtr(self: *FuncGen, inst: Air.Inst.Index, err_cold: bool) !Builder.Value {
const o = self.ng.object;
const zcu = o.pt.zcu;
const ty_pl = self.air.instructions.items(.data)[@intFromEnum(inst)].ty_pl;
@@ -5987,7 +6031,7 @@ pub const FuncGen = struct {
const body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra.end..][0..extra.data.body_len]);
const err_union_ty = self.typeOf(extra.data.ptr).childType(zcu);
const is_unused = self.liveness.isUnused(inst);
- return lowerTry(self, err_union_ptr, body, err_union_ty, true, true, is_unused);
+ return lowerTry(self, err_union_ptr, body, err_union_ty, true, true, is_unused, err_cold);
}
fn lowerTry(
@@ -5998,6 +6042,7 @@ pub const FuncGen = struct {
operand_is_ptr: bool,
can_elide_load: bool,
is_unused: bool,
+ err_cold: bool,
) !Builder.Value {
const o = fg.ng.object;
const pt = o.pt;
@@ -6036,9 +6081,10 @@ pub const FuncGen = struct {
const return_block = try fg.wip.block(1, "TryRet");
const continue_block = try fg.wip.block(1, "TryCont");
- _ = try fg.wip.brCond(is_err, return_block, continue_block);
+ _ = try fg.wip.brCond(is_err, return_block, continue_block, if (err_cold) .none else .else_likely);
fg.wip.cursor = .{ .block = return_block };
+ if (err_cold) _ = try fg.wip.callIntrinsicAssumeCold();
try fg.genBodyDebugScope(null, body);
fg.wip.cursor = .{ .block = continue_block };
@@ -6065,9 +6111,11 @@ pub const FuncGen = struct {
fn airSwitchBr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
const o = self.ng.object;
- const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
- const cond = try self.resolveInst(pl_op.operand);
- const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload);
+
+ const switch_br = self.air.unwrapSwitch(inst);
+
+ const cond = try self.resolveInst(switch_br.operand);
+
const else_block = try self.wip.block(1, "Default");
const llvm_usize = try o.lowerType(Type.usize);
const cond_int = if (cond.typeOfWip(&self.wip).isPointer(&o.builder))
@@ -6075,34 +6123,70 @@ pub const FuncGen = struct {
else
cond;
- var extra_index: usize = switch_br.end;
- var case_i: u32 = 0;
- var llvm_cases_len: u32 = 0;
- while (case_i < switch_br.data.cases_len) : (case_i += 1) {
- const case = self.air.extraData(Air.SwitchBr.Case, extra_index);
- const items: []const Air.Inst.Ref =
- @ptrCast(self.air.extra[case.end..][0..case.data.items_len]);
- const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];
- extra_index = case.end + case.data.items_len + case_body.len;
+ const llvm_cases_len = llvm_cases_len: {
+ var len: u32 = 0;
+ var it = switch_br.iterateCases();
+ while (it.next()) |case| len += @intCast(case.items.len);
+ break :llvm_cases_len len;
+ };
+
+ const weights: Builder.Function.Instruction.BrCond.Weights = weights: {
+ // First pass. If any weights are `.unpredictable`, unpredictable.
+ // If all are `.none` or `.cold`, none.
+ var any_likely = false;
+ for (0..switch_br.cases_len) |case_idx| {
+ switch (switch_br.getHint(@intCast(case_idx))) {
+ .none, .cold => {},
+ .likely, .unlikely => any_likely = true,
+ .unpredictable => break :weights .unpredictable,
+ }
+ }
+ switch (switch_br.getElseHint()) {
+ .none, .cold => {},
+ .likely, .unlikely => any_likely = true,
+ .unpredictable => break :weights .unpredictable,
+ }
+ if (!any_likely) break :weights .none;
- llvm_cases_len += @intCast(items.len);
- }
+ var weights = try self.gpa.alloc(Builder.Metadata, llvm_cases_len + 1);
+ defer self.gpa.free(weights);
- var wip_switch = try self.wip.@"switch"(cond_int, else_block, llvm_cases_len);
- defer wip_switch.finish(&self.wip);
+ const else_weight: u32 = switch (switch_br.getElseHint()) {
+ .unpredictable => unreachable,
+ .none, .cold => 1000,
+ .likely => 2000,
+ .unlikely => 1,
+ };
+ weights[0] = try o.builder.metadataConstant(try o.builder.intConst(.i32, else_weight));
+
+ var weight_idx: usize = 1;
+ var it = switch_br.iterateCases();
+ while (it.next()) |case| {
+ const weight_val: u32 = switch (switch_br.getHint(case.idx)) {
+ .unpredictable => unreachable,
+ .none, .cold => 1000,
+ .likely => 2000,
+ .unlikely => 1,
+ };
+ const weight_meta = try o.builder.metadataConstant(try o.builder.intConst(.i32, weight_val));
+ @memset(weights[weight_idx..][0..case.items.len], weight_meta);
+ weight_idx += case.items.len;
+ }
+
+ assert(weight_idx == weights.len);
- extra_index = switch_br.end;
- case_i = 0;
- while (case_i < switch_br.data.cases_len) : (case_i += 1) {
- const case = self.air.extraData(Air.SwitchBr.Case, extra_index);
- const items: []const Air.Inst.Ref =
- @ptrCast(self.air.extra[case.end..][0..case.data.items_len]);
- const case_body: []const Air.Inst.Index = @ptrCast(self.air.extra[case.end + items.len ..][0..case.data.body_len]);
- extra_index = case.end + case.data.items_len + case_body.len;
+ const branch_weights_str = try o.builder.metadataString("branch_weights");
+ const tuple = try o.builder.strTuple(branch_weights_str, weights);
+ break :weights @enumFromInt(@intFromEnum(tuple));
+ };
- const case_block = try self.wip.block(@intCast(items.len), "Case");
+ var wip_switch = try self.wip.@"switch"(cond_int, else_block, llvm_cases_len, weights);
+ defer wip_switch.finish(&self.wip);
- for (items) |item| {
+ var it = switch_br.iterateCases();
+ while (it.next()) |case| {
+ const case_block = try self.wip.block(@intCast(case.items.len), "Case");
+ for (case.items) |item| {
const llvm_item = (try self.resolveInst(item)).toConst().?;
const llvm_int_item = if (llvm_item.typeOf(&o.builder).isPointer(&o.builder))
try o.builder.castConst(.ptrtoint, llvm_item, llvm_usize)
@@ -6110,13 +6194,14 @@ pub const FuncGen = struct {
llvm_item;
try wip_switch.addCase(llvm_int_item, case_block, &self.wip);
}
-
self.wip.cursor = .{ .block = case_block };
- try self.genBodyDebugScope(null, case_body);
+ if (switch_br.getHint(case.idx) == .cold) _ = try self.wip.callIntrinsicAssumeCold();
+ try self.genBodyDebugScope(null, case.body);
}
+ const else_body = it.elseBody();
self.wip.cursor = .{ .block = else_block };
- const else_body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra_index..][0..switch_br.data.else_body_len]);
+ if (switch_br.getElseHint() == .cold) _ = try self.wip.callIntrinsicAssumeCold();
if (else_body.len != 0) {
try self.genBodyDebugScope(null, else_body);
} else {
@@ -7748,7 +7833,7 @@ pub const FuncGen = struct {
const fail_block = try fg.wip.block(1, "OverflowFail");
const ok_block = try fg.wip.block(1, "OverflowOk");
- _ = try fg.wip.brCond(overflow_bit, fail_block, ok_block);
+ _ = try fg.wip.brCond(overflow_bit, fail_block, ok_block, .none);
fg.wip.cursor = .{ .block = fail_block };
try fg.buildSimplePanic(.integer_overflow);
@@ -9389,7 +9474,7 @@ pub const FuncGen = struct {
self.wip.cursor = .{ .block = loop_block };
const it_ptr = try self.wip.phi(.ptr, "");
const end = try self.wip.icmp(.ne, it_ptr.toValue(), end_ptr, "");
- _ = try self.wip.brCond(end, body_block, end_block);
+ _ = try self.wip.brCond(end, body_block, end_block, .none);
self.wip.cursor = .{ .block = body_block };
const elem_abi_align = elem_ty.abiAlignment(zcu);
@@ -9427,7 +9512,7 @@ pub const FuncGen = struct {
const cond = try self.cmp(.normal, .neq, Type.usize, len, usize_zero);
const memset_block = try self.wip.block(1, "MemsetTrapSkip");
const end_block = try self.wip.block(2, "MemsetTrapEnd");
- _ = try self.wip.brCond(cond, memset_block, end_block);
+ _ = try self.wip.brCond(cond, memset_block, end_block, .none);
self.wip.cursor = .{ .block = memset_block };
_ = try self.wip.callMemSet(dest_ptr, dest_ptr_align, fill_byte, len, access_kind);
_ = try self.wip.br(end_block);
@@ -9462,7 +9547,7 @@ pub const FuncGen = struct {
const cond = try self.cmp(.normal, .neq, Type.usize, len, usize_zero);
const memcpy_block = try self.wip.block(1, "MemcpyTrapSkip");
const end_block = try self.wip.block(2, "MemcpyTrapEnd");
- _ = try self.wip.brCond(cond, memcpy_block, end_block);
+ _ = try self.wip.brCond(cond, memcpy_block, end_block, .none);
self.wip.cursor = .{ .block = memcpy_block };
_ = try self.wip.callMemCpy(
dest_ptr,
@@ -9632,7 +9717,7 @@ pub const FuncGen = struct {
const valid_block = try self.wip.block(@intCast(names.len), "Valid");
const invalid_block = try self.wip.block(1, "Invalid");
const end_block = try self.wip.block(2, "End");
- var wip_switch = try self.wip.@"switch"(operand, invalid_block, @intCast(names.len));
+ var wip_switch = try self.wip.@"switch"(operand, invalid_block, @intCast(names.len), .none);
defer wip_switch.finish(&self.wip);
for (0..names.len) |name_index| {
@@ -9708,7 +9793,7 @@ pub const FuncGen = struct {
const named_block = try wip.block(@intCast(enum_type.names.len), "Named");
const unnamed_block = try wip.block(1, "Unnamed");
const tag_int_value = wip.arg(0);
- var wip_switch = try wip.@"switch"(tag_int_value, unnamed_block, @intCast(enum_type.names.len));
+ var wip_switch = try wip.@"switch"(tag_int_value, unnamed_block, @intCast(enum_type.names.len), .none);
defer wip_switch.finish(&wip);
for (0..enum_type.names.len) |field_index| {
@@ -9858,7 +9943,7 @@ pub const FuncGen = struct {
const cond = try self.wip.icmp(.ult, i, llvm_vector_len, "");
const loop_then = try self.wip.block(1, "ReduceLoopThen");
- _ = try self.wip.brCond(cond, loop_then, loop_exit);
+ _ = try self.wip.brCond(cond, loop_then, loop_exit, .none);
{
self.wip.cursor = .{ .block = loop_then };
diff --git a/src/codegen/llvm/Builder.zig b/src/codegen/llvm/Builder.zig
index 90da3bdd7a..9ada51acad 100644
--- a/src/codegen/llvm/Builder.zig
+++ b/src/codegen/llvm/Builder.zig
@@ -4817,12 +4817,22 @@ pub const Function = struct {
cond: Value,
then: Block.Index,
@"else": Block.Index,
+ weights: Weights,
+ pub const Weights = enum(u32) {
+ // We can do this as metadata indices 0 and 1 are reserved.
+ none = 0,
+ unpredictable = 1,
+ /// These values should be converted to `Metadata` to be used
+ /// in a `prof` annotation providing branch weights.
+ _,
+ };
};
pub const Switch = struct {
val: Value,
default: Block.Index,
cases_len: u32,
+ weights: BrCond.Weights,
//case_vals: [cases_len]Constant,
//case_blocks: [cases_len]Block.Index,
};
@@ -4969,7 +4979,8 @@ pub const Function = struct {
};
pub const Info = packed struct(u32) {
call_conv: CallConv,
- _: u22 = undefined,
+ has_op_bundle_cold: bool,
+ _: u21 = undefined,
};
};
@@ -5036,6 +5047,7 @@ pub const Function = struct {
FunctionAttributes,
Type,
Value,
+ Instruction.BrCond.Weights,
=> @enumFromInt(value),
MemoryAccessInfo,
Instruction.Alloca.Info,
@@ -5201,6 +5213,7 @@ pub const WipFunction = struct {
cond: Value,
then: Block.Index,
@"else": Block.Index,
+ weights: enum { none, unpredictable, then_likely, else_likely },
) Allocator.Error!Instruction.Index {
assert(cond.typeOfWip(self) == .i1);
try self.ensureUnusedExtraCapacity(1, Instruction.BrCond, 0);
@@ -5210,6 +5223,22 @@ pub const WipFunction = struct {
.cond = cond,
.then = then,
.@"else" = @"else",
+ .weights = switch (weights) {
+ .none => .none,
+ .unpredictable => .unpredictable,
+ .then_likely, .else_likely => w: {
+ const branch_weights_str = try self.builder.metadataString("branch_weights");
+ const unlikely_const = try self.builder.metadataConstant(try self.builder.intConst(.i32, 1));
+ const likely_const = try self.builder.metadataConstant(try self.builder.intConst(.i32, 2000));
+ const weight_vals: [2]Metadata = switch (weights) {
+ .none, .unpredictable => unreachable,
+ .then_likely => .{ likely_const, unlikely_const },
+ .else_likely => .{ unlikely_const, likely_const },
+ };
+ const tuple = try self.builder.strTuple(branch_weights_str, &weight_vals);
+ break :w @enumFromInt(@intFromEnum(tuple));
+ },
+ },
}),
});
then.ptr(self).branches += 1;
@@ -5248,6 +5277,7 @@ pub const WipFunction = struct {
val: Value,
default: Block.Index,
cases_len: u32,
+ weights: Instruction.BrCond.Weights,
) Allocator.Error!WipSwitch {
try self.ensureUnusedExtraCapacity(1, Instruction.Switch, cases_len * 2);
const instruction = try self.addInst(null, .{
@@ -5256,6 +5286,7 @@ pub const WipFunction = struct {
.val = val,
.default = default,
.cases_len = cases_len,
+ .weights = weights,
}),
});
_ = self.extra.addManyAsSliceAssumeCapacity(cases_len * 2);
@@ -5896,6 +5927,20 @@ pub const WipFunction = struct {
args: []const Value,
name: []const u8,
) Allocator.Error!Value {
+ return self.callInner(kind, call_conv, function_attributes, ty, callee, args, name, false);
+ }
+
+ fn callInner(
+ self: *WipFunction,
+ kind: Instruction.Call.Kind,
+ call_conv: CallConv,
+ function_attributes: FunctionAttributes,
+ ty: Type,
+ callee: Value,
+ args: []const Value,
+ name: []const u8,
+ has_op_bundle_cold: bool,
+ ) Allocator.Error!Value {
const ret_ty = ty.functionReturn(self.builder);
assert(ty.isFunction(self.builder));
assert(callee.typeOfWip(self).isPointer(self.builder));
@@ -5918,7 +5963,10 @@ pub const WipFunction = struct {
.tail_fast => .@"tail call fast",
},
.data = self.addExtraAssumeCapacity(Instruction.Call{
- .info = .{ .call_conv = call_conv },
+ .info = .{
+ .call_conv = call_conv,
+ .has_op_bundle_cold = has_op_bundle_cold,
+ },
.attributes = function_attributes,
.ty = ty,
.callee = callee,
@@ -5964,6 +6012,20 @@ pub const WipFunction = struct {
);
}
+ pub fn callIntrinsicAssumeCold(self: *WipFunction) Allocator.Error!Value {
+ const intrinsic = try self.builder.getIntrinsic(.assume, &.{});
+ return self.callInner(
+ .normal,
+ CallConv.default,
+ .none,
+ intrinsic.typeOf(self.builder),
+ intrinsic.toValue(self.builder),
+ &.{try self.builder.intValue(.i1, 1)},
+ "",
+ true,
+ );
+ }
+
pub fn callMemCpy(
self: *WipFunction,
dst: Value,
@@ -6040,7 +6102,7 @@ pub const WipFunction = struct {
break :blk metadata;
},
- .constant => |constant| try self.builder.debugConstant(constant),
+ .constant => |constant| try self.builder.metadataConstant(constant),
.metadata => |metadata| metadata,
};
}
@@ -6099,6 +6161,7 @@ pub const WipFunction = struct {
FunctionAttributes,
Type,
Value,
+ Instruction.BrCond.Weights,
=> @intFromEnum(value),
MemoryAccessInfo,
Instruction.Alloca.Info,
@@ -6380,6 +6443,7 @@ pub const WipFunction = struct {
.cond = instructions.map(extra.cond),
.then = extra.then,
.@"else" = extra.@"else",
+ .weights = extra.weights,
});
},
.call,
@@ -6522,6 +6586,7 @@ pub const WipFunction = struct {
.val = instructions.map(extra.data.val),
.default = extra.data.default,
.cases_len = extra.data.cases_len,
+ .weights = extra.data.weights,
});
wip_extra.appendSlice(case_vals);
wip_extra.appendSlice(case_blocks);
@@ -6744,6 +6809,7 @@ pub const WipFunction = struct {
FunctionAttributes,
Type,
Value,
+ Instruction.BrCond.Weights,
=> @intFromEnum(value),
MemoryAccessInfo,
Instruction.Alloca.Info,
@@ -6792,6 +6858,7 @@ pub const WipFunction = struct {
FunctionAttributes,
Type,
Value,
+ Instruction.BrCond.Weights,
=> @enumFromInt(value),
MemoryAccessInfo,
Instruction.Alloca.Info,
@@ -7697,6 +7764,7 @@ pub const MetadataString = enum(u32) {
pub const Metadata = enum(u32) {
none = 0,
+ empty_tuple = 1,
_,
const first_forward_reference = 1 << 29;
@@ -7734,6 +7802,7 @@ pub const Metadata = enum(u32) {
enumerator_signed_negative,
subrange,
tuple,
+ str_tuple,
module_flag,
expression,
local_var,
@@ -7779,6 +7848,7 @@ pub const Metadata = enum(u32) {
.enumerator_signed_negative,
.subrange,
.tuple,
+ .str_tuple,
.module_flag,
.local_var,
.parameter,
@@ -8043,6 +8113,13 @@ pub const Metadata = enum(u32) {
// elements: [elements_len]Metadata
};
+ pub const StrTuple = struct {
+ str: MetadataString,
+ elements_len: u32,
+
+ // elements: [elements_len]Metadata
+ };
+
pub const ModuleFlag = struct {
behavior: Metadata,
name: MetadataString,
@@ -8355,7 +8432,7 @@ pub const Metadata = enum(u32) {
};
pub fn init(options: Options) Allocator.Error!Builder {
- var self = Builder{
+ var self: Builder = .{
.gpa = options.allocator,
.strip = options.strip,
@@ -8454,7 +8531,9 @@ pub fn init(options: Options) Allocator.Error!Builder {
assert(try self.intConst(.i32, 0) == .@"0");
assert(try self.intConst(.i32, 1) == .@"1");
assert(try self.noneConst(.token) == .none);
- if (!self.strip) assert(try self.debugNone() == .none);
+
+ assert(try self.metadataNone() == .none);
+ assert(try self.metadataTuple(&.{}) == .empty_tuple);
try self.metadata_string_indices.append(self.gpa, 0);
assert(try self.metadataString("") == .none);
@@ -9683,6 +9762,13 @@ pub fn printUnbuffered(
extra.then.toInst(&function).fmt(function_index, self),
extra.@"else".toInst(&function).fmt(function_index, self),
});
+ switch (extra.weights) {
+ .none => {},
+ .unpredictable => try writer.writeAll(", !unpredictable !{}"),
+ _ => try writer.print("{}", .{
+ try metadata_formatter.fmt(", !prof ", @as(Metadata, @enumFromInt(@intFromEnum(extra.weights)))),
+ }),
+ }
},
.call,
.@"call fast",
@@ -9727,6 +9813,9 @@ pub fn printUnbuffered(
});
}
try writer.writeByte(')');
+ if (extra.data.info.has_op_bundle_cold) {
+ try writer.writeAll(" [ \"cold\"() ]");
+ }
const call_function_attributes = extra.data.attributes.func(self);
if (call_function_attributes != .none) try writer.print(" #{d}", .{
(try attribute_groups.getOrPutValue(
@@ -9937,6 +10026,13 @@ pub fn printUnbuffered(
},
);
try writer.writeAll(" ]");
+ switch (extra.data.weights) {
+ .none => {},
+ .unpredictable => try writer.writeAll(", !unpredictable !{}"),
+ _ => try writer.print("{}", .{
+ try metadata_formatter.fmt(", !prof ", @as(Metadata, @enumFromInt(@intFromEnum(extra.data.weights)))),
+ }),
+ }
},
.va_arg => |tag| {
const extra = function.extraData(Function.Instruction.VaArg, instruction.data);
@@ -10285,6 +10381,17 @@ pub fn printUnbuffered(
});
try writer.writeAll("}\n");
},
+ .str_tuple => {
+ var extra = self.metadataExtraDataTrail(Metadata.StrTuple, metadata_item.data);
+ const elements = extra.trail.next(extra.data.elements_len, Metadata, self);
+ try writer.print("!{{{[str]%}", .{
+ .str = try metadata_formatter.fmt("", extra.data.str),
+ });
+ for (elements) |element| try writer.print("{[element]%}", .{
+ .element = try metadata_formatter.fmt("", element),
+ });
+ try writer.writeAll("}\n");
+ },
.module_flag => {
const extra = self.metadataExtraData(Metadata.ModuleFlag, metadata_item.data);
try writer.print("!{{{[behavior]%}{[name]%}{[constant]%}}}\n", .{
@@ -11797,9 +11904,9 @@ pub fn debugNamed(self: *Builder, name: MetadataString, operands: []const Metada
self.debugNamedAssumeCapacity(name, operands);
}
-fn debugNone(self: *Builder) Allocator.Error!Metadata {
+fn metadataNone(self: *Builder) Allocator.Error!Metadata {
try self.ensureUnusedMetadataCapacity(1, NoExtra, 0);
- return self.debugNoneAssumeCapacity();
+ return self.metadataNoneAssumeCapacity();
}
pub fn debugFile(
@@ -12088,12 +12195,21 @@ pub fn debugExpression(
return self.debugExpressionAssumeCapacity(elements);
}
-pub fn debugTuple(
+pub fn metadataTuple(
self: *Builder,
elements: []const Metadata,
) Allocator.Error!Metadata {
try self.ensureUnusedMetadataCapacity(1, Metadata.Tuple, elements.len);
- return self.debugTupleAssumeCapacity(elements);
+ return self.metadataTupleAssumeCapacity(elements);
+}
+
+pub fn strTuple(
+ self: *Builder,
+ str: MetadataString,
+ elements: []const Metadata,
+) Allocator.Error!Metadata {
+ try self.ensureUnusedMetadataCapacity(1, Metadata.StrTuple, elements.len);
+ return self.strTupleAssumeCapacity(str, elements);
}
pub fn debugModuleFlag(
@@ -12164,9 +12280,9 @@ pub fn debugGlobalVarExpression(
return self.debugGlobalVarExpressionAssumeCapacity(variable, expression);
}
-pub fn debugConstant(self: *Builder, value: Constant) Allocator.Error!Metadata {
+pub fn metadataConstant(self: *Builder, value: Constant) Allocator.Error!Metadata {
try self.ensureUnusedMetadataCapacity(1, NoExtra, 0);
- return self.debugConstantAssumeCapacity(value);
+ return self.metadataConstantAssumeCapacity(value);
}
pub fn debugForwardReferenceSetType(self: *Builder, fwd_ref: Metadata, ty: Metadata) void {
@@ -12261,8 +12377,7 @@ fn debugNamedAssumeCapacity(self: *Builder, name: MetadataString, operands: []co
};
}
-pub fn debugNoneAssumeCapacity(self: *Builder) Metadata {
- assert(!self.strip);
+pub fn metadataNoneAssumeCapacity(self: *Builder) Metadata {
return self.metadataSimpleAssumeCapacity(.none, .{});
}
@@ -12738,11 +12853,10 @@ fn debugExpressionAssumeCapacity(
return @enumFromInt(gop.index);
}
-fn debugTupleAssumeCapacity(
+fn metadataTupleAssumeCapacity(
self: *Builder,
elements: []const Metadata,
) Metadata {
- assert(!self.strip);
const Key = struct {
elements: []const Metadata,
};
@@ -12785,6 +12899,55 @@ fn debugTupleAssumeCapacity(
return @enumFromInt(gop.index);
}
+fn strTupleAssumeCapacity(
+ self: *Builder,
+ str: MetadataString,
+ elements: []const Metadata,
+) Metadata {
+ const Key = struct {
+ str: MetadataString,
+ elements: []const Metadata,
+ };
+ const Adapter = struct {
+ builder: *const Builder,
+ pub fn hash(_: @This(), key: Key) u32 {
+ var hasher = comptime std.hash.Wyhash.init(std.hash.uint32(@intFromEnum(Metadata.Tag.tuple)));
+ hasher.update(std.mem.sliceAsBytes(key.elements));
+ return @truncate(hasher.final());
+ }
+
+ pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
+ if (.str_tuple != ctx.builder.metadata_items.items(.tag)[rhs_index]) return false;
+ const rhs_data = ctx.builder.metadata_items.items(.data)[rhs_index];
+ var rhs_extra = ctx.builder.metadataExtraDataTrail(Metadata.StrTuple, rhs_data);
+ return rhs_extra.data.str == lhs_key.str and std.mem.eql(
+ Metadata,
+ lhs_key.elements,
+ rhs_extra.trail.next(rhs_extra.data.elements_len, Metadata, ctx.builder),
+ );
+ }
+ };
+
+ const gop = self.metadata_map.getOrPutAssumeCapacityAdapted(
+ Key{ .str = str, .elements = elements },
+ Adapter{ .builder = self },
+ );
+
+ if (!gop.found_existing) {
+ gop.key_ptr.* = {};
+ gop.value_ptr.* = {};
+ self.metadata_items.appendAssumeCapacity(.{
+ .tag = .str_tuple,
+ .data = self.addMetadataExtraAssumeCapacity(Metadata.StrTuple{
+ .str = str,
+ .elements_len = @intCast(elements.len),
+ }),
+ });
+ self.metadata_extra.appendSliceAssumeCapacity(@ptrCast(elements));
+ }
+ return @enumFromInt(gop.index);
+}
+
fn debugModuleFlagAssumeCapacity(
self: *Builder,
behavior: Metadata,
@@ -12875,8 +13038,7 @@ fn debugGlobalVarExpressionAssumeCapacity(
});
}
-fn debugConstantAssumeCapacity(self: *Builder, constant: Constant) Metadata {
- assert(!self.strip);
+fn metadataConstantAssumeCapacity(self: *Builder, constant: Constant) Metadata {
const Adapter = struct {
builder: *const Builder,
pub fn hash(_: @This(), key: Constant) u32 {
@@ -13755,15 +13917,18 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
}
// METADATA_KIND_BLOCK
- if (!self.strip) {
+ {
const MetadataKindBlock = ir.MetadataKindBlock;
var metadata_kind_block = try module_block.enterSubBlock(MetadataKindBlock, true);
- inline for (@typeInfo(ir.MetadataKind).Enum.fields) |field| {
- try metadata_kind_block.writeAbbrev(MetadataKindBlock.Kind{
- .id = field.value,
- .name = field.name,
- });
+ inline for (@typeInfo(ir.FixedMetadataKind).Enum.fields) |field| {
+ // don't include `dbg` in stripped functions
+ if (!(self.strip and std.mem.eql(u8, field.name, "dbg"))) {
+ try metadata_kind_block.writeAbbrev(MetadataKindBlock.Kind{
+ .id = field.value,
+ .name = field.name,
+ });
+ }
}
try metadata_kind_block.end();
@@ -13808,14 +13973,14 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
const metadata_adapter = MetadataAdapter.init(self, constant_adapter);
// METADATA_BLOCK
- if (!self.strip) {
+ {
const MetadataBlock = ir.MetadataBlock;
var metadata_block = try module_block.enterSubBlock(MetadataBlock, true);
const MetadataBlockWriter = @TypeOf(metadata_block);
// Emit all MetadataStrings
- {
+ if (self.metadata_string_map.count() > 1) {
const strings_offset, const strings_size = blk: {
var strings_offset: u32 = 0;
var strings_size: u32 = 0;
@@ -14046,7 +14211,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
else
-%val << 1 | 1);
}
- try metadata_block.writeUnabbrev(MetadataBlock.Enumerator.id, record.items);
+ try metadata_block.writeUnabbrev(@intFromEnum(MetadataBlock.Enumerator.id), record.items);
continue;
};
try metadata_block.writeAbbrevAdapted(MetadataBlock.Enumerator{
@@ -14085,6 +14250,22 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
.elements = elements,
}, metadata_adapter);
},
+ .str_tuple => {
+ var extra = self.metadataExtraDataTrail(Metadata.StrTuple, data);
+
+ const elements = extra.trail.next(extra.data.elements_len, Metadata, self);
+
+ const all_elems = try self.gpa.alloc(Metadata, elements.len + 1);
+ defer self.gpa.free(all_elems);
+ all_elems[0] = @enumFromInt(metadata_adapter.getMetadataStringIndex(extra.data.str));
+ for (elements, all_elems[1..]) |elem, *out_elem| {
+ out_elem.* = @enumFromInt(metadata_adapter.getMetadataIndex(elem));
+ }
+
+ try metadata_block.writeAbbrev(MetadataBlock.Node{
+ .elements = all_elems,
+ });
+ },
.module_flag => {
const extra = self.metadataExtraData(Metadata.ModuleFlag, data);
try metadata_block.writeAbbrev(MetadataBlock.Node{
@@ -14177,7 +14358,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
try metadata_block.writeAbbrev(MetadataBlock.GlobalDeclAttachment{
.value = @enumFromInt(constant_adapter.getConstantIndex(global.toConst())),
- .kind = ir.MetadataKind.dbg,
+ .kind = .dbg,
.metadata = @enumFromInt(metadata_adapter.getMetadataIndex(global_ptr.dbg) - 1),
});
}
@@ -14186,6 +14367,18 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
try metadata_block.end();
}
+ // OPERAND_BUNDLE_TAGS_BLOCK
+ {
+ const OperandBundleTags = ir.OperandBundleTags;
+ var operand_bundle_tags_block = try module_block.enterSubBlock(OperandBundleTags, true);
+
+ try operand_bundle_tags_block.writeAbbrev(OperandBundleTags.OperandBundleTag{
+ .tag = "cold",
+ });
+
+ try operand_bundle_tags_block.end();
+ }
+
// Block info
{
const BlockInfo = ir.BlockInfo;
@@ -14220,20 +14413,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
constant_adapter: ConstantAdapter,
metadata_adapter: MetadataAdapter,
func: *const Function,
- instruction_index: u32 = 0,
-
- pub fn init(
- const_adapter: ConstantAdapter,
- meta_adapter: MetadataAdapter,
- func: *const Function,
- ) @This() {
- return .{
- .constant_adapter = const_adapter,
- .metadata_adapter = meta_adapter,
- .func = func,
- .instruction_index = 0,
- };
- }
+ instruction_index: Function.Instruction.Index,
pub fn get(adapter: @This(), value: anytype, comptime field_name: []const u8) @TypeOf(value) {
_ = field_name;
@@ -14254,7 +14434,6 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
.instruction => |instruction| instruction.valueIndex(adapter.func) + adapter.firstInstr(),
.constant => |constant| adapter.constant_adapter.getConstantIndex(constant),
.metadata => |metadata| {
- assert(!adapter.func.strip);
const real_metadata = metadata.unwrap(adapter.metadata_adapter.builder);
if (@intFromEnum(real_metadata) < Metadata.first_local_metadata)
return adapter.metadata_adapter.getMetadataIndex(real_metadata) - 1;
@@ -14282,19 +14461,12 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
}
pub fn offset(adapter: @This()) u32 {
- return @as(
- Function.Instruction.Index,
- @enumFromInt(adapter.instruction_index),
- ).valueIndex(adapter.func) + adapter.firstInstr();
+ return adapter.instruction_index.valueIndex(adapter.func) + adapter.firstInstr();
}
fn firstInstr(adapter: @This()) u32 {
return adapter.constant_adapter.numConstants();
}
-
- pub fn next(adapter: *@This()) void {
- adapter.instruction_index += 1;
- }
};
for (self.functions.items, 0..) |func, func_index| {
@@ -14307,7 +14479,12 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
try function_block.writeAbbrev(FunctionBlock.DeclareBlocks{ .num_blocks = func.blocks.len });
- var adapter = FunctionAdapter.init(constant_adapter, metadata_adapter, &func);
+ var adapter: FunctionAdapter = .{
+ .constant_adapter = constant_adapter,
+ .metadata_adapter = metadata_adapter,
+ .func = &func,
+ .instruction_index = @enumFromInt(0),
+ };
// Emit function level metadata block
if (!func.strip and func.debug_values.len > 0) {
@@ -14330,21 +14507,27 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
var has_location = false;
var block_incoming_len: u32 = undefined;
- for (0..func.instructions.len) |instr_index| {
- const tag = tags[instr_index];
-
+ for (tags, datas, 0..) |tag, data, instr_index| {
+ adapter.instruction_index = @enumFromInt(instr_index);
record.clearRetainingCapacity();
switch (tag) {
- .block => block_incoming_len = datas[instr_index],
- .arg => {},
+ .arg => continue,
+ .block => {
+ block_incoming_len = data;
+ continue;
+ },
.@"unreachable" => try function_block.writeAbbrev(FunctionBlock.Unreachable{}),
.call,
.@"musttail call",
.@"notail call",
.@"tail call",
=> |kind| {
- var extra = func.extraDataTrail(Function.Instruction.Call, datas[instr_index]);
+ var extra = func.extraDataTrail(Function.Instruction.Call, data);
+
+ if (extra.data.info.has_op_bundle_cold) {
+ try function_block.writeAbbrev(FunctionBlock.ColdOperandBundle{});
+ }
const call_conv = extra.data.info.call_conv;
const args = extra.trail.next(extra.data.args_len, Value, &func);
@@ -14367,7 +14550,11 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
.@"notail call fast",
.@"tail call fast",
=> |kind| {
- var extra = func.extraDataTrail(Function.Instruction.Call, datas[instr_index]);
+ var extra = func.extraDataTrail(Function.Instruction.Call, data);
+
+ if (extra.data.info.has_op_bundle_cold) {
+ try function_block.writeAbbrev(FunctionBlock.ColdOperandBundle{});
+ }
const call_conv = extra.data.info.call_conv;
const args = extra.trail.next(extra.data.args_len, Value, &func);
@@ -14405,7 +14592,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
.srem,
.ashr,
=> |kind| {
- const extra = func.extraData(Function.Instruction.Binary, datas[instr_index]);
+ const extra = func.extraData(Function.Instruction.Binary, data);
try function_block.writeAbbrev(FunctionBlock.Binary{
.opcode = kind.toBinaryOpcode(),
.lhs = adapter.getOffsetValueIndex(extra.lhs),
@@ -14417,7 +14604,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
.@"lshr exact",
.@"ashr exact",
=> |kind| {
- const extra = func.extraData(Function.Instruction.Binary, datas[instr_index]);
+ const extra = func.extraData(Function.Instruction.Binary, data);
try function_block.writeAbbrev(FunctionBlock.BinaryExact{
.opcode = kind.toBinaryOpcode(),
.lhs = adapter.getOffsetValueIndex(extra.lhs),
@@ -14437,7 +14624,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
.@"shl nuw",
.@"shl nuw nsw",
=> |kind| {
- const extra = func.extraData(Function.Instruction.Binary, datas[instr_index]);
+ const extra = func.extraData(Function.Instruction.Binary, data);
try function_block.writeAbbrev(FunctionBlock.BinaryNoWrap{
.opcode = kind.toBinaryOpcode(),
.lhs = adapter.getOffsetValueIndex(extra.lhs),
@@ -14468,7 +14655,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
.@"frem fast",
.@"fsub fast",
=> |kind| {
- const extra = func.extraData(Function.Instruction.Binary, datas[instr_index]);
+ const extra = func.extraData(Function.Instruction.Binary, data);
try function_block.writeAbbrev(FunctionBlock.BinaryFast{
.opcode = kind.toBinaryOpcode(),
.lhs = adapter.getOffsetValueIndex(extra.lhs),
@@ -14479,7 +14666,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
.alloca,
.@"alloca inalloca",
=> |kind| {
- const extra = func.extraData(Function.Instruction.Alloca, datas[instr_index]);
+ const extra = func.extraData(Function.Instruction.Alloca, data);
const alignment = extra.info.alignment.toLlvm();
try function_block.writeAbbrev(FunctionBlock.Alloca{
.inst_type = extra.type,
@@ -14508,7 +14695,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
.sext,
.zext,
=> |kind| {
- const extra = func.extraData(Function.Instruction.Cast, datas[instr_index]);
+ const extra = func.extraData(Function.Instruction.Cast, data);
try function_block.writeAbbrev(FunctionBlock.Cast{
.val = adapter.getOffsetValueIndex(extra.val),
.type_index = extra.type,
@@ -14542,7 +14729,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
.@"icmp ule",
.@"icmp ult",
=> |kind| {
- const extra = func.extraData(Function.Instruction.Binary, datas[instr_index]);
+ const extra = func.extraData(Function.Instruction.Binary, data);
try function_block.writeAbbrev(FunctionBlock.Cmp{
.lhs = adapter.getOffsetValueIndex(extra.lhs),
.rhs = adapter.getOffsetValueIndex(extra.rhs),
@@ -14566,7 +14753,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
.@"fcmp fast une",
.@"fcmp fast uno",
=> |kind| {
- const extra = func.extraData(Function.Instruction.Binary, datas[instr_index]);
+ const extra = func.extraData(Function.Instruction.Binary, data);
try function_block.writeAbbrev(FunctionBlock.CmpFast{
.lhs = adapter.getOffsetValueIndex(extra.lhs),
.rhs = adapter.getOffsetValueIndex(extra.rhs),
@@ -14575,14 +14762,14 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
});
},
.fneg => try function_block.writeAbbrev(FunctionBlock.FNeg{
- .val = adapter.getOffsetValueIndex(@enumFromInt(datas[instr_index])),
+ .val = adapter.getOffsetValueIndex(@enumFromInt(data)),
}),
.@"fneg fast" => try function_block.writeAbbrev(FunctionBlock.FNegFast{
- .val = adapter.getOffsetValueIndex(@enumFromInt(datas[instr_index])),
+ .val = adapter.getOffsetValueIndex(@enumFromInt(data)),
.fast_math = FastMath.fast,
}),
.extractvalue => {
- var extra = func.extraDataTrail(Function.Instruction.ExtractValue, datas[instr_index]);
+ var extra = func.extraDataTrail(Function.Instruction.ExtractValue, data);
const indices = extra.trail.next(extra.data.indices_len, u32, &func);
try function_block.writeAbbrev(FunctionBlock.ExtractValue{
.val = adapter.getOffsetValueIndex(extra.data.val),
@@ -14590,7 +14777,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
});
},
.insertvalue => {
- var extra = func.extraDataTrail(Function.Instruction.InsertValue, datas[instr_index]);
+ var extra = func.extraDataTrail(Function.Instruction.InsertValue, data);
const indices = extra.trail.next(extra.data.indices_len, u32, &func);
try function_block.writeAbbrev(FunctionBlock.InsertValue{
.val = adapter.getOffsetValueIndex(extra.data.val),
@@ -14599,14 +14786,14 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
});
},
.extractelement => {
- const extra = func.extraData(Function.Instruction.ExtractElement, datas[instr_index]);
+ const extra = func.extraData(Function.Instruction.ExtractElement, data);
try function_block.writeAbbrev(FunctionBlock.ExtractElement{
.val = adapter.getOffsetValueIndex(extra.val),
.index = adapter.getOffsetValueIndex(extra.index),
});
},
.insertelement => {
- const extra = func.extraData(Function.Instruction.InsertElement, datas[instr_index]);
+ const extra = func.extraData(Function.Instruction.InsertElement, data);
try function_block.writeAbbrev(FunctionBlock.InsertElement{
.val = adapter.getOffsetValueIndex(extra.val),
.elem = adapter.getOffsetValueIndex(extra.elem),
@@ -14614,7 +14801,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
});
},
.select => {
- const extra = func.extraData(Function.Instruction.Select, datas[instr_index]);
+ const extra = func.extraData(Function.Instruction.Select, data);
try function_block.writeAbbrev(FunctionBlock.Select{
.lhs = adapter.getOffsetValueIndex(extra.lhs),
.rhs = adapter.getOffsetValueIndex(extra.rhs),
@@ -14622,7 +14809,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
});
},
.@"select fast" => {
- const extra = func.extraData(Function.Instruction.Select, datas[instr_index]);
+ const extra = func.extraData(Function.Instruction.Select, data);
try function_block.writeAbbrev(FunctionBlock.SelectFast{
.lhs = adapter.getOffsetValueIndex(extra.lhs),
.rhs = adapter.getOffsetValueIndex(extra.rhs),
@@ -14631,7 +14818,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
});
},
.shufflevector => {
- const extra = func.extraData(Function.Instruction.ShuffleVector, datas[instr_index]);
+ const extra = func.extraData(Function.Instruction.ShuffleVector, data);
try function_block.writeAbbrev(FunctionBlock.ShuffleVector{
.lhs = adapter.getOffsetValueIndex(extra.lhs),
.rhs = adapter.getOffsetValueIndex(extra.rhs),
@@ -14641,7 +14828,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
.getelementptr,
.@"getelementptr inbounds",
=> |kind| {
- var extra = func.extraDataTrail(Function.Instruction.GetElementPtr, datas[instr_index]);
+ var extra = func.extraDataTrail(Function.Instruction.GetElementPtr, data);
const indices = extra.trail.next(extra.data.indices_len, Value, &func);
try function_block.writeAbbrevAdapted(
FunctionBlock.GetElementPtr{
@@ -14654,7 +14841,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
);
},
.load => {
- const extra = func.extraData(Function.Instruction.Load, datas[instr_index]);
+ const extra = func.extraData(Function.Instruction.Load, data);
try function_block.writeAbbrev(FunctionBlock.Load{
.ptr = adapter.getOffsetValueIndex(extra.ptr),
.ty = extra.type,
@@ -14663,7 +14850,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
});
},
.@"load atomic" => {
- const extra = func.extraData(Function.Instruction.Load, datas[instr_index]);
+ const extra = func.extraData(Function.Instruction.Load, data);
try function_block.writeAbbrev(FunctionBlock.LoadAtomic{
.ptr = adapter.getOffsetValueIndex(extra.ptr),
.ty = extra.type,
@@ -14674,7 +14861,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
});
},
.store => {
- const extra = func.extraData(Function.Instruction.Store, datas[instr_index]);
+ const extra = func.extraData(Function.Instruction.Store, data);
try function_block.writeAbbrev(FunctionBlock.Store{
.ptr = adapter.getOffsetValueIndex(extra.ptr),
.val = adapter.getOffsetValueIndex(extra.val),
@@ -14683,7 +14870,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
});
},
.@"store atomic" => {
- const extra = func.extraData(Function.Instruction.Store, datas[instr_index]);
+ const extra = func.extraData(Function.Instruction.Store, data);
try function_block.writeAbbrev(FunctionBlock.StoreAtomic{
.ptr = adapter.getOffsetValueIndex(extra.ptr),
.val = adapter.getOffsetValueIndex(extra.val),
@@ -14695,11 +14882,11 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
},
.br => {
try function_block.writeAbbrev(FunctionBlock.BrUnconditional{
- .block = datas[instr_index],
+ .block = data,
});
},
.br_cond => {
- const extra = func.extraData(Function.Instruction.BrCond, datas[instr_index]);
+ const extra = func.extraData(Function.Instruction.BrCond, data);
try function_block.writeAbbrev(FunctionBlock.BrConditional{
.then_block = @intFromEnum(extra.then),
.else_block = @intFromEnum(extra.@"else"),
@@ -14707,7 +14894,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
});
},
.@"switch" => {
- var extra = func.extraDataTrail(Function.Instruction.Switch, datas[instr_index]);
+ var extra = func.extraDataTrail(Function.Instruction.Switch, data);
try record.ensureUnusedCapacity(self.gpa, 3 + extra.data.cases_len * 2);
@@ -14730,7 +14917,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
try function_block.writeUnabbrev(12, record.items);
},
.va_arg => {
- const extra = func.extraData(Function.Instruction.VaArg, datas[instr_index]);
+ const extra = func.extraData(Function.Instruction.VaArg, data);
try function_block.writeAbbrev(FunctionBlock.VaArg{
.list_type = extra.list.typeOf(@enumFromInt(func_index), self),
.list = adapter.getOffsetValueIndex(extra.list),
@@ -14740,7 +14927,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
.phi,
.@"phi fast",
=> |kind| {
- var extra = func.extraDataTrail(Function.Instruction.Phi, datas[instr_index]);
+ var extra = func.extraDataTrail(Function.Instruction.Phi, data);
const vals = extra.trail.next(block_incoming_len, Value, &func);
const blocks = extra.trail.next(block_incoming_len, Function.Block.Index, &func);
@@ -14764,11 +14951,11 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
try function_block.writeUnabbrev(16, record.items);
},
.ret => try function_block.writeAbbrev(FunctionBlock.Ret{
- .val = adapter.getOffsetValueIndex(@enumFromInt(datas[instr_index])),
+ .val = adapter.getOffsetValueIndex(@enumFromInt(data)),
}),
.@"ret void" => try function_block.writeAbbrev(FunctionBlock.RetVoid{}),
.atomicrmw => {
- const extra = func.extraData(Function.Instruction.AtomicRmw, datas[instr_index]);
+ const extra = func.extraData(Function.Instruction.AtomicRmw, data);
try function_block.writeAbbrev(FunctionBlock.AtomicRmw{
.ptr = adapter.getOffsetValueIndex(extra.ptr),
.val = adapter.getOffsetValueIndex(extra.val),
@@ -14782,7 +14969,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
.cmpxchg,
.@"cmpxchg weak",
=> |kind| {
- const extra = func.extraData(Function.Instruction.CmpXchg, datas[instr_index]);
+ const extra = func.extraData(Function.Instruction.CmpXchg, data);
try function_block.writeAbbrev(FunctionBlock.CmpXchg{
.ptr = adapter.getOffsetValueIndex(extra.ptr),
@@ -14797,7 +14984,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
});
},
.fence => {
- const info: MemoryAccessInfo = @bitCast(datas[instr_index]);
+ const info: MemoryAccessInfo = @bitCast(data);
try function_block.writeAbbrev(FunctionBlock.Fence{
.ordering = info.success_ordering,
.sync_scope = info.sync_scope,
@@ -14806,7 +14993,7 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
}
if (!func.strip) {
- if (func.debug_locations.get(@enumFromInt(instr_index))) |debug_location| {
+ if (func.debug_locations.get(adapter.instruction_index)) |debug_location| {
switch (debug_location) {
.no_location => has_location = false,
.location => |location| {
@@ -14823,8 +15010,6 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
try function_block.writeAbbrev(FunctionBlock.DebugLocAgain{});
}
}
-
- adapter.next();
}
// VALUE_SYMTAB
@@ -14850,18 +15035,48 @@ pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]co
}
// METADATA_ATTACHMENT_BLOCK
- if (!func.strip) blk: {
- const dbg = func.global.ptrConst(self).dbg;
-
- if (dbg == .none) break :blk;
-
+ {
const MetadataAttachmentBlock = ir.MetadataAttachmentBlock;
var metadata_attach_block = try function_block.enterSubBlock(MetadataAttachmentBlock, false);
- try metadata_attach_block.writeAbbrev(MetadataAttachmentBlock.AttachmentSingle{
- .kind = ir.MetadataKind.dbg,
- .metadata = @enumFromInt(metadata_adapter.getMetadataIndex(dbg) - 1),
- });
+ dbg: {
+ if (func.strip) break :dbg;
+ const dbg = func.global.ptrConst(self).dbg;
+ if (dbg == .none) break :dbg;
+ try metadata_attach_block.writeAbbrev(MetadataAttachmentBlock.AttachmentGlobalSingle{
+ .kind = .dbg,
+ .metadata = @enumFromInt(metadata_adapter.getMetadataIndex(dbg) - 1),
+ });
+ }
+
+ var instr_index: u32 = 0;
+ for (func.instructions.items(.tag), func.instructions.items(.data)) |instr_tag, data| switch (instr_tag) {
+ .arg, .block => {}, // not an actual instruction
+ else => {
+ instr_index += 1;
+ },
+ .br_cond, .@"switch" => {
+ const weights = switch (instr_tag) {
+ .br_cond => func.extraData(Function.Instruction.BrCond, data).weights,
+ .@"switch" => func.extraData(Function.Instruction.Switch, data).weights,
+ else => unreachable,
+ };
+ switch (weights) {
+ .none => {},
+ .unpredictable => try metadata_attach_block.writeAbbrev(MetadataAttachmentBlock.AttachmentInstructionSingle{
+ .inst = instr_index,
+ .kind = .unpredictable,
+ .metadata = @enumFromInt(metadata_adapter.getMetadataIndex(.empty_tuple) - 1),
+ }),
+ _ => try metadata_attach_block.writeAbbrev(MetadataAttachmentBlock.AttachmentInstructionSingle{
+ .inst = instr_index,
+ .kind = .prof,
+ .metadata = @enumFromInt(metadata_adapter.getMetadataIndex(@enumFromInt(@intFromEnum(weights))) - 1),
+ }),
+ }
+ instr_index += 1;
+ },
+ };
try metadata_attach_block.end();
}
diff --git a/src/codegen/llvm/ir.zig b/src/codegen/llvm/ir.zig
index 6a7c6c6857..4d7effdaaf 100644
--- a/src/codegen/llvm/ir.zig
+++ b/src/codegen/llvm/ir.zig
@@ -20,8 +20,142 @@ const ColumnAbbrev = AbbrevOp{ .vbr = 8 };
const BlockAbbrev = AbbrevOp{ .vbr = 6 };
-pub const MetadataKind = enum(u1) {
+/// Unused tags are commented out so that they are omitted in the generated
+/// bitcode, which scans over this enum using reflection.
+pub const FixedMetadataKind = enum(u8) {
dbg = 0,
+ //tbaa = 1,
+ prof = 2,
+ //fpmath = 3,
+ //range = 4,
+ //@"tbaa.struct" = 5,
+ //@"invariant.load" = 6,
+ //@"alias.scope" = 7,
+ //@"noalias" = 8,
+ //nontemporal = 9,
+ //@"llvm.mem.parallel_loop_access" = 10,
+ //nonnull = 11,
+ //dereferenceable = 12,
+ //dereferenceable_or_null = 13,
+ //@"make.implicit" = 14,
+ unpredictable = 15,
+ //@"invariant.group" = 16,
+ //@"align" = 17,
+ //@"llvm.loop" = 18,
+ //type = 19,
+ //section_prefix = 20,
+ //absolute_symbol = 21,
+ //associated = 22,
+ //callees = 23,
+ //irr_loop = 24,
+ //@"llvm.access.group" = 25,
+ //callback = 26,
+ //@"llvm.preserve.access.index" = 27,
+ //vcall_visibility = 28,
+ //noundef = 29,
+ //annotation = 30,
+ //nosanitize = 31,
+ //func_sanitize = 32,
+ //exclude = 33,
+ //memprof = 34,
+ //callsite = 35,
+ //kcfi_type = 36,
+ //pcsections = 37,
+ //DIAssignID = 38,
+ //@"coro.outside.frame" = 39,
+};
+
+pub const MetadataCode = enum(u8) {
+ /// MDSTRING: [values]
+ STRING_OLD = 1,
+ /// VALUE: [type num, value num]
+ VALUE = 2,
+ /// NODE: [n x md num]
+ NODE = 3,
+ /// STRING: [values]
+ NAME = 4,
+ /// DISTINCT_NODE: [n x md num]
+ DISTINCT_NODE = 5,
+ /// [n x [id, name]]
+ KIND = 6,
+ /// [distinct, line, col, scope, inlined-at?]
+ LOCATION = 7,
+ /// OLD_NODE: [n x (type num, value num)]
+ OLD_NODE = 8,
+ /// OLD_FN_NODE: [n x (type num, value num)]
+ OLD_FN_NODE = 9,
+ /// NAMED_NODE: [n x mdnodes]
+ NAMED_NODE = 10,
+ /// [m x [value, [n x [id, mdnode]]]
+ ATTACHMENT = 11,
+ /// [distinct, tag, vers, header, n x md num]
+ GENERIC_DEBUG = 12,
+ /// [distinct, count, lo]
+ SUBRANGE = 13,
+ /// [isUnsigned|distinct, value, name]
+ ENUMERATOR = 14,
+ /// [distinct, tag, name, size, align, enc]
+ BASIC_TYPE = 15,
+ /// [distinct, filename, directory, checksumkind, checksum]
+ FILE = 16,
+ /// [distinct, ...]
+ DERIVED_TYPE = 17,
+ /// [distinct, ...]
+ COMPOSITE_TYPE = 18,
+ /// [distinct, flags, types, cc]
+ SUBROUTINE_TYPE = 19,
+ /// [distinct, ...]
+ COMPILE_UNIT = 20,
+ /// [distinct, ...]
+ SUBPROGRAM = 21,
+ /// [distinct, scope, file, line, column]
+ LEXICAL_BLOCK = 22,
+ ///[distinct, scope, file, discriminator]
+ LEXICAL_BLOCK_FILE = 23,
+ /// [distinct, scope, file, name, line, exportSymbols]
+ NAMESPACE = 24,
+ /// [distinct, scope, name, type, ...]
+ TEMPLATE_TYPE = 25,
+ /// [distinct, scope, name, type, value, ...]
+ TEMPLATE_VALUE = 26,
+ /// [distinct, ...]
+ GLOBAL_VAR = 27,
+ /// [distinct, ...]
+ LOCAL_VAR = 28,
+ /// [distinct, n x element]
+ EXPRESSION = 29,
+ /// [distinct, name, file, line, ...]
+ OBJC_PROPERTY = 30,
+ /// [distinct, tag, scope, entity, line, name]
+ IMPORTED_ENTITY = 31,
+ /// [distinct, scope, name, ...]
+ MODULE = 32,
+ /// [distinct, macinfo, line, name, value]
+ MACRO = 33,
+ /// [distinct, macinfo, line, file, ...]
+ MACRO_FILE = 34,
+ /// [count, offset] blob([lengths][chars])
+ STRINGS = 35,
+ /// [valueid, n x [id, mdnode]]
+ GLOBAL_DECL_ATTACHMENT = 36,
+ /// [distinct, var, expr]
+ GLOBAL_VAR_EXPR = 37,
+ /// [offset]
+ INDEX_OFFSET = 38,
+ /// [bitpos]
+ INDEX = 39,
+ /// [distinct, scope, name, file, line]
+ LABEL = 40,
+ /// [distinct, name, size, align,...]
+ STRING_TYPE = 41,
+ /// [distinct, scope, name, variable,...]
+ COMMON_BLOCK = 44,
+ /// [distinct, count, lo, up, stride]
+ GENERIC_SUBRANGE = 45,
+ /// [n x [type num, value num]]
+ ARG_LIST = 46,
+ /// [distinct, ...]
+ ASSIGN_ID = 47,
};
pub const Identification = struct {
@@ -622,16 +756,29 @@ pub const MetadataAttachmentBlock = struct {
pub const id = 16;
pub const abbrevs = [_]type{
- AttachmentSingle,
+ AttachmentGlobalSingle,
+ AttachmentInstructionSingle,
};
- pub const AttachmentSingle = struct {
+ pub const AttachmentGlobalSingle = struct {
pub const ops = [_]AbbrevOp{
- .{ .literal = 11 },
+ .{ .literal = @intFromEnum(MetadataCode.ATTACHMENT) },
.{ .fixed = 1 },
MetadataAbbrev,
};
- kind: MetadataKind,
+ kind: FixedMetadataKind,
+ metadata: Builder.Metadata,
+ };
+
+ pub const AttachmentInstructionSingle = struct {
+ pub const ops = [_]AbbrevOp{
+ .{ .literal = @intFromEnum(MetadataCode.ATTACHMENT) },
+ ValueAbbrev,
+ .{ .fixed = 5 },
+ MetadataAbbrev,
+ };
+ inst: u32,
+ kind: FixedMetadataKind,
metadata: Builder.Metadata,
};
};
@@ -666,7 +813,7 @@ pub const MetadataBlock = struct {
pub const Strings = struct {
pub const ops = [_]AbbrevOp{
- .{ .literal = 35 },
+ .{ .literal = @intFromEnum(MetadataCode.STRINGS) },
.{ .vbr = 6 },
.{ .vbr = 6 },
.blob,
@@ -678,7 +825,7 @@ pub const MetadataBlock = struct {
pub const File = struct {
pub const ops = [_]AbbrevOp{
- .{ .literal = 16 },
+ .{ .literal = @intFromEnum(MetadataCode.FILE) },
.{ .literal = 0 }, // is distinct
MetadataAbbrev, // filename
MetadataAbbrev, // directory
@@ -692,7 +839,7 @@ pub const MetadataBlock = struct {
pub const CompileUnit = struct {
pub const ops = [_]AbbrevOp{
- .{ .literal = 20 },
+ .{ .literal = @intFromEnum(MetadataCode.COMPILE_UNIT) },
.{ .literal = 1 }, // is distinct
.{ .literal = std.dwarf.LANG.C99 }, // source language
MetadataAbbrev, // file
@@ -726,7 +873,7 @@ pub const MetadataBlock = struct {
pub const Subprogram = struct {
pub const ops = [_]AbbrevOp{
- .{ .literal = 21 },
+ .{ .literal = @intFromEnum(MetadataCode.SUBPROGRAM) },
.{ .literal = 0b111 }, // is distinct | has sp flags | has flags
MetadataAbbrev, // scope
MetadataAbbrev, // name
@@ -763,7 +910,7 @@ pub const MetadataBlock = struct {
pub const LexicalBlock = struct {
pub const ops = [_]AbbrevOp{
- .{ .literal = 22 },
+ .{ .literal = @intFromEnum(MetadataCode.LEXICAL_BLOCK) },
.{ .literal = 0 }, // is distinct
MetadataAbbrev, // scope
MetadataAbbrev, // file
@@ -779,7 +926,7 @@ pub const MetadataBlock = struct {
pub const Location = struct {
pub const ops = [_]AbbrevOp{
- .{ .literal = 7 },
+ .{ .literal = @intFromEnum(MetadataCode.LOCATION) },
.{ .literal = 0 }, // is distinct
LineAbbrev, // line
ColumnAbbrev, // column
@@ -796,7 +943,7 @@ pub const MetadataBlock = struct {
pub const BasicType = struct {
pub const ops = [_]AbbrevOp{
- .{ .literal = 15 },
+ .{ .literal = @intFromEnum(MetadataCode.BASIC_TYPE) },
.{ .literal = 0 }, // is distinct
.{ .literal = std.dwarf.TAG.base_type }, // tag
MetadataAbbrev, // name
@@ -813,7 +960,7 @@ pub const MetadataBlock = struct {
pub const CompositeType = struct {
pub const ops = [_]AbbrevOp{
- .{ .literal = 18 },
+ .{ .literal = @intFromEnum(MetadataCode.COMPOSITE_TYPE) },
.{ .literal = 0 | 0x2 }, // is distinct | is not used in old type ref
.{ .fixed = 32 }, // tag
MetadataAbbrev, // name
@@ -852,7 +999,7 @@ pub const MetadataBlock = struct {
pub const DerivedType = struct {
pub const ops = [_]AbbrevOp{
- .{ .literal = 17 },
+ .{ .literal = @intFromEnum(MetadataCode.DERIVED_TYPE) },
.{ .literal = 0 }, // is distinct
.{ .fixed = 32 }, // tag
MetadataAbbrev, // name
@@ -880,7 +1027,7 @@ pub const MetadataBlock = struct {
pub const SubroutineType = struct {
pub const ops = [_]AbbrevOp{
- .{ .literal = 19 },
+ .{ .literal = @intFromEnum(MetadataCode.SUBROUTINE_TYPE) },
.{ .literal = 0 | 0x2 }, // is distinct | has no old type refs
.{ .literal = 0 }, // flags
MetadataAbbrev, // types
@@ -891,7 +1038,7 @@ pub const MetadataBlock = struct {
};
pub const Enumerator = struct {
- pub const id = 14;
+ pub const id: MetadataCode = .ENUMERATOR;
pub const Flags = packed struct(u3) {
distinct: bool = false,
@@ -900,7 +1047,7 @@ pub const MetadataBlock = struct {
};
pub const ops = [_]AbbrevOp{
- .{ .literal = Enumerator.id },
+ .{ .literal = @intFromEnum(Enumerator.id) },
.{ .fixed = @bitSizeOf(Flags) }, // flags
.{ .vbr = 6 }, // bit width
MetadataAbbrev, // name
@@ -915,7 +1062,7 @@ pub const MetadataBlock = struct {
pub const Subrange = struct {
pub const ops = [_]AbbrevOp{
- .{ .literal = 13 },
+ .{ .literal = @intFromEnum(MetadataCode.SUBRANGE) },
.{ .literal = 0b10 }, // is distinct | version
MetadataAbbrev, // count
MetadataAbbrev, // lower bound
@@ -929,7 +1076,7 @@ pub const MetadataBlock = struct {
pub const Expression = struct {
pub const ops = [_]AbbrevOp{
- .{ .literal = 29 },
+ .{ .literal = @intFromEnum(MetadataCode.EXPRESSION) },
.{ .literal = 0 | (3 << 1) }, // is distinct | version
MetadataArrayAbbrev, // elements
};
@@ -939,7 +1086,7 @@ pub const MetadataBlock = struct {
pub const Node = struct {
pub const ops = [_]AbbrevOp{
- .{ .literal = 3 },
+ .{ .literal = @intFromEnum(MetadataCode.NODE) },
MetadataArrayAbbrev, // elements
};
@@ -948,7 +1095,7 @@ pub const MetadataBlock = struct {
pub const LocalVar = struct {
pub const ops = [_]AbbrevOp{
- .{ .literal = 28 },
+ .{ .literal = @intFromEnum(MetadataCode.LOCAL_VAR) },
.{ .literal = 0b10 }, // is distinct | has alignment
MetadataAbbrev, // scope
MetadataAbbrev, // name
@@ -970,7 +1117,7 @@ pub const MetadataBlock = struct {
pub const Parameter = struct {
pub const ops = [_]AbbrevOp{
- .{ .literal = 28 },
+ .{ .literal = @intFromEnum(MetadataCode.LOCAL_VAR) },
.{ .literal = 0b10 }, // is distinct | has alignment
MetadataAbbrev, // scope
MetadataAbbrev, // name
@@ -993,7 +1140,7 @@ pub const MetadataBlock = struct {
pub const GlobalVar = struct {
pub const ops = [_]AbbrevOp{
- .{ .literal = 27 },
+ .{ .literal = @intFromEnum(MetadataCode.GLOBAL_VAR) },
.{ .literal = 0b101 }, // is distinct | version
MetadataAbbrev, // scope
MetadataAbbrev, // name
@@ -1020,7 +1167,7 @@ pub const MetadataBlock = struct {
pub const GlobalVarExpression = struct {
pub const ops = [_]AbbrevOp{
- .{ .literal = 37 },
+ .{ .literal = @intFromEnum(MetadataCode.GLOBAL_VAR_EXPR) },
.{ .literal = 0 }, // is distinct
MetadataAbbrev, // variable
MetadataAbbrev, // expression
@@ -1032,7 +1179,7 @@ pub const MetadataBlock = struct {
pub const Constant = struct {
pub const ops = [_]AbbrevOp{
- .{ .literal = 2 },
+ .{ .literal = @intFromEnum(MetadataCode.VALUE) },
MetadataAbbrev, // type
MetadataAbbrev, // value
};
@@ -1043,7 +1190,7 @@ pub const MetadataBlock = struct {
pub const Name = struct {
pub const ops = [_]AbbrevOp{
- .{ .literal = 4 },
+ .{ .literal = @intFromEnum(MetadataCode.NAME) },
.{ .array_fixed = 8 }, // name
};
@@ -1052,7 +1199,7 @@ pub const MetadataBlock = struct {
pub const NamedNode = struct {
pub const ops = [_]AbbrevOp{
- .{ .literal = 10 },
+ .{ .literal = @intFromEnum(MetadataCode.NAMED_NODE) },
MetadataArrayAbbrev, // elements
};
@@ -1061,18 +1208,32 @@ pub const MetadataBlock = struct {
pub const GlobalDeclAttachment = struct {
pub const ops = [_]AbbrevOp{
- .{ .literal = 36 },
+ .{ .literal = @intFromEnum(MetadataCode.GLOBAL_DECL_ATTACHMENT) },
ValueAbbrev, // value id
.{ .fixed = 1 }, // kind
MetadataAbbrev, // elements
};
value: Builder.Constant,
- kind: MetadataKind,
+ kind: FixedMetadataKind,
metadata: Builder.Metadata,
};
};
+pub const OperandBundleTags = struct {
+ pub const id = 21;
+
+ pub const abbrevs = [_]type{OperandBundleTag};
+
+ pub const OperandBundleTag = struct {
+ pub const ops = [_]AbbrevOp{
+ .{ .literal = 1 },
+ .array_char6,
+ };
+ tag: []const u8,
+ };
+};
+
pub const FunctionMetadataBlock = struct {
pub const id = 15;
@@ -1132,6 +1293,7 @@ pub const FunctionBlock = struct {
Fence,
DebugLoc,
DebugLocAgain,
+ ColdOperandBundle,
};
pub const DeclareBlocks = struct {
@@ -1644,6 +1806,13 @@ pub const FunctionBlock = struct {
.{ .literal = 33 },
};
};
+
+ pub const ColdOperandBundle = struct {
+ pub const ops = [_]AbbrevOp{
+ .{ .literal = 55 },
+ .{ .literal = 0 },
+ };
+ };
};
pub const FunctionValueSymbolTable = struct {
diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig
index adab565508..d1df1ba77e 100644
--- a/src/codegen/spirv.zig
+++ b/src/codegen/spirv.zig
@@ -410,7 +410,7 @@ const NavGen = struct {
}
pub fn fail(self: *NavGen, comptime format: []const u8, args: anytype) Error {
- @setCold(true);
+ @branchHint(.cold);
const zcu = self.pt.zcu;
const src_loc = zcu.navSrcLoc(self.owner_nav);
assert(self.error_msg == null);
@@ -6173,11 +6173,10 @@ const NavGen = struct {
const pt = self.pt;
const zcu = pt.zcu;
const target = self.getTarget();
- const pl_op = self.air.instructions.items(.data)[@intFromEnum(inst)].pl_op;
- const cond_ty = self.typeOf(pl_op.operand);
- const cond = try self.resolve(pl_op.operand);
+ const switch_br = self.air.unwrapSwitch(inst);
+ const cond_ty = self.typeOf(switch_br.operand);
+ const cond = try self.resolve(switch_br.operand);
var cond_indirect = try self.convertToIndirect(cond_ty, cond);
- const switch_br = self.air.extraData(Air.SwitchBr, pl_op.payload);
const cond_words: u32 = switch (cond_ty.zigTypeTag(zcu)) {
.Bool, .ErrorSet => 1,
@@ -6204,18 +6203,15 @@ const NavGen = struct {
else => return self.todo("implement switch for type {s}", .{@tagName(cond_ty.zigTypeTag(zcu))}),
};
- const num_cases = switch_br.data.cases_len;
+ const num_cases = switch_br.cases_len;
// Compute the total number of arms that we need.
// Zig switches are grouped by condition, so we need to loop through all of them
const num_conditions = blk: {
- var extra_index: usize = switch_br.end;
var num_conditions: u32 = 0;
- for (0..num_cases) |_| {
- const case = self.air.extraData(Air.SwitchBr.Case, extra_index);
- const case_body = self.air.extra[case.end + case.data.items_len ..][0..case.data.body_len];
- extra_index = case.end + case.data.items_len + case_body.len;
- num_conditions += case.data.items_len;
+ var it = switch_br.iterateCases();
+ while (it.next()) |case| {
+ num_conditions += @intCast(case.items.len);
}
break :blk num_conditions;
};
@@ -6244,17 +6240,12 @@ const NavGen = struct {
// Emit each of the cases
{
- var extra_index: usize = switch_br.end;
- for (0..num_cases) |case_i| {
+ var it = switch_br.iterateCases();
+ while (it.next()) |case| {
// SPIR-V needs a literal here, which' width depends on the case condition.
- const case = self.air.extraData(Air.SwitchBr.Case, extra_index);
- const items: []const Air.Inst.Ref = @ptrCast(self.air.extra[case.end..][0..case.data.items_len]);
- const case_body = self.air.extra[case.end + items.len ..][0..case.data.body_len];
- extra_index = case.end + case.data.items_len + case_body.len;
-
- const label = case_labels.at(case_i);
+ const label = case_labels.at(case.idx);
- for (items) |item| {
+ for (case.items) |item| {
const value = (try self.air.value(item, pt)) orelse unreachable;
const int_val: u64 = switch (cond_ty.zigTypeTag(zcu)) {
.Bool, .Int => if (cond_ty.isSignedInt(zcu)) @bitCast(value.toSignedInt(zcu)) else value.toUnsignedInt(zcu),
@@ -6285,20 +6276,15 @@ const NavGen = struct {
}
// Now, finally, we can start emitting each of the cases.
- var extra_index: usize = switch_br.end;
- for (0..num_cases) |case_i| {
- const case = self.air.extraData(Air.SwitchBr.Case, extra_index);
- const items: []const Air.Inst.Ref = @ptrCast(self.air.extra[case.end..][0..case.data.items_len]);
- const case_body: []const Air.Inst.Index = @ptrCast(self.air.extra[case.end + items.len ..][0..case.data.body_len]);
- extra_index = case.end + case.data.items_len + case_body.len;
-
- const label = case_labels.at(case_i);
+ var it = switch_br.iterateCases();
+ while (it.next()) |case| {
+ const label = case_labels.at(case.idx);
try self.beginSpvBlock(label);
switch (self.control_flow) {
.structured => {
- const next_block = try self.genStructuredBody(.selection, case_body);
+ const next_block = try self.genStructuredBody(.selection, case.body);
incoming_structured_blocks.appendAssumeCapacity(.{
.src_label = self.current_block_label,
.next_block = next_block,
@@ -6306,12 +6292,12 @@ const NavGen = struct {
try self.func.body.emitBranch(self.spv.gpa, merge_label.?);
},
.unstructured => {
- try self.genBody(case_body);
+ try self.genBody(case.body);
},
}
}
- const else_body: []const Air.Inst.Index = @ptrCast(self.air.extra[extra_index..][0..switch_br.data.else_body_len]);
+ const else_body = it.elseBody();
try self.beginSpvBlock(default);
if (else_body.len != 0) {
switch (self.control_flow) {