Skip to content

LIR Reference

LIR is GDCC’s lower-level function IR. It is designed around explicit GDExtension-facing boundaries: types, variable slots, temporary values, control flow, object lifecycle, and Variant transitions are represented directly in the IR.

This reference describes the public LIR surface and the intent of each instruction. It does not document GDCC’s concrete backend implementation strategy.

An LIR unit is organized around class definitions. A class contains signals, properties, and functions; functions contain the executable body.

  • Module: contains one or more class definitions emitted by a compile unit.
  • Class definition: contains the class name, superclass, annotations, signals, properties, and functions that make up the Godot-visible class surface.
  • Signal: contains a name and parameter list for a typed signal declaration.
  • Property: contains a name, type, static flag, initialization helper, and accessor helpers for field/property surface.
  • Function: contains the signature, parameters, return type, variable table, and basic blocks for executable logic.
  • Variables: record parameters, locals, constants, and stack slots addressed by $id.
  • Basic block: contains one entry, ordinary instructions, and one terminator instruction.
  • Instruction: contains an opcode, optional result, and operands for a computation, call, read/write, or jump.

LIR is not SSA. Values flow through explicit variable slots, assignments, loads, stores, and returns. That shape keeps the IR close to GDExtension C generation without making the generated C details part of this reference.

The text form is:

($<result_id> = )?<opcode> <operand>...

Variable operands use $id, strings and operator names use quotes, and block labels are written as bare labels.

Instructions can require a result, allow an optional result, or produce no result.

  • Required result: the instruction produces a new value, written as $result = opcode ....
  • Optional result: call instructions may keep the return value or omit it when only side effects matter.
  • No result: the instruction only produces side effects, control flow, or debug metadata.

Common operand forms:

  • Variable: $value, referring to a variable id or temporary id.
  • String: "name", used for class names, function names, property names, and string literals.
  • Number or bool: 1, 1.5, true, used for immediate literal operands.
  • Label: entry, used for basic block ids.
  • Operator: "ADD", used for Godot operator enum names.

These instructions turn constants or existing variables into LIR values. They are usually expression-lowering leaves.

Creates a bool constant.

$flag = literal_bool true

Creates an integer constant.

$count = literal_int 42

Creates a floating-point constant.

$ratio = literal_float 0.5

Creates a UTF-8 String constant.

$text = literal_string "hello"

Creates a StringName constant for identity-like names such as methods, properties, and signals.

$name = literal_string_name "position"

Creates a Variant Nil value.

$v = literal_nil

Creates a null object reference.

$obj = literal_null

Moves a source value into a target-typed result slot.

$target = assign $source

assign represents a typed boundary. The source must be assignable to the result variable’s type, such as same-type assignment, object upcast, Variant boundary, supported container covariance, or a value already materialized by a supported implicit conversion rule.

These instructions create complex values, maintain lifecycle boundaries, and execute Godot operators.

Constructs a builtin value using the result variable’s type.

$vec = construct_builtin $x $y $z

Constructs Array or Packed*Array. A normal Array may carry an element type hint; a packed array is selected from the result variable type.

$items = construct_array "Node"
$packed = construct_array

Constructs a typed or generic Dictionary.

$map = construct_dictionary "StringName" "Node"

Constructs an object of a named class.

$node = construct_object "Node"

Creates a Callable from a function in the compile unit.

$cb = construct_callable "do_work"

Creates a Callable from a lambda and capture variables. The first operand is the lambda function name; the remaining operands are captures.

$cb = construct_lambda "lambda_1" $self $value

Destroys or releases a resource held by a variable, with provenance.

destruct $value "AUTO_GENERATED"

Tries to take ownership of an object reference. For non-reference-counted objects, this may be a semantic no-op.

try_own_object $obj "INTERNAL"

Tries to release ownership of an object reference. For non-reference-counted objects, this may be a semantic no-op.

try_release_object $obj "USER_EXPLICIT"

Lifecycle provenance may be AUTO_GENERATED, INTERNAL, USER_EXPLICIT, or UNKNOWN. New LIR should prefer explicit provenance.

Executes a unary Godot operator.

$out = unary_op "NEGATE" $value

Available unary operators:

OperatorCommon source spelling
NEGATEunary -
POSITIVEunary +
BIT_NOT~
NOTnot, !

Executes a binary Godot operator.

$sum = binary_op "ADD" $left $right

Available binary operators:

OperatorCommon source spelling
EQUAL==
NOT_EQUAL!=
LESS<
LESS_EQUAL<=
GREATER>
GREATER_EQUAL>=
ADDbinary +
SUBTRACTbinary -
MULTIPLY*
DIVIDE/
MODULE%
POWER**
SHIFT_LEFT<<
SHIFT_RIGHT>>
BIT_AND&
BIT_OR|
BIT_XOR^
ANDand, &&
ORor, ||
XORxor
INin

The LIR text operand uses the enum name, such as "ADD" or "NEGATE", not the source symbol + or -.

These instructions are the dynamic access surface for Variant, dictionary-like, array-like, object-like, keyed, named, and indexed access.

Reads from a Variant with a Variant key.

$out = variant_get $variant $key

Reads from a keyed Variant, usually dictionary-like.

$out = variant_get_keyed $dict_like $key

Reads from a named Variant using StringName.

$out = variant_get_named $object_like $name

Reads from a Variant using an integer index.

$out = variant_get_indexed $array_like $index

Writes to a Variant with a Variant key.

variant_set $variant $key $value

Writes to a keyed Variant.

variant_set_keyed $dict_like $key $value

Writes to a named Variant.

variant_set_named $object_like $name $value

Writes to a Variant using an integer index.

variant_set_indexed $array_like $index $value

Results often remain Variant until a later unpack_variant, assign, or explicit typed boundary.

Type instructions handle runtime type queries, object tests, object casts, and stable-type to Variant transitions.

Reads the Godot type id held by a Variant.

$type_id = get_variant_type $variant

Gets a static type name or runtime object class name as String.

$name = get_class_name $value

Casts an object to a named class, returning null on mismatch.

$node = object_cast "Node" $obj

Tests whether an object is an instance of a named class.

$ok = is_instance_of "Node" $obj

Packs a stable value into Variant.

$variant = pack_variant $value

Unpacks a Variant into the result variable’s type.

$value = unpack_variant $variant

pack_variant and unpack_variant are the explicit markers for entering and leaving dynamic value space.

Tests whether a Variant is Nil.

$is_nil = variant_is_nil $variant

Tests whether an object reference is null.

$is_null = object_is_null $obj

Control-flow instructions terminate basic blocks.

Unconditionally branches to a basic block.

goto exit

Branches to true/false blocks based on a bool.

go_if $cond then_block else_block

go_if expects a boolean condition. Dynamic or non-boolean source conditions should be normalized before the branch.

Returns from the current function, with or without a value.

return
return $value

Call instructions allow optional results. Keep the result when the surrounding expression needs it; omit it for side-effect-only calls.

Calls a global function.

$out = call_global "print" $message

Calls an instance method. The first variable operand is the receiver.

$out = call_method "get_child" $node $index

Calls a superclass method.

call_super_method "_ready" $self

Calls a static method on a class.

$out = call_static_method "MathUtil" "clamp_i" $value $min $max

Calls a backend-owned intrinsic registered by name. Implicit conversions that need materialization use this shape, such as c_int_to_float and c_vector3i_to_vector3.

$out = call_intrinsic "intrinsic_name" $arg

Call arguments are listed in source order. Retain the result only when the surrounding expression needs it.

These instructions represent stable property/static paths, unlike variant_get_named and variant_set_named, which operate through dynamic Variant access.

Reads a named property from an object.

$value = load_property "position" $node

Writes a named property on an object.

store_property "position" $node $value

Reads a static variable or property.

$value = load_static "GameState" "score"

Writes a static variable or property.

store_static "GameState" "score" $value

Does nothing; useful as a placeholder or test instruction.

nop

Marks the current source line for diagnostics or debug data.

line_number 27
  • Data: literal_bool, literal_int, literal_float, literal_string, literal_string_name, literal_nil, literal_null, assign.
  • Construction, lifecycle, and operators: construct_builtin, construct_array, construct_dictionary, construct_object, construct_callable, construct_lambda, destruct, try_own_object, try_release_object, unary_op, binary_op.
  • Indexing and dynamic access: variant_get, variant_get_keyed, variant_get_named, variant_get_indexed, variant_set, variant_set_keyed, variant_set_named, variant_set_indexed.
  • Type: get_variant_type, get_class_name, object_cast, is_instance_of, pack_variant, unpack_variant, variant_is_nil, object_is_null.
  • Control flow: goto, go_if, return.
  • Calls: call_global, call_method, call_super_method, call_static_method, call_intrinsic.
  • Access: load_property, store_property, load_static, store_static.
  • Misc: nop, line_number.