Papers
Topics
Authors
Recent
Search
2000 character limit reached

CuLifter: GPU Binary Lifting Framework

Updated 4 July 2026
  • CuLifter is a GPU binary lifting framework that reconstructs typed LLVM IR from untyped NVIDIA SASS using constraint propagation to recover lost type information.
  • It organizes the lifting process into three ordered stages—control-flow recovery, semantic-operation recovery, and type recovery—to ensure correct, explicitly typed IR generation.
  • Empirical evaluation shows a 99.98% function lifting success across 24,437 GPU functions, emphasizing the central role of type recovery in the pipeline.

Searching arXiv for CuLifter and closely related GPU binary lifting work. CuLifter is a SASS-to-LLVM IR lifting framework for NVIDIA GPU binaries that targets the central obstacle in GPU binary lifting: recovery of type information from SASS’s untyped, unified register file (Zhao et al., 30 Apr 2026). The framework reconstructs typed LLVM IR by combining three ordered components—control-flow recovery, semantic-operation recovery, and type recovery via constraint propagation with conflict detection—and reports successful lifting of 99.98% of functions across eight benchmark suites comprising 24,437 GPU functions in 919 cubins. Its design is motivated by the mismatch between final-machine GPU assembly, where registers carry no explicit type tags, and LLVM IR, where every operation must be explicitly typed.

1. Problem Setting and Motivation

GPU compilers lower typed PTX into SASS, NVIDIA’s final-machine assembly, using a single, “unified” register file that holds integers, floats, pointers, 16-bit packed values, and booleans without tag bits or transfer instructions to distinguish them (Zhao et al., 30 Apr 2026). A register can therefore be interpreted as Float32 in one instruction and as Int32 in the next, with no intervening typed move such as movd or cvtsi2ss. In this setting, a register name such as R25 carries no type information.

This is a fundamental difficulty for any LLVM-based lifter because LLVM IR is strongly typed: add, fadd, load, icmp, and related operations require explicit operand and result types. Without determining whether a SASS value corresponds to i32, float, or another type, a lifter cannot emit valid IR for its uses. The paper situates this as more than a syntactic issue. Downstream analyses such as alias analysis, vectorization, machine-modeling, and vulnerability scanning, as well as retargeted backends such as x86/emulation and ARM, all depend on correct typing. An integer/float confusion can silently corrupt numerics by orders of magnitude.

A common misconception is that binary lifting is dominated by CFG reconstruction or instruction decoding. CuLifter’s empirical results argue instead that type recovery from the untyped register file is the central challenge of GPU binary lifting. This claim is directly supported by its ablation study, where disabling type recovery collapses downstream pass rates to zero.

2. Architecture and Lifting Pipeline

CuLifter organizes lifting into three ordered stages and then emits typed LLVM IR plus NVVM intrinsics (Zhao et al., 30 Apr 2026).

Stage Main functions Result
Stage 1 Control-flow recovery SSIR, CFG, SSA with ψ\psi-functions
Stage 2 Semantic-operation recovery Aggregated operations and recognized CUDA objects
Stage 3 Type recovery via constraint propagation Typed LLVM IR

The pipeline is specified step by step as follows. CuLifter first disassembles a cubin into raw SASS. It then parses instructions and expands hidden registers into SSIR, identifies block leaders from entry points, branch targets, fall-throughs, and predicate changes, and constructs a CFG plus SSA with ψ\psi-functions. It next pattern-matches and rewrites SSIR sequences into aggregated operations, runs fixed-point type propagation, and finally emits typed LLVM IR together with NVVM intrinsics.

The architectural ordering is significant. Control-flow reconstruction establishes the program skeleton. Semantic-operation recovery normalizes the instruction stream by collapsing multi-instruction idioms into higher-level operations. Type recovery then propagates constraints over the resulting SSA graph, detects conflicts, and inserts explicit bitcasts where a single static type cannot satisfy all uses. This sequence suggests that CuLifter treats typing not as a by-product of decoding but as a dedicated inference stage operating over a normalized IR.

3. Type Recovery by Constraint Propagation

CuLifter’s type system is formulated over a finite domain

L={Bool}{Int8,Int16,Int32,Int64,Int128}{Float16,BF16,TF32,Float32,Float64}.L = \{\mathrm{Bool}\}\cup\{\mathrm{Int}8,\mathrm{Int}16,\mathrm{Int}32,\mathrm{Int}64,\mathrm{Int}128\}\cup\{\mathrm{Float}16,\mathrm{BF}16,\mathrm{TF}32,\mathrm{Float}32,\mathrm{Float}64\}.

Each SSA value vv is assigned a candidate-type set T(v)LT(v)\subseteq L, initialized as T0(v)=LT_0(v)=L (Zhao et al., 30 Apr 2026). Type inference begins by seeding constraints from typed opcodes. Examples given in the paper include FADD→Float32, ISETP→Bool, LDG→Num32, and HMMA.F32.BF16→BF16 inputs with Float32 accumulators. For an instruction II defining register rr, CuLifter intersects the current candidate set with the instruction’s known result type:

T(r)T(r)Cdef(I).T(r)\leftarrow T(r)\cap C_{\mathrm{def}(I)}.

For type-transparent instructions such as MOV, bitwise logic, and memory operations, CuLifter enforces equality-style constraints along SSA edges. If an instruction defines yy from uses ψ\psi0, then

ψ\psi1

For conversion opcodes such as I2F and F2I, it applies the known mapping ψ\psi2 so that ψ\psi3.

Constraint solving proceeds by worklist-based fixed-point iteration. Registers whose candidate sets change are re-enqueued, and all constraints touching them are re-applied until convergence. The reported complexity is ψ\psi4, where ψ\psi5 is the number of registers and ψ\psi6 is the maximum def–use chain length; in practice, convergence occurs in at most six iterations.

CuLifter’s distinctive mechanism is conflict detection. If a new intersection yields an empty set, ψ\psi7, then no single type satisfies all uses. Rather than treating this as failure, the framework identifies a type boundary at the conflicting use site, keeps the definition-site register at its prior type, inserts an LLVM bitcast from the definition type to the use-required type, and marks the register as conflicted so that the contradiction does not cascade (Zhao et al., 30 Apr 2026). After convergence, any remaining ambiguous set defaults to Int32 if available, otherwise Int64, otherwise the first remaining type; unreachable-code empties are reset to Int32 for soundness.

This design directly encodes a property of SASS programs: the same register may legitimately cross type boundaries. CuLifter therefore does not assume global single-type consistency per physical register, but instead restores typed semantics at the SSA-use level.

4. Control-Flow Reconstruction and SSIR

CuLifter’s front end constructs SSIR by parsing SASS and expanding implicit register groups (Zhao et al., 30 Apr 2026). This is necessary because many SASS opcodes mention only part of a register group: for example, LDG.E.64 R4 defines R5:R4, and tensor-core shapes may expand to fourteen or more registers. CuLifter consults per-opcode tables so that SSIR makes all reads and writes explicit.

CFG recovery is predicate-aware. Basic-block leaders include function entry, branch targets, fall-throughs, and any change in predicate guard. This ensures that each block has uniform predication. A predicated branch such as @P0 [BRA](https://www.emergentmind.com/topics/bi-level-routing-attention-bra-6d73b6b5-85c4-42bc-ad01-5245b1a2adc0) target becomes a two-way conditional branch to target or fall-through. A predicated @P0 EXIT becomes a conditional return of those lanes. For dual-predicate branches of the form @!P0 BRA P1,target, CuLifter models !P0 as the execution guard and P1 as the branch condition, using nested conditionals in SSIR to recover the true control-flow edges.

SSA construction is performed with ψ\psi8-functions rather than conventional ψ\psi9-nodes at the point where predicated writes within a block are merged. For each register L={Bool}{Int8,Int16,Int32,Int64,Int128}{Float16,BF16,TF32,Float32,Float64}.L = \{\mathrm{Bool}\}\cup\{\mathrm{Int}8,\mathrm{Int}16,\mathrm{Int}32,\mathrm{Int}64,\mathrm{Int}128\}\cup\{\mathrm{Float}16,\mathrm{BF}16,\mathrm{TF}32,\mathrm{Float}32,\mathrm{Float}64\}.0, CuLifter collects the ordered list of (pred, val) pairs together with the live-in value L={Bool}{Int8,Int16,Int32,Int64,Int128}{Float16,BF16,TF32,Float32,Float64}.L = \{\mathrm{Bool}\}\cup\{\mathrm{Int}8,\mathrm{Int}16,\mathrm{Int}32,\mathrm{Int}64,\mathrm{Int}128\}\cup\{\mathrm{Float}16,\mathrm{BF}16,\mathrm{TF}32,\mathrm{Float}32,\mathrm{Float}64\}.1, removes the predicated writes, and appends a single SSA assignment of the form

L={Bool}{Int8,Int16,Int32,Int64,Int128}{Float16,BF16,TF32,Float32,Float64}.L = \{\mathrm{Bool}\}\cup\{\mathrm{Int}8,\mathrm{Int}16,\mathrm{Int}32,\mathrm{Int}64,\mathrm{Int}128\}\cup\{\mathrm{Float}16,\mathrm{BF}16,\mathrm{TF}32,\mathrm{Float}32,\mathrm{Float}64\}.2

This realizes a L={Bool}{Int8,Int16,Int32,Int64,Int128}{Float16,BF16,TF32,Float32,Float64}.L = \{\mathrm{Bool}\}\cup\{\mathrm{Int}8,\mathrm{Int}16,\mathrm{Int}32,\mathrm{Int}64,\mathrm{Int}128\}\cup\{\mathrm{Float}16,\mathrm{BF}16,\mathrm{TF}32,\mathrm{Float}32,\mathrm{Float}64\}.3-node L={Bool}{Int8,Int16,Int32,Int64,Int128}{Float16,BF16,TF32,Float32,Float64}.L = \{\mathrm{Bool}\}\cup\{\mathrm{Int}8,\mathrm{Int}16,\mathrm{Int}32,\mathrm{Int}64,\mathrm{Int}128\}\cup\{\mathrm{Float}16,\mathrm{BF}16,\mathrm{TF}32,\mathrm{Float}32,\mathrm{Float}64\}.4. Convergence barriers such as SSY/SYNC or BSSY/BSYNC delimit regions across which threads that have not reconverged are not merged.

The framework also recovers embedded device functions. SASS kernels can contain CALL.ABS.NOINC addr to RET pairs in the same section without ELF symbols. After CFG construction, disconnected subgraphs whose entry addresses match relocated call targets are extracted as separate SSIR functions or, when they are small helpers, inlined back into the caller to preserve SSA scope. This is an important detail for realistic cubins, where binary organization does not always align with high-level function boundaries.

5. Semantic-Operation Recovery and CUDA Object Recognition

Stage 2 aggregates multi-instruction idioms by pattern matching and variable unification (Zhao et al., 30 Apr 2026). CuLifter uses a catalog of generation-specific templates and a variable-unification graph matcher that slides a window over each basic block, binds symbolic operands to actual SSIR registers, and replaces matched sequences with a single pseudo-operation or LLVM intrinsic.

The listed idioms include carry chains, where two IADD3/IADD3.X instructions represent a 64-bit add; XMAD fusion on SM52, producing an IMAD pseudo-instruction; fast reciprocal sequences consisting of I2F→MUFU.RCP→IADD3→F2I with a magic constant; .X4 address scaling, rewritten into an explicit shl; and packed conversions such as F2FP_PACK_AB_MERGE_C, which are synthesized into extract, pack, and unpack steps.

CuLifter also recognizes CUDA objects and synchronization structures. Patterns of WARPSYNC/BAR.SYNC with mask constants distinguish warp scope from block scope in cooperative groups. SHFL.XOR is mapped to llvm.nvvm.read.ptx.s32.shrd.* or to custom mutex/shuffle emulation in the CPU backend. Atomics and barriers are folded into standard IR intrinsics.

The role of this stage is normalization rather than primary correctness enforcement. The ablation study later shows that disabling pattern normalization leaves the reported x86 pass rate unchanged. That result does not make semantic aggregation unimportant; rather, it indicates that, within the tested pipeline, pattern aggregation improves representation quality and semantic compactness, while type recovery determines whether the lifted IR is semantically correct enough for downstream execution.

6. Evaluation, Ablations, and Performance

The evaluation spans eight benchmark suites totaling 919 cubins and 24,437 GPU functions across SM75–SM120: HeCBench with 773 functions across 10 domains; cuBLAS with 7,260 functions; CUTLASS with 641 functions; FlashAttention with 4,952 functions; cuDNN CNN, cuDNN Ops, and cuDNN Adv with approximately 11,092 functions; and 19 CUDA SDK example functions (Zhao et al., 30 Apr 2026).

On this corpus, CuLifter lifts 24,431 of 24,437 functions, yielding a 99.98% lifting rate. The six failures all occur in CUTLASS and are attributed to the new SM90 QGMMA opcode not yet being implemented in the parser. The paper explicitly reports no type-propagation bug and no CFG bug in these failures.

The characterization of type recovery is detailed. Of instructions, 90.1% are seeding, 6.3% are transparent, and 3.8% are conflicts. Value resolution is attributed 90.5% to seeding, 4.9% to propagation, 3.2% to conflict bitcasts, and 1.4% to default fallback. For non-seeded values, 68% are resolved within one hop and 95% within three hops of propagation. Fixed-point convergence averages 3.5 iterations and never exceeds six iterations over all kernels.

The ablation study uses HeCBench with 229 kernels and an x86 CPU backend. The full pipeline yields 169 of 229 passing kernels, or 73.8%, with failures limited by CPU emulation issues such as MUFU approximations and textures. Disabling predicate-to-select lowering gives 72.9%, a decrease of 0.9 percentage points. Disabling pattern normalization leaves the result unchanged at 73.8%. By contrast, disabling propagation and retaining seed-only typing yields 0%, and disabling all type recovery also yields 0%. This 73.8 percentage-point drop is the strongest empirical basis for the paper’s thesis that type propagation is the only step whose removal collapses downstream correctness.

Reported runtime is modest: average parsing plus CFG construction is approximately 15 ms per function, pattern recovery approximately 5 ms, and type propagation approximately 3 ms, for an end-to-end lifting time of approximately 25–50 ms per function on a 16-core x86 server.

7. Illustrative Example and Technical Significance

The paper’s worked example is a fast inverse square root snippet in which FADD and MUFU.RSQ use R25 and R24 as Float32, while a later IADD3 consumes R25 as Int32 (Zhao et al., 30 Apr 2026). In the lifted LLVM IR, CuLifter emits

L={Bool}{Int8,Int16,Int32,Int64,Int128}{Float16,BF16,TF32,Float32,Float64}.L = \{\mathrm{Bool}\}\cup\{\mathrm{Int}8,\mathrm{Int}16,\mathrm{Int}32,\mathrm{Int}64,\mathrm{Int}128\}\cup\{\mathrm{Float}16,\mathrm{BF}16,\mathrm{TF}32,\mathrm{Float}32,\mathrm{Float}64\}.7

The example exhibits the core mechanism of the framework. FADD seeds %v as Float32; a later integer use at IADD3 demands Int32; the intersection L={Bool}{Int8,Int16,Int32,Int64,Int128}{Float16,BF16,TF32,Float32,Float64}.L = \{\mathrm{Bool}\}\cup\{\mathrm{Int}8,\mathrm{Int}16,\mathrm{Int}32,\mathrm{Int}64,\mathrm{Int}128\}\cup\{\mathrm{Float}16,\mathrm{BF}16,\mathrm{TF}32,\mathrm{Float}32,\mathrm{Float}64\}.5 is empty; and CuLifter therefore inserts %v_i = bitcast float %v to i32 at the use boundary. The result is valid LLVM IR with well-formed types throughout. In this example, L={Bool}{Int8,Int16,Int32,Int64,Int128}{Float16,BF16,TF32,Float32,Float64}.L = \{\mathrm{Bool}\}\cup\{\mathrm{Int}8,\mathrm{Int}16,\mathrm{Int}32,\mathrm{Int}64,\mathrm{Int}128\}\cup\{\mathrm{Float}16,\mathrm{BF}16,\mathrm{TF}32,\mathrm{Float}32,\mathrm{Float}64\}.6-functions are not needed because only one predicated block is present.

The broader significance is methodological. CuLifter demonstrates that GPU binary lifting to typed IR is feasible at scale when the lifter explicitly models SASS’s erased type system, reconstructs predicate-sensitive control flow, and admits local type reinterpretation through conflict-driven bitcasts. It also narrows the engineering bottleneck: unsupported opcode coverage, exemplified by SM90 QGMMA, appears as a concrete residual limitation, while the ablations indicate that the decisive semantic barrier is not CFG formation or idiom aggregation but type recovery from the unified register file. A plausible implication is that future extensions of the framework will depend primarily on expanding parser and pattern coverage for new GPU generations while preserving the same constraint-propagation core.

Definition Search Book Streamline Icon: https://streamlinehq.com
References (1)

Topic to Video (Beta)

No one has generated a video about this topic yet.

Whiteboard

No one has generated a whiteboard explanation for this topic yet.

Follow Topic

Get notified by email when new papers are published related to CuLifter.