ir

package
v0.0.0-...-d52052c Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 29, 2026 License: BSD-3-Clause Imports: 4 Imported by: 0

Documentation

Overview

Package ir is the typed structured IR every target is emitted from.

Why an IR and not an AST walk per target

The predecessor emitted GLSL and MSL by walking the Go AST with a `glsl bool` threaded through every method, and ran a separate inspection pass per target to find written buffers. That is the two-target shape of a problem that is quadratic in targets. Every analysis here (recursion, access inference, capability requirements, and at M4 barrier divergence) runs once, on one representation.

SPIR-V is the argument that makes it mandatory rather than tidy. It is a binary SSA format with explicit result ids and structured control flow declared through OpSelectionMerge and OpLoopMerge, which you do not print by walking an AST, and there is no cgo-free path from GLSL text to SPIR-V because glslang and shaderc are C++. Vulkan consumes SPIR-V only.

Why structured control flow, and why not go/ssa

The IR is a tree of typed statements with `if` and `for` as nodes, not a general CFG. Three of the four GPU targets are structured source languages and SPIR-V demands structured control flow anyway, so golang.org/x/tools/go/ssa is rejected: it discards exactly the structure every target needs back, and recovering it means writing a relooper to undo work nobody needed done. Because the Go subset excludes goto and arbitrary labeled jumps, the structure survives for free.

The set is closed

There is deliberately no generic AST escape node. A construct outside this set is a source-positioned subset error, never a passthrough. See specs/004-kernel-authoring.md.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Assign

type Assign struct {
	LHS Value
	RHS Value
	// contains filtered or unexported fields
}

Assign stores to a local, an index, or a field.

func NewAssign

func NewAssign(p token.Pos, lhs, rhs Value) *Assign

type Attribute

type Attribute struct {
	Name  string
	Index int
	Type  *Type
}

Attribute is one per-vertex input of a vertex stage.

Index is the dense position among the stage's attributes, which is what the pipeline's vertex layout binds against — not the parameter position, since the receiver and any uniforms are interleaved with them in the signature.

type Binary

type Binary struct {
	Op   token.Token
	X, Y Value
	// contains filtered or unexported fields
}

Binary is a binary operation.

func NewBinary

func NewBinary(p token.Pos, t *Type, op token.Token, x, y Value) *Binary

func (Binary) Type

func (v Binary) Type() *Type

type Binding

type Binding struct {
	Name  string
	Index int
	Type  *Type

	// Read and Write are inferred from the body rather than declared. A caller
	// who could declare them would be a second source of truth for something the
	// compiler already knows, and one that can be wrong.
	Read, Write bool
}

Binding is one resource parameter, as the IR sees it.

type Block

type Block struct {
	List []Stmt
	// contains filtered or unexported fields
}

Block is a statement sequence.

func NewBlock

func NewBlock(p token.Pos, list ...Stmt) *Block

type Break

type Break struct {
	// contains filtered or unexported fields
}

Break and Continue carry no label, because the subset admits none.

func NewBreak

func NewBreak(p token.Pos) *Break

type Call

type Call struct {
	Callee *Func
	Args   []Value
	// contains filtered or unexported fields
}

Call is a call to a helper in the same compilation.

func NewCall

func NewCall(p token.Pos, t *Type, callee *Func, args []Value) *Call

func (Call) Type

func (v Call) Type() *Type

type Composite

type Composite struct {
	Elems []Value
	// contains filtered or unexported fields
}

Composite is a struct or array literal.

Admitted for the graphics stages of specs/032-stage-abi.md and nowhere else. A stage must *construct* what it returns — a clip position, a varyings struct, an attachment struct — and there is no other way to say that. A compute kernel writes through its bindings and has nothing to build, so the subset stays closed there and the front end refuses one.

Elems is positional and complete: the front end expands a keyed literal and fills an omitted field with its zero, so an emitter never has to know which spelling the author used.

func (Composite) Type

func (v Composite) Type() *Type

type Const

type Const struct {
	Val constant.Value
	// contains filtered or unexported fields
}

Const is a compile-time constant with its resolved type and value.

Resolved, which is where the GLSL integer-literal divergence is settled: the emitter knows whether the 2 in gid*2 is u32, i32, or f32 and spells it accordingly, instead of coercing the id to int to keep literals legal.

func NewConst

func NewConst(p token.Pos, t *Type, v constant.Value) *Const

func (Const) Type

func (v Const) Type() *Type

type Continue

type Continue struct {
	// contains filtered or unexported fields
}

Continue leaves the current iteration.

func NewContinue

func NewContinue(p token.Pos) *Continue

type Convert

type Convert struct {
	X Value
	// contains filtered or unexported fields
}

Convert is an explicit conversion. There are no implicit ones: Go's own rules already forbid them between the numeric types here, which is what keeps a narrow dtype from silently participating in arithmetic.

func NewConvert

func NewConvert(p token.Pos, t *Type, x Value) *Convert

func (Convert) Type

func (v Convert) Type() *Type

type Declare

type Declare struct {
	Local *Local
	Init  Value
	// contains filtered or unexported fields
}

Declare introduces a local, with its initializer.

func NewDeclare

func NewDeclare(p token.Pos, l *Local, init Value) *Declare

type ExprStmt

type ExprStmt struct {
	X Value
	// contains filtered or unexported fields
}

ExprStmt is a call evaluated for its effect.

func NewExprStmt

func NewExprStmt(p token.Pos, x Value) *ExprStmt

type Field

type Field struct {
	Name string
	Type *Type
}

Field is one member of a struct type.

type FieldSel

type FieldSel struct {
	X     Value
	Index int
	Name  string
	// contains filtered or unexported fields
}

FieldSel is a struct or ID3 field selection.

func NewFieldSel

func NewFieldSel(p token.Pos, t *Type, x Value, i int, name string) *FieldSel

func (FieldSel) Type

func (v FieldSel) Type() *Type

type For

type For struct {
	Init Stmt
	Cond Value
	Post Stmt
	Body *Block
	// contains filtered or unexported fields
}

For covers all three Go loop forms: Init and Post are nil for the condition-only form, and Cond is nil for the infinite form.

func NewFor

func NewFor(p token.Pos, init Stmt, cond Value, post Stmt, body *Block) *For

type Func

type Func struct {
	Name  string
	Stage Stage

	// Workgroup is the extent from the //accel:kernel directive. Zero for a
	// helper and for a graphics stage.
	Workgroup [3]uint32

	// Thread is the index of the accel.Thread parameter, or -1 for a helper that
	// does not take one.
	Thread   int
	Params   []*Param
	Bindings []*Binding
	Body     *Block

	// Shared is the workgroup-shared storage the signature declares, in
	// signature order. Its element type and extent come from the Go array type,
	// so the IR never invents const generics.
	Shared []*SharedMem

	// Cooperative reports that the body reaches a barrier, shared memory, or a
	// subgroup operation, so it needs the resumable lowering rather than the
	// flat one. It is derived from the body, never declared: a declaration can
	// be forgotten and the failure would be a kernel lowered the wrong way.
	Cooperative bool

	// Caps is every capability the body implies, inferred from the intrinsics it
	// reaches. Never declared: a declaration can be forgotten, and the failure
	// is silent -- a kernel using a feature the device lacks produces wrong
	// results rather than an error, because nothing checked.
	Caps uint32

	// Textures are the shader-visible texture bindings the signature declares,
	// in signature order. A texture is a distinct resource kind from a slice
	// binding and from a uniform, so the three are distinguishable by type
	// alone.
	Textures []*TextureBinding

	// Attributes are a vertex stage's per-vertex inputs, in signature order.
	// They are the by-value array parameters; a uniform is a by-value struct and
	// a storage buffer is a slice, so the three are distinguishable by type
	// alone. See specs/032-stage-abi.md section 2.2.
	Attributes []*Attribute

	// Varyings is the struct a vertex stage returns as its second result and a
	// fragment stage takes as its second parameter. The same named type, checked
	// by object identity rather than structurally: two empty structs are
	// structurally identical and mean different things.
	Varyings *Type

	// Outputs are a fragment stage's colour attachments, one per field of its
	// result struct, in declaration order.
	Outputs []*Target

	// Discards reports that the body reaches accel.Discard, which stops a
	// backend promising an early depth test the stage cannot have.
	Discards bool

	// Atomics reports that this function's own body reaches an atomic
	// read-modify-write. It does not include what its helpers reach; a caller
	// that needs the whole picture unions this over Helpers, which is already
	// transitive.
	//
	// An atomic is the only thing specs/002-compute-model.md defines *between*
	// workgroups, so it is the only thing that can make a kernel's result
	// depend on the order they run in. That is what the CPU backend gates its
	// worker pool on: see kernel.Kernel.OrderIndependent.
	Atomics bool

	// Intrinsics is every intrinsic the body reaches, in first-use order, by its
	// authored spelling. The digest records these rather than resolved package
	// paths, so relocating a type does not invalidate a committed digest.
	Intrinsics []string

	// Source is the normalized text of the authored declaration, printed from
	// the AST rather than read from the file.
	//
	// Printed, because it has to work for a package that is not on disk, and
	// because normalizing means a gofmt run does not force every kernel to be
	// regenerated while a semantic edit still does. Comments are dropped for the
	// same reason: a comment is not something the generated form depends on.
	Source string

	// Digest identifies everything this kernel's generated form depends on, not
	// only its source. Filled in by the generator.
	Digest string

	// Result is a helper's return type, or nil for a kernel and for a helper
	// that returns nothing. A kernel never returns: it writes through its
	// bindings.
	Result *Type

	// SignatureBuilt reports whether this function's parameters are known. A
	// helper's signature is built before any body, so that a helper calling
	// another can be checked whatever order the file declares them in.
	SignatureBuilt bool

	// Uniforms are the by-value struct parameters, in signature order. Each
	// carries the std140 layout its codec is generated from.
	Uniforms []*Uniform

	// Helpers are the helpers this function's body reaches, transitively, in a
	// stable order. The digest records them so that editing a helper without
	// regenerating its callers is caught.
	Helpers []*Func
	// contains filtered or unexported fields
}

Func is an entry point or a helper.

func (Func) Pos

func (p Func) Pos() token.Pos

type If

type If struct {
	Cond Value
	Then *Block
	Else Stmt
	// contains filtered or unexported fields
}

If is a conditional. Else is nil, a *Block, or another *If.

func NewIf

func NewIf(p token.Pos, cond Value, then *Block, els Stmt) *If

type IndexExpr

type IndexExpr struct {
	X     Value
	Index Value

	// Binding is the parameter index of the resource this reaches, or -1 when
	// the indexed value is not a binding. Access inference reads it, which is
	// why an access is a property of the IR rather than of a second AST pass.
	Binding int
	// contains filtered or unexported fields
}

IndexExpr is an index into a slice or a shared array.

func NewIndex

func NewIndex(p token.Pos, t *Type, x, idx Value, binding int) *IndexExpr

func (IndexExpr) Type

func (v IndexExpr) Type() *Type

type IntrinsicCall

type IntrinsicCall struct {
	Op   Opcode
	Recv Value // the Thread receiver, or nil for a free function
	Args []Value
	// contains filtered or unexported fields
}

IntrinsicCall is a call to a known intrinsic, identified by opcode rather than by name. Resolution happens in the front end against object identity; by the time it reaches the IR the name is gone and cannot be confused with a user function that shares it.

func NewIntrinsic

func NewIntrinsic(p token.Pos, t *Type, op Opcode, recv Value, args []Value) *IntrinsicCall

func (IntrinsicCall) Type

func (v IntrinsicCall) Type() *Type

type Kind

type Kind int

Kind is a type's shape in the IR.

const (
	Invalid Kind = iota
	Bool
	I32
	U32
	F32
	// I8 and U8 are storage and conversion types, for quantized weights. Like
	// the narrow floats they are storage rather than arithmetic kinds.
	I8
	U8
	// F16 and BF16 are storage kinds. They carry no arithmetic: a value converts
	// to F32 on load and back on store, which is what makes narrow dtypes work
	// on every backend rather than only where native narrow arithmetic exists.
	F16
	BF16
	// ID3Kind is the three-component id struct, which is a distinct kind rather
	// than an ordinary struct because every target has a native spelling for it.
	ID3Kind
	// MaskKind is a subgroup ballot: an opaque value with methods, 128 bits
	// wide. A distinct kind for the opposite reason ID3Kind is one -- no target
	// has a spelling every other target shares, since Vulkan's is a 4-vector,
	// Metal's is a simd_vote that is not an integer at all, and the dtype set
	// has no 64-bit integer to fall back on. specs/058-ballot.md §2.
	MaskKind
	Struct
	// Array is a fixed-extent workgroup-shared array, whose extent go/types
	// reads off the type so the IR never invents const generics.
	Array
	// Slice is a storage-buffer binding.
	Slice
	// Texture2D is a shader-visible texture binding, distinct from Slice so the
	// compiler can tell an image binding from a storage buffer. It carries no
	// element type: the fetch that reads it returns four floats whatever the
	// bound format is, the way every target's float-sampled texture does. See
	// specs/032-stage-abi.md section 5.
	Texture2D
)

func (Kind) Bytes

func (k Kind) Bytes() int

Bytes is a scalar kind's size in memory.

Zero for a kind that is not a scalar, which makes "not a scalar" answerable rather than a guess: a caller summing shared-memory bytes needs to know the difference between an eight-bit type and a struct it cannot size.

func (Kind) Numeric

func (k Kind) Numeric() bool

Numeric reports whether arithmetic is expressible on this kind directly. F16 and BF16 are excluded on purpose: they are storage formats and Go itself forces the conversion, so f32 accumulation is not a convention but the only thing that compiles.

func (Kind) String

func (k Kind) String() string

type Len

type Len struct {
	X Value
	// contains filtered or unexported fields
}

Len is the length of a slice binding. It is a node rather than an intrinsic because every target spells it differently and none of them spells it as a call.

func NewLen

func NewLen(p token.Pos, t *Type, x Value) *Len

func (Len) Type

func (v Len) Type() *Type

type Local

type Local struct {
	Name string
	ID   int
	Obj  types.Object
	// contains filtered or unexported fields
}

Local is a declared local variable.

func NewLocal

func NewLocal(p token.Pos, t *Type, id int, name string, obj types.Object) *Local

func (Local) Type

func (v Local) Type() *Type

type Node

type Node interface {
	Pos() token.Pos
}

Node is anything in the IR, which is everything carrying a source position. A diagnostic that cannot name a line is one a reader cannot act on.

type Opcode

type Opcode int

Opcode identifies an intrinsic. It is versioned as part of the intrinsic table's ABI, which participates in the kernel digest.

const (
	OpInvalid Opcode = iota

	// Thread ids. Available to a flat kernel.
	OpGlobalID
	OpLocalID
	OpGroupID
	OpGlobalIndex
	OpLocalIndex
	OpGroupIndex

	// Dispatch shape, specs/052-dispatch-shape.md. WorkgroupSize is a
	// compile-time constant and the other two are dispatch parameters, which
	// is a distinction the emitters keep rather than the IR.
	OpWorkgroupSize
	OpNumGroups
	OpGlobalSize

	// Bounded scalar math from accel/kmath. Each has a normative per-operation
	// domain and error ceiling in spec 008 section 6; an operation with no bound
	// is not admitted rather than admitted with a tuned tolerance.
	OpSqrt
	OpRSqrt
	OpExp
	OpLog
	OpSin
	OpCos
	OpTanh
	OpAbs
	OpMin
	OpMax

	// Saturating float-to-integer conversions. Intrinsics rather than an
	// ir.Convert because the conversion Go spells has no defined result for a
	// value the destination cannot hold, and neither does MSL's or SPIR-V's --
	// specs/051-float-to-int.md.
	OpToI32
	OpToU32

	// Conversions between narrow storage and f32. They are intrinsics rather
	// than IR conversions because every target spells them differently: a native
	// instruction where the format exists, and a bit-packing sequence where it
	// does not.
	OpF16ToF32
	OpBF16ToF32
	OpF32ToF16
	OpF32ToBF16

	// Atomics. Free functions taking a buffer and an index, because GLSL cannot
	// form a pointer into a buffer (specs/002-compute-model.md section 4.1).
	// Each returns the previous value.
	OpAtomicAddU32
	OpAtomicAddI32
	OpAtomicSubU32
	OpAtomicSubI32
	OpAtomicMinU32
	OpAtomicMinI32
	OpAtomicMaxU32
	OpAtomicMaxI32
	OpAtomicAndU32
	OpAtomicOrU32
	OpAtomicXorU32
	OpAtomicExchangeU32
	OpAtomicExchangeI32
	OpAtomicCompareExchangeU32
	OpAtomicCompareExchangeI32

	// OpAtomicAddF32 is a capability rather than a baseline, and it makes a
	// reduction non-deterministic because the hardware picks the accumulation
	// order.
	OpAtomicAddF32

	// Subgroup operations. Each is a rendezvous in the generated lowering,
	// because it needs every lane's contribution at the point of the call and
	// the scheduler advances one invocation at a time.
	OpSubgroupSize
	OpSubgroupID
	OpSubgroupInvocationID

	// OpSubgroupBarrier is a barrier at subgroup scope, specs/050 and 002
	// §5.3. It sits before the rendezvous range on purpose: it combines
	// nothing and returns nothing, so IsSubgroupRendezvous -- which selects the
	// two-state contribute/result split -- must not cover it, while IsSubgroup
	// must, because it is capability-gated like the rest.
	OpSubgroupBarrier

	OpSubgroupAddF32
	OpSubgroupMinF32
	OpSubgroupMaxF32

	// The integer minima and maxima, specs/059-subgroup-reductions.md §6's
	// first slice. Inside the rendezvous range, because they combine across
	// lanes exactly as the f32 ones do.
	OpSubgroupMinI32
	OpSubgroupMaxI32
	OpSubgroupMinU32
	OpSubgroupMaxU32

	// The bitwise family, specs/059-subgroup-reductions.md §6's second slice.
	OpSubgroupAndI32
	OpSubgroupOrI32
	OpSubgroupXorI32
	OpSubgroupAndU32
	OpSubgroupOrU32
	OpSubgroupXorU32

	// The products, specs/059-subgroup-reductions.md §6's third slice.
	OpSubgroupMulF32
	OpSubgroupMulI32
	OpSubgroupMulU32
	OpBroadcastFirstF32
	OpElect
	OpSubgroupAny
	OpSubgroupAll
	OpBallot

	// The lane-addressed reads. Each takes a value and a second operand naming
	// which lane to read, and each is undefined when that lane is not active --
	// see specs/002-compute-model.md section 5.2 rule 3, which is why the CPU
	// oracle carries a definition bit beside the value rather than a number.
	OpBroadcastF32
	OpShuffleF32
	OpShuffleXorF32
	OpShuffleUpF32
	OpShuffleDownF32

	// The scans. A scan is a reduction over a *prefix* of the active lanes, so
	// it skips an inactive lane rather than adding an identity element in its
	// place -- specs/002-compute-model.md section 5.2 rule 4, where an
	// exclusive add-scan over active lanes {0, 2, 3} gives lane 3 the sum of
	// lanes 0 and 2.
	OpSubgroupInclusiveAddF32
	OpSubgroupExclusiveAddF32

	// The mask's methods, specs/058-ballot.md §2. Each is an intrinsic in its
	// own right because a kernel writes `t.Ballot(p).Count()` and Count is a
	// call the compiler has to lower -- the alternative is exposing the bits,
	// which 002 §5.2 rejects.
	//
	// **After the subgroup range on purpose**, for the reason the graphics
	// built-ins below give: IsSubgroupRendezvous is a bounds check, and a mask
	// method inside it would be lowered as a suspension that combines nothing.
	// They need no capability of their own -- the Ballot that produced the mask
	// carries it, and a mask cannot exist without one.
	OpMaskCount
	OpMaskBit
	OpMaskLowestSet
	OpMaskCountLower
	OpMaskAny

	// The graphics stage built-ins of specs/032-stage-abi.md. They sit after the
	// subgroup range on purpose: IsSubgroup is a bounds check over that range,
	// and inserting into it would silently make a vertex index a subgroup
	// operation.
	OpVertexIndex
	OpInstanceIndex
	OpFragCoord
	OpFrontFacing

	// OpTexelFetch is an indexed load from a texture at a signed integer
	// coordinate: no filter, no LOD selection, no addressing mode. The
	// subresource is the binding's, not the operation's, so there is no level
	// operand -- specs/045-texture-attachments.md section 2 puts the mip and
	// the layer on the view so that the feedback rule comparing an attachment
	// against a shader-visible binding has one shape to read, and reads it when
	// a pipeline is built rather than when a fragment runs.
	//
	// Out of range is zero, in all four directions. Not undefined: an
	// out-of-range fetch returning whatever is adjacent in memory is the class
	// of defect the sampler refusal exists to avoid.
	OpTexelFetch

	// Cooperative. Recognized so that a kernel using one is rejected by name
	// with a position, rather than failing as an unknown call. See
	// specs/012-kernel-pipeline.md.
	OpBarrier
	// The masked barriers, specs/050-barrier-scopes.md. Separate opcodes
	// rather than an argument on OpBarrier: the scope is fixed at the call
	// site and every backend spells it as a different token, so an opcode is
	// what the emitters already switch on.
	OpBarrierShared
	OpBarrierStorage
)

func (Opcode) IsAtomic

func (o Opcode) IsAtomic() bool

func (Opcode) IsMaskMethod

func (o Opcode) IsMaskMethod() bool

IsMaskMethod reports whether an opcode is one of the ballot mask's methods.

A predicate rather than a range check, because the five sit outside every other subgroup range and a reader asking "is this a subgroup thing" gets a no from all of them. What they are is *derived from* a subgroup value, which the uniformity analysis needs to know. specs/058-ballot.md.

func (Opcode) IsSubgroup

func (o Opcode) IsSubgroup() bool

IsSubgroup reports whether an opcode is any subgroup operation, rendezvous or accessor. It is what capability inference and the uniformity requirement key on.

func (Opcode) IsSubgroupLaneRead

func (o Opcode) IsSubgroupLaneRead() bool

IsSubgroupLaneRead reports whether an opcode reads a value from a lane the second operand names, which is the family whose result is undefined when that lane is inactive.

func (Opcode) IsSubgroupRendezvous

func (o Opcode) IsSubgroupRendezvous() bool

IsAtomic reports whether an opcode is an atomic read-modify-write.

It exists so that access inference does not have to enumerate the set: an atomic added to the table and forgotten here would be a binding that looks untouched, which the graph builder turns into a missing barrier. IsSubgroupRendezvous reports whether an opcode needs every lane's value at the point of the call, and therefore suspends.

The id accessors are excluded: they read this invocation's own position and combine nothing, so making them suspend would cost an epoch for an answer already in hand.

func (Opcode) IsWorkgroupBarrier

func (o Opcode) IsWorkgroupBarrier() bool

IsWorkgroupBarrier reports whether an opcode is a workgroup barrier of any storage-class mask.

A predicate rather than three case labels in each of the four places that ask. The scopes differ in what they make *visible* and agree exactly on execution -- every invocation rendezvouses -- so the cooperative lowering, the uniformity acceptor and the suspension counter want the whole family and would each have to be found and edited when one is added. specs/050.

func (Opcode) String

func (o Opcode) String() string

type Param

type Param struct {
	Index int
	Name  string
	Obj   types.Object
	// contains filtered or unexported fields
}

Param is a kernel or helper parameter, addressed by index because the signature is the binding layout.

func NewParam

func NewParam(p token.Pos, t *Type, i int, name string, obj types.Object) *Param

func (Param) Type

func (v Param) Type() *Type

type Return

type Return struct {

	// Value is a helper's single result, or nil.
	Value Value

	// Values is a graphics stage's results: two for a vertex stage, one for a
	// fragment stage. Separate from Value rather than replacing it, because a
	// helper returns exactly one thing and folding the two would make every
	// consumer index a slice to find it.
	Values []Value
	// contains filtered or unexported fields
}

Return is single-value or empty.

func NewReturn

func NewReturn(p token.Pos, v Value) *Return

type SharedMem

type SharedMem struct {
	Name  string
	Index int
	Type  *Type
}

SharedMem is one workgroup-shared array a kernel's signature declares.

Its extent is fixed at pipeline creation on every backend -- it appears in the GLSL layout qualifier and in Metal's threadgroup attribute -- which is why the authored form is a pointer to a fixed-size array rather than a slice.

type Stage

type Stage uint8

Stage is what a Func is: a helper, or one of the three entry points.

An enum rather than a boolean because a boolean cannot answer "which stage", and every consumer would end up inferring it from the presence of a workgroup extent -- which is a second source of truth for something the directive already said. See specs/032-stage-abi.md section 6.

const (
	// StageHelper is a function a stage calls, not an entry point.
	StageHelper Stage = iota
	StageCompute
	StageVertex
	StageFragment
)

func (Stage) Entry

func (s Stage) Entry() bool

Entry reports whether this stage is an entry point rather than a helper.

func (Stage) Graphics

func (s Stage) Graphics() bool

Graphics reports whether this stage runs in a render pipeline.

The graphics stages have no workgroup, no barrier, no shared memory and no subgroup, so this is what the front end tests before refusing one of those with an error naming the stage -- a compiler guarantee rather than a convention.

func (Stage) String

func (s Stage) String() string

type Stmt

type Stmt interface {
	Node
	// contains filtered or unexported methods
}

Stmt is a statement. Closed, for the same reason Value is.

type Target

type Target struct {
	Name  string
	Index int
	Type  *Type
}

Target is one colour attachment a fragment stage writes.

Index is the field's position in the result struct, and that is the whole mapping: one field per attachment, in declaration order. specs/005-graphics.md records that the predecessor proved this shape on Metal.

type TextureBinding

type TextureBinding struct {
	Name  string
	Index int

	// Param is the parameter position, which a diagnostic names and the
	// generated lowering's signature is built from.
	Param int

	// Reads is whether the body fetches from it. A texture nothing reads is a
	// resource the caller has to bind for no reason, and it is also what tells
	// the graph whether a pass depends on the subresource -- which is the
	// barrier specs/045-texture-attachments.md section 3 draws between a pass
	// that writes an attachment and a pass that fetches it.
	//
	// Inferred from the body, never declared, for the reason [Binding]'s access
	// is.
	Reads bool
}

TextureBinding is one shader-visible texture a signature declares.

Index is the dense position among the function's textures, which is what a backend binds against -- not the parameter position, since the receiver, the varyings, the attributes and any uniforms are interleaved with them in the signature. It is the same rule Attribute follows and for the same reason.

type Type

type Type struct {
	Kind   Kind
	Elem   *Type   // Array and Slice
	Len    int     // Array
	Name   string  // Struct
	Fields []Field // Struct
}

Type is a resolved IR type.

func (*Type) String

func (t *Type) String() string

type Unary

type Unary struct {
	Op token.Token
	X  Value
	// contains filtered or unexported fields
}

Unary is a unary operation.

func NewUnary

func NewUnary(p token.Pos, t *Type, op token.Token, x Value) *Unary

func (Unary) Type

func (v Unary) Type() *Type

type Uniform

type Uniform struct {
	Name  string
	Index int

	// TypeName is the Go type's name, which the generated codec is named after
	// and which a caller writes when constructing a value.
	TypeName string

	// Size is the encoded block size in bytes, rounded up to sixteen.
	Size int

	// Fields is the block's placement, which the generated codec is emitted
	// from.
	Fields []UniformField

	// Reads is whether the body reads any of it. A uniform nothing reads is a
	// value the caller has to supply for no reason.
	Reads bool
}

Uniform is one by-value struct parameter.

It is a separate list from Binding because it is a different resource kind with a different layout rule: a binding is a tightly packed array of one dtype and a uniform is a std140 block whose padding is not the caller's to compute. See specs/001-device-resources.md section 3.3.

type UniformField

type UniformField struct {
	Name   string
	Offset int

	// Kind is "scalar", "vector", "array", "matrix", or "struct".
	Kind string

	// Scalar is the Go spelling of the element type.
	Scalar string

	// Len is an array's length, a vector's component count, or a matrix's
	// column count.
	Len int

	// Stride is the byte distance between elements of an array or columns of a
	// matrix, which std140 rounds up to sixteen.
	Stride int
}

UniformField is one member of a uniform block, placed.

It carries the offset rather than a way to compute one, because the offset is the whole point: std140's padding is not Go's, and a generated encoder that recomputed it would be a second implementation of the layout.

type Value

type Value interface {
	Node
	Type() *Type
	// contains filtered or unexported methods
}

Value produces a value. The set is closed: the unexported method is what makes adding a case outside this file impossible rather than merely discouraged.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL