Thin normalization pass over disassembled BEAM instructions.
Assigns globally-unique instruction IDs, canonicalizes allocation variants,
and strips typed register annotations. The goal is to simplify downstream
pattern matching in Argus.Pipeline.Emit without losing information.
Instruction ID format
Each instruction gets an ID of the form "mod:func/arity#idx" where idx
is the zero-based index within the function body. The format itself is
owned by Argus.InstrId — see Argus.InstrId.mint/2.
Normalization rules
- Typed registers:
{:tr, reg, _type}→reg. The type info from the compiler is stripped since we derive types from the instruction stream. - Allocation variants:
allocate_heap,allocate_zero, etc. are canonicalized — the heap hint is preserved in a uniform tuple shape. - test_heap: canonicalized to extract the raw word count from
{:alloc, ...}. - Everything else passes through unchanged with its ID attached.
Summary
Functions
Returns the function ID string for a given MFA.
The name and arity a function ID was minted from, parsed right-anchored
so compiler-generated names containing / or : survive.
Normalizes a function's instructions.
Types
@type instruction_id() :: String.t()
@type normalized() :: {instruction_id(), term()}
Functions
@spec func_id(atom(), atom(), non_neg_integer()) :: String.t()
Returns the function ID string for a given MFA.
@spec func_id_name_arity(String.t()) :: {String.t(), non_neg_integer()}
The name and arity a function ID was minted from, parsed right-anchored
so compiler-generated names containing / or : survive.
@spec normalize_function( atom(), {:function, atom(), non_neg_integer(), non_neg_integer(), list()} ) :: [normalized()]
Normalizes a function's instructions.
Takes a module name and a function tuple from :beam_disasm and returns
a list of {id, instruction} pairs with normalized instructions.