// SPDX-License-Identifier: Apache-2.0
// Copyright 2017 WebAssembly Community Group participants.
// Copyright 2023 WebAssembly Community Group participants (historical Starshine notice).
// Adapted and modified for Starshine in 2026: HOT graph representation,
// typed boundaries, cache handling and validation differ from upstream.
// Derived portions retain Apache-2.0 terms; see ../../licenses/Binaryen-LICENSE.txt.
// Source: Binaryen src/passes/PickLoadSigns.cpp, version_130.
// https://github.com/WebAssembly/binaryen/blob/version_130/src/passes/PickLoadSigns.cpp
///|
pub fn pick_load_signs_descriptor() -> @ir.HotPassDescriptor {
@ir.HotPassDescriptor::new(
"pick-load-signs",
requires=[@ir.HotAnalysis::use_def()],
invalidates=[
@ir.HotAnalysis::cfg(),
@ir.HotAnalysis::dominance(),
@ir.HotAnalysis::liveness(),
@ir.HotAnalysis::use_def(),
@ir.HotAnalysis::effects(),
@ir.HotAnalysis::loop_info(),
@ir.HotAnalysis::ssa(),
],
)
}
///|
pub fn pick_load_signs_summary() -> String {
"Pick narrower signed/unsigned load opcodes based on local use extension evidence."
}
///|
priv struct PLSUsage {
mut signed_usages : Int32
mut signed_bits : Int32
mut unsigned_usages : Int32
mut unsigned_bits : Int32
mut total_usages : Int32
mut invalid : Bool
}
///|
fn PLSUsage::new() -> PLSUsage {
{
signed_usages: 0,
signed_bits: 0,
unsigned_usages: 0,
unsigned_bits: 0,
total_usages: 0,
invalid: false,
}
}
///|
priv struct PLSCandidateLoad {
local_idx : Int32
set_node : Int32
load_id : Int32
load_addr_id : Int32
load_bits : Int32
load_is_i64 : Bool
current_signed : Bool
target_signed : Bool
}
///|
priv struct PLSShiftExtCacheEntry {
has_result : Bool
is_signed : Bool
bits : Int32
root_id : Int32
}
///|
priv struct PLSElidableUse {
local_idx : Int32
read_id : Int32
root_id : Int32
bits : Int32
target_signed : Bool
}
///|
priv struct PLSAnalysis {
candidates : Array[PLSCandidateLoad]
rewritable_candidates : Int32
elidable_uses : Array[PLSElidableUse]
}
///|
fn pls_record_signed_usage(
usage_by_local : Array[PLSUsage],
local_idx : Int32,
bits : Int32,
) -> Unit {
let usage = usage_by_local[local_idx]
if usage.invalid {
return
}
if usage.signed_usages == 0 {
usage.signed_bits = bits
} else if usage.signed_bits != bits {
usage.invalid = true
usage_by_local[local_idx] = usage
return
}
usage.signed_usages += 1
usage_by_local[local_idx] = usage
}
///|
fn pls_record_unsigned_usage(
usage_by_local : Array[PLSUsage],
local_idx : Int32,
bits : Int32,
) -> Unit {
let usage = usage_by_local[local_idx]
if usage.invalid {
return
}
if usage.unsigned_usages == 0 {
usage.unsigned_bits = bits
} else if usage.unsigned_bits != bits {
usage.invalid = true
usage_by_local[local_idx] = usage
return
}
usage.unsigned_usages += 1
usage_by_local[local_idx] = usage
}
///|
fn pls_load_info(instr : @lib.Instruction) -> (Bool, Int32, Bool)? {
match instr {
@lib.Instruction::I32Load8S(_) => Some((true, 8, false))
@lib.Instruction::I32Load8U(_) => Some((false, 8, false))
@lib.Instruction::I32Load16S(_) => Some((true, 16, false))
@lib.Instruction::I32Load16U(_) => Some((false, 16, false))
@lib.Instruction::I64Load8S(_) => Some((true, 8, true))
@lib.Instruction::I64Load8U(_) => Some((false, 8, true))
@lib.Instruction::I64Load16S(_) => Some((true, 16, true))
@lib.Instruction::I64Load16U(_) => Some((false, 16, true))
@lib.Instruction::I64Load32S(_) => Some((true, 32, true))
@lib.Instruction::I64Load32U(_) => Some((false, 32, true))
_ => None
}
}
///|
fn pls_load_with_signedness(
instr : @lib.Instruction,
signed : Bool,
) -> @lib.Instruction? {
match instr {
@lib.Instruction::I32Load8S(memarg) =>
Some(
if signed {
@lib.Instruction::i32_load8s(memarg)
} else {
@lib.Instruction::i32_load8u(memarg)
},
)
@lib.Instruction::I32Load8U(memarg) =>
Some(
if signed {
@lib.Instruction::i32_load8s(memarg)
} else {
@lib.Instruction::i32_load8u(memarg)
},
)
@lib.Instruction::I32Load16S(memarg) =>
Some(
if signed {
@lib.Instruction::i32_load16s(memarg)
} else {
@lib.Instruction::i32_load16u(memarg)
},
)
@lib.Instruction::I32Load16U(memarg) =>
Some(
if signed {
@lib.Instruction::i32_load16s(memarg)
} else {
@lib.Instruction::i32_load16u(memarg)
},
)
@lib.Instruction::I64Load8S(memarg) =>
Some(
if signed {
@lib.Instruction::i64_load8s(memarg)
} else {
@lib.Instruction::i64_load8u(memarg)
},
)
@lib.Instruction::I64Load8U(memarg) =>
Some(
if signed {
@lib.Instruction::i64_load8s(memarg)
} else {
@lib.Instruction::i64_load8u(memarg)
},
)
@lib.Instruction::I64Load16S(memarg) =>
Some(
if signed {
@lib.Instruction::i64_load16s(memarg)
} else {
@lib.Instruction::i64_load16u(memarg)
},
)
@lib.Instruction::I64Load16U(memarg) =>
Some(
if signed {
@lib.Instruction::i64_load16s(memarg)
} else {
@lib.Instruction::i64_load16u(memarg)
},
)
@lib.Instruction::I64Load32S(memarg) =>
Some(
if signed {
@lib.Instruction::i64_load32s(memarg)
} else {
@lib.Instruction::i64_load32u(memarg)
},
)
@lib.Instruction::I64Load32U(memarg) =>
Some(
if signed {
@lib.Instruction::i64_load32s(memarg)
} else {
@lib.Instruction::i64_load32u(memarg)
},
)
_ => None
}
}
///|
fn pls_i32_const_node(func : @ir.HotFunc, node_id : Int32) -> @lib.I32? {
if node_id < 0 || !@ir.hot_node_is_live(func, node_id) {
return None
}
let node = @ir.hot_node_get(func, node_id)
match node.op {
@ir.HotOp::Const =>
match @ir.hot_const_get(func, node.imm0) {
@ir.HotConstPayload::I32Const(value) => Some(value)
_ => None
}
_ => None
}
}
///|
fn pls_i64_const_node(func : @ir.HotFunc, node_id : Int32) -> @lib.I64? {
if node_id < 0 || !@ir.hot_node_is_live(func, node_id) {
return None
}
let node = @ir.hot_node_get(func, node_id)
match node.op {
@ir.HotOp::Const =>
match @ir.hot_const_get(func, node.imm0) {
@ir.HotConstPayload::I64Const(value) => Some(value)
_ => None
}
_ => None
}
}
///|
fn pls_const_i32_eq(
func : @ir.HotFunc,
node_id : Int32,
expected : @lib.I32,
) -> Bool {
match pls_i32_const_node(func, node_id) {
Some(bits) => bits == expected
None => false
}
}
///|
fn pls_const_i64_eq(
func : @ir.HotFunc,
node_id : Int32,
expected : @lib.I64,
) -> Bool {
match pls_i64_const_node(func, node_id) {
Some(bits) => bits == expected
None => false
}
}
///|
fn pls_i32_low_mask_bits(mask : @lib.I32) -> Int32? {
let @lib.I32(value) = mask
let mut bits = 0
let mut value_u = value.reinterpret_as_uint()
while bits < 32 && (value_u & 1U) == 1U {
bits += 1
value_u = value_u >> 1
}
if bits > 0 && value_u == 0U {
Some(bits)
} else {
None
}
}
///|
fn pls_i64_low_mask_bits(mask : @lib.I64) -> Int32? {
let @lib.I64(value) = mask
let mut bits = 0
let mut value_u = value.reinterpret_as_uint64()
while bits < 64 && (value_u & 1UL) == 1UL {
bits += 1
value_u = value_u >> 1
}
if bits > 0 && value_u == 0UL {
Some(bits)
} else {
None
}
}
///|
fn pls_i32_shift_ext_bits(shift : @lib.I32) -> Int32 {
let @lib.I32(value) = shift
let effective = value.reinterpret_as_uint() & 31U
32 - effective.reinterpret_as_int()
}
///|
fn pls_i64_shift_ext_bits(shift : @lib.I64) -> Int32 {
let @lib.I64(value) = shift
let effective = value.reinterpret_as_uint64() & 63UL
64 - effective.to_int()
}
///|
fn pls_is_child_use_slot(kind : @ir.HotUseSlotKind) -> Bool {
match kind {
@ir.HotUseSlotKind::ChildUseSlot => true
_ => false
}
}
///|
fn pls_target_signedness(
candidate : PLSCandidateLoad,
usage : PLSUsage,
) -> Bool {
if usage.invalid ||
usage.total_usages == 0 ||
usage.signed_usages + usage.unsigned_usages != usage.total_usages ||
(usage.signed_usages != 0 && usage.signed_bits != candidate.load_bits) ||
(usage.unsigned_usages != 0 && usage.unsigned_bits != candidate.load_bits) {
candidate.current_signed
} else if usage.signed_usages * 2 >= usage.unsigned_usages {
true
} else {
false
}
}
///|
fn pls_extension_from_grandparent_zero_ext(
func : @ir.HotFunc,
use_def : @ir.HotUseDef,
parent_id : Int32,
shift_bits : @lib.I32,
) -> (Bool, Int32, Int32)? {
for grand_site in @ir.node_use_sites_borrowed(use_def, parent_id) {
if !pls_is_child_use_slot(grand_site.kind) || grand_site.slot != 0 {
continue
}
let grand_id = grand_site.user
let grand_instr = match @ir.hot_node_exact_instr(func, grand_id) {
Some(i) => i
None => continue
}
let grand_rhs = @ir.hot_child_get(func, grand_id, 1)
if !pls_const_i32_eq(func, grand_rhs, shift_bits) {
continue
}
match grand_instr {
@lib.Instruction::I32ShrU(_) =>
return Some((false, pls_i32_shift_ext_bits(shift_bits), grand_id))
@lib.Instruction::I32ShrS(_) =>
return Some((true, pls_i32_shift_ext_bits(shift_bits), grand_id))
_ => ()
}
}
None
}
///|
fn pls_extension_from_grandparent_zero_ext64(
func : @ir.HotFunc,
use_def : @ir.HotUseDef,
parent_id : Int32,
shift_bits : @lib.I64,
) -> (Bool, Int32, Int32)? {
for grand_site in @ir.node_use_sites_borrowed(use_def, parent_id) {
if !pls_is_child_use_slot(grand_site.kind) || grand_site.slot != 0 {
continue
}
let grand_id = grand_site.user
let grand_instr = match @ir.hot_node_exact_instr(func, grand_id) {
Some(i) => i
None => continue
}
let grand_rhs = @ir.hot_child_get(func, grand_id, 1)
if !pls_const_i64_eq(func, grand_rhs, shift_bits) {
continue
}
match grand_instr {
@lib.Instruction::I64ShrU(_) =>
return Some((false, pls_i64_shift_ext_bits(shift_bits), grand_id))
@lib.Instruction::I64ShrS(_) =>
return Some((true, pls_i64_shift_ext_bits(shift_bits), grand_id))
_ => ()
}
}
None
}
///|
fn pls_extension_from_parent(
func : @ir.HotFunc,
use_def : @ir.HotUseDef,
_read_node_id : Int32,
site : @ir.HotUseSite,
shift_ext_cache : @hashmap.HashMap[Int32, PLSShiftExtCacheEntry],
) -> (Bool, Int32, Int32)? {
if !pls_is_child_use_slot(site.kind) {
return None
}
let parent_id = site.user
let parent_instr = match @ir.hot_node_exact_instr(func, parent_id) {
Some(i) => i
None => return None
}
if site.slot == 0 {
match parent_instr {
@lib.Instruction::I32Extend8S => return Some((true, 8, -1))
@lib.Instruction::I32Extend16S => return Some((true, 16, -1))
@lib.Instruction::I64Extend8S => return Some((true, 8, parent_id))
@lib.Instruction::I64Extend16S => return Some((true, 16, parent_id))
@lib.Instruction::I64Extend32S => return Some((true, 32, parent_id))
@lib.Instruction::I64ExtendI32S => return Some((true, 32, -1))
@lib.Instruction::I64ExtendI32U => return Some((false, 32, -1))
@lib.Instruction::I32Shl => {
let shift_bits = match
pls_i32_const_node(func, @ir.hot_child_get(func, parent_id, 1)) {
Some(bits) => bits
None => return None
}
let updated_cache = match shift_ext_cache.get(parent_id) {
Some(cache) => cache
None => {
let cache = match
pls_extension_from_grandparent_zero_ext(
func, use_def, parent_id, shift_bits,
) {
Some((is_signed, bits, root_id)) =>
{ has_result: true, is_signed, bits, root_id, }
None =>
{ has_result: false, is_signed: false, bits: 0, root_id: -1, }
}
shift_ext_cache.set(parent_id, cache)
cache
}
}
if updated_cache.has_result {
return Some(
(
updated_cache.is_signed,
updated_cache.bits,
if updated_cache.is_signed {
-1
} else {
updated_cache.root_id
},
),
)
}
return None
}
@lib.Instruction::I64Shl => {
let shift_bits = match
pls_i64_const_node(func, @ir.hot_child_get(func, parent_id, 1)) {
Some(bits) => bits
None => return None
}
let updated_cache = match shift_ext_cache.get(parent_id) {
Some(cache) => cache
None => {
let cache = match
pls_extension_from_grandparent_zero_ext64(
func, use_def, parent_id, shift_bits,
) {
Some((is_signed, bits, root_id)) =>
{ has_result: true, is_signed, bits, root_id, }
None =>
{ has_result: false, is_signed: false, bits: 0, root_id: -1, }
}
shift_ext_cache.set(parent_id, cache)
cache
}
}
if updated_cache.has_result {
return Some(
(updated_cache.is_signed, updated_cache.bits, updated_cache.root_id),
)
}
return None
}
_ => ()
}
}
match parent_instr {
@lib.Instruction::I32And => {
let sibling_id = if site.slot == 0 {
@ir.hot_child_get(func, parent_id, 1)
} else if site.slot == 1 {
@ir.hot_child_get(func, parent_id, 0)
} else {
return None
}
let mask = match pls_i32_const_node(func, sibling_id) {
Some(v) => v
None => return None
}
match pls_i32_low_mask_bits(mask) {
Some(bits) =>
Some((false, bits, if site.slot == 1 { parent_id } else { -1 }))
None => None
}
}
@lib.Instruction::I64And => {
let sibling_id = if site.slot == 0 {
@ir.hot_child_get(func, parent_id, 1)
} else if site.slot == 1 {
@ir.hot_child_get(func, parent_id, 0)
} else {
return None
}
let mask = match pls_i64_const_node(func, sibling_id) {
Some(v) => v
None => return None
}
match pls_i64_low_mask_bits(mask) {
Some(bits) => Some((false, bits, parent_id))
None => None
}
}
_ => None
}
}
///|
fn pls_analyze_candidates(
func : @ir.HotFunc,
candidates : Array[PLSCandidateLoad],
use_def : @ir.HotUseDef,
) -> PLSAnalysis {
let usage_by_local : Array[PLSUsage] = []
let usage_slot_by_local : @hashmap.HashMap[Int32, Int32] = @hashmap.new(
capacity=candidates.length() * 2 + 1,
)
let local_work_list : Array[Int32] = []
let cleanup_uses : Array[PLSElidableUse] = []
let shift_ext_cache : @hashmap.HashMap[Int32, PLSShiftExtCacheEntry] = @hashmap.new(
capacity=candidates.length() * 2 + 1,
)
for candidate in candidates {
let local_idx = candidate.local_idx
if local_idx < 0 || local_idx >= @ir.hot_local_count(func) {
continue
}
match usage_slot_by_local.get(local_idx) {
Some(_) => ()
None => {
usage_slot_by_local.set(local_idx, usage_by_local.length())
usage_by_local.push(PLSUsage::new())
local_work_list.push(local_idx)
}
}
}
for local_idx in local_work_list {
let usage_slot = usage_slot_by_local.get(local_idx).unwrap()
for read_id in @ir.local_read_nodes_borrowed(use_def, local_idx) {
if usage_by_local[usage_slot].invalid {
break
}
if !@ir.hot_node_is_live(func, read_id) {
continue
}
for site in @ir.node_use_sites_borrowed(use_def, read_id) {
let usage = usage_by_local[usage_slot]
if usage.invalid {
break
}
usage.total_usages += 1
usage_by_local[usage_slot] = usage
match
pls_extension_from_parent(
func, use_def, read_id, site, shift_ext_cache,
) {
Some((is_signed, bits, root_id)) =>
if is_signed {
pls_record_signed_usage(usage_by_local, usage_slot, bits)
if root_id >= 0 {
cleanup_uses.push({
local_idx,
read_id,
root_id,
bits,
target_signed: true,
})
}
} else {
pls_record_unsigned_usage(usage_by_local, usage_slot, bits)
if root_id >= 0 {
cleanup_uses.push({
local_idx,
read_id,
root_id,
bits,
target_signed: false,
})
}
}
None => {
let usage = usage_by_local[usage_slot]
usage.invalid = true
usage_by_local[usage_slot] = usage
}
}
}
}
}
let mut rewritable_candidates = 0
for idx in 0..= 0 &&
candidate_by_write.get(candidate.set_node) is None {
candidate_by_write.set(candidate.set_node, candidate)
}
}
let cleanup_eligibility : Array[(Int32, Bool)?] = Array::make(
usage_by_local.length(),
None,
)
for local_idx in local_work_list {
let usage_slot = usage_slot_by_local.get(local_idx).unwrap()
if local_idx < @ir.hot_param_count(func) {
continue
}
let writes = @ir.local_write_nodes_borrowed(use_def, local_idx)
if writes.is_empty() {
continue
}
let mut bits = -1
let mut target_signed = false
let mut rewrites_opposite_load = false
let mut all_matching = true
for write_id in writes {
let candidate = match candidate_by_write.get(write_id) {
Some(candidate) => candidate
_ => {
all_matching = false
break
}
}
if bits < 0 {
bits = candidate.load_bits
target_signed = candidate.target_signed
} else if candidate.load_bits != bits ||
candidate.target_signed != target_signed {
all_matching = false
break
}
if candidate.current_signed != target_signed {
rewrites_opposite_load = true
}
}
if all_matching && rewrites_opposite_load {
cleanup_eligibility[usage_slot] = Some((bits, target_signed))
}
}
let elidable_uses : Array[PLSElidableUse] = []
let seen_roots : @hashmap.HashMap[Int32, Bool] = @hashmap.new(
capacity=cleanup_uses.length() * 2 + 1,
)
for cleanup_use in cleanup_uses {
if cleanup_use.root_id < 0 ||
seen_roots.get(cleanup_use.root_id) == Some(true) {
continue
}
let usage_slot = usage_slot_by_local.get(cleanup_use.local_idx).unwrap()
match cleanup_eligibility[usage_slot] {
Some((bits, target_signed)) if bits == cleanup_use.bits &&
target_signed == cleanup_use.target_signed => {
elidable_uses.push(cleanup_use)
seen_roots.set(cleanup_use.root_id, true)
}
_ => ()
}
}
{ candidates, rewritable_candidates, elidable_uses, }
}
///|
fn pls_scan_candidate_loads(
func : @ir.HotFunc,
use_def : @ir.HotUseDef,
) -> Array[PLSCandidateLoad] {
let candidates : Array[PLSCandidateLoad] = []
for local_idx in 0..<@ir.hot_local_count(func) {
for node_id in @ir.local_write_nodes_borrowed(use_def, local_idx) {
let node = @ir.hot_node_get(func, node_id)
match node.op {
@ir.HotOp::LocalSet => ()
_ => continue
}
let child_id = @ir.hot_child_get(func, node_id, 0)
if child_id < 0 || !@ir.hot_node_is_live(func, child_id) {
continue
}
let child_node = @ir.hot_node_get(func, child_id)
match child_node.op {
@ir.HotOp::Load => ()
_ => continue
}
let current_load = match @ir.hot_node_exact_instr(func, child_id) {
Some(v) => v
None => continue
}
let load_addr_id = @ir.hot_child_get(func, child_id, 0)
if load_addr_id < 0 || !@ir.hot_node_is_live(func, load_addr_id) {
continue
}
match pls_load_info(current_load) {
Some((current_signed, load_bits, load_is_i64)) =>
candidates.push({
local_idx,
set_node: node_id,
load_id: child_id,
load_addr_id,
load_bits,
load_is_i64,
current_signed,
target_signed: false,
})
None => ()
}
}
}
candidates
}
///|
fn pls_rewrite_candidates(
ctx : HotPassContext,
func : @ir.HotFunc,
analysis : PLSAnalysis,
) -> Bool {
let mut changed = false
for candidate in analysis.candidates {
if candidate.target_signed == candidate.current_signed {
continue
}
if !@ir.hot_node_is_live(func, candidate.load_id) {
continue
}
let current_load = match @ir.hot_node_exact_instr(func, candidate.load_id) {
Some(v) => v
None => continue
}
let next_load = match
pls_load_with_signedness(current_load, candidate.target_signed) {
Some(instr) => instr
None => continue
}
pipeline_trace_hook(
ctx.trace,
"pick-load-signs",
"replace-load",
payload="candidate(\{candidate.local_idx},\{candidate.set_node}) load_id=\{candidate.load_id} target_signed=\{candidate.target_signed}",
)
@ir.hot_node_exact_instr_set(func, candidate.load_id, next_load)
pass_mark_mutated(ctx, func)
pipeline_trace_hook(
ctx.trace,
"pick-load-signs",
"replace-load-done",
payload="load_id=\{candidate.load_id}",
)
changed = true
}
for cleanup_use in analysis.elidable_uses {
if !@ir.hot_node_is_live(func, cleanup_use.root_id) ||
!@ir.hot_node_is_live(func, cleanup_use.read_id) {
continue
}
match @ir.hot_node_exact_instr(func, cleanup_use.root_id) {
Some(@lib.Instruction::I32ShrU(_))
| Some(@lib.Instruction::I64ShrU(_))
| Some(@lib.Instruction::I64ShrS(_))
| Some(@lib.Instruction::I32And)
| Some(@lib.Instruction::I64And)
| Some(@lib.Instruction::I64Extend8S)
| Some(@lib.Instruction::I64Extend16S)
| Some(@lib.Instruction::I64Extend32S) => ()
_ => continue
}
let read_node = @ir.hot_node_get(func, cleanup_use.read_id)
match read_node.op {
@ir.HotOp::LocalGet => ()
_ => continue
}
pipeline_trace_hook(
ctx.trace,
"pick-load-signs",
"remove-redundant-extension",
payload="local=\{cleanup_use.local_idx} root_id=\{cleanup_use.root_id} bits=\{cleanup_use.bits} signed=\{cleanup_use.target_signed}",
)
pass_replace_node(ctx, func, cleanup_use.root_id, read_node)
changed = true
}
changed
}
///|
fn pick_load_signs_run(
ctx : HotPassContext,
func : @ir.HotFunc,
) -> HotPassResult {
let use_def = pass_require_use_def(ctx, func)
let candidates = pls_scan_candidate_loads(func, use_def)
pipeline_trace_hook(
ctx.trace,
"pick-load-signs",
"scan-candidates",
payload="count=\{candidates.length()}",
)
if candidates.length() == 0 {
pipeline_trace_hook(ctx.trace, "pick-load-signs", "scan-none")
return HotPassResult::unchanged()
}
let analysis = pls_analyze_candidates(func, candidates, use_def)
pipeline_trace_hook(
ctx.trace,
"pick-load-signs",
"analyzed",
payload="rewritable=\{analysis.rewritable_candidates} elidable_uses=\{analysis.elidable_uses.length()}",
)
if analysis.rewritable_candidates == 0 && analysis.elidable_uses.length() == 0 {
pipeline_trace_hook(ctx.trace, "pick-load-signs", "no-rewrites")
return HotPassResult::unchanged()
}
if pls_rewrite_candidates(ctx, func, analysis) {
pipeline_trace_hook(ctx.trace, "pick-load-signs", "rewrite-changed")
HotPassResult::changed()
} else {
pipeline_trace_hook(ctx.trace, "pick-load-signs", "rewrite-no-changes")
HotPassResult::unchanged()
}
}