luv

Workshop wiki

instructions.lisp

hal/vulkan/spir-v/instructions.lisp

system luv/spir-v · 109 definitions · on GitHub

A deliberately small SPIR-V assembler for shaders luv can execute today.

Result IDs lead their instruction, which makes the data read naturally:

(%float type-float 32) (%x load %float %pointer) (return)

The instruction classes and enumerant table are explicit subsets of the SPIR-V grammar. Growing this file follows actual shader needs rather than importing the entire registry into the Lisp image.

in-package#:luv.spir-v
define-conditionspir-v-error
error
form:initarg:form:initformnil:readerspir-v-error-form
reason:initarg:reason:readerspir-v-error-reason
details:initarg:details:initformnil:readerspir-v-error-details
:report
lambda
conditionstream
formatstream"Cannot assemble SPIR-V form ~S: ~A~@[ (~S)~]."
spir-v-error-formcondition
spir-v-error-reasoncondition
spir-v-error-detailscondition
eval-when
:compile-toplevel:load-toplevel:execute

One-time migration from the short-lived structure-definition registry. No user-held occurrences existed yet: the old instances were definitions in *INSTRUCTIONS*, so retiring that class binding loses no shader IR.

let
old-class
find-class'instructionnil
when
andold-class
not
typepold-class'closer-mop:standard-class
setf
find-class'instruction
nil
when
boundp'*instructions*
makunbound'*instructions*
dolist
name'
make-instructioncopy-instructioninstruction-pinstruction-opcodeinstruction-resultinstruction-operandsencode-instruction
when
fboundpname
fmakunboundname
defclassinstruction-class
closer-mop:standard-class
opcode:initformnil:accessorinstruction-class-opcode
result-convention:initform:none:accessorinstruction-class-result-convention
lambda-list:initformnil:accessorinstruction-class-lambda-list
operand-specs:initformnil:accessorinstruction-class-operand-specs
defmethodcloser-mop:validate-superclass
superclasscloser-mop:standard-class
declare
ignoreclasssuperclass
t
defclassinstruction
result-id:initarg:result-id:initformnil:readerinstruction-result-id
result-type:initarg:result-type:initformnil:readerinstruction-result-type
defclasstyped-unary-instruction
value:initarg:value
defclasstyped-binary-arithmetic-instruction
left:initarg:left
right:initarg:right
defgenericinstruction-name
instruction-or-class
defgenericinstruction-opcode
instruction-or-class
defgenericinstruction-result-convention
instruction-or-class
defmethodinstruction-name
class-nameclass
defmethodinstruction-opcode
instruction-class-opcodeclass
defmethodinstruction-result-convention
instruction-class-result-conventionclass
eval-when
:compile-toplevel:load-toplevel:execute
defunregistry-key
name
string-upcase
symbol-namename
defuninstruction-operand-specs
namelambda-listtypes
let
rest-position
position'&restlambda-list
cond
rest-position
unless
and
=
+rest-position2
lengthlambda-list
=
1+rest-position
lengthtypes
error"Bad operands for SPIR-V instruction ~S."name
append
subseqtypes0rest-position
list
list:rest
elttypesrest-position
t
unless
=
lengthlambda-list
lengthtypes
error"Bad operands for SPIR-V instruction ~S."name
types
defuninstruction-operand-names
lambda-list
remove'&restlambda-list
defunconfigure-instruction-class
classnamelambda-listopcoderesulttypes
unless
typepopcode'
unsigned-byte16
error"Bad opcode for SPIR-V instruction ~S: ~S."nameopcode
unless
memberresult'
:none:id:typed
error"Bad result convention for SPIR-V instruction ~S: ~S."nameresult
setf
instruction-class-opcodeclass
opcode
instruction-class-result-conventionclass
result
instruction-class-lambda-listclass
lambda-list
instruction-class-operand-specsclass
instruction-operand-specsnamelambda-listtypes
class
defmacrodefine-instruction
namelambda-list&restoptions

Define one instruction class in luv's SPIR-V backend vocabulary.

let
opcodenil
result:none
typesnil
superclasses'
inherited-operands-pnil
dolist
optionoptions
case
firstoption
:opcode
setfopcode
secondoption
:result
setfresult
secondoption
:operands
setftypes
restoption
:superclasses
setfsuperclasses
restoption
:inherited-operands
setfinherited-operands-pt
otherwise
error"Unknown DEFINE-INSTRUCTION option ~S."option
unlessopcode
error"SPIR-V instruction ~S has no opcode."name
let
slots
unlessinherited-operands-p
loopforoperandin
instruction-operand-nameslambda-list
collect`
,operand:initarg,
intern
symbol-nameoperand
:keyword
`
progn
defclass,name,superclasses,slots
eval-when
:load-toplevel:execute
configure-instruction-class
find-class',name
',name',lambda-list,opcode,result',types
',name
defmacrodefine-enumeration
name&bodyentries
`
eval-when
:compile-toplevel:load-toplevel:execute
register-enumeration',name',entries
defmacrodefine-typed-unary-instructions
&bodydefinitions
`
progn,@
loopfor
nameopcode
indefinitionscollect`
define-instruction,name
value
:opcode,opcode
:result:typed
:operands:id
:inherited-operands
defmacrodefine-typed-binary-instructions
&bodydefinitions
`
progn,@
loopfor
nameopcode
indefinitionscollect`
define-instruction,name
leftright
:opcode,opcode
:result:typed
:operands:id:id
:inherited-operands

Like SBCL's backend instruction files, this is executable treaty text: definitions create their own IR classes, and repetitive instruction families get a local definer instead of being expanded by hand.

define-instructionextension
name
:opcode10
:operands:string
define-instructionext-inst-import
name
:opcode11
:result:id
:operands:string

The extended instruction number is a literal, so lowering may write the readable (enum glsl-std-450 f-clamp) form rather than a bare integer.

define-instructionext-inst
setinstruction&restoperands
:opcode12
:result:typed
:operands:id:literal:id
define-instructionentry-point
execution-modelentry-pointname&restinterface
:opcode15
:operands:id:string:id
define-instructionexecution-mode
entry-pointmode&restliterals
:opcode16
:operands:id:literal
define-instructiondecorate
targetdecoration&restliterals
:opcode71
:operands:id:literal
define-instructionmember-decorate
targetmemberdecoration&restliterals
:opcode72
:operands:id:literal:literal
define-instructiontype-void
:opcode19
:result:id
define-instructiontype-bool
:opcode20
:result:id
define-instructiontype-int
widthsignedness
:opcode21
:result:id
:operands:literal:literal
define-instructiontype-float
:opcode22
:result:id
:operands:literal
define-instructiontype-vector
componentcount
:opcode23
:result:id
:operands:id:literal
define-instructiontype-image
sampled-typedimdeptharrayedmultisampledsampledformat
:opcode25
:result:id
:operands:id
:enumdim
:literal:literal:literal:literal
define-instructiontype-sampled-image
image-type
:opcode27
:result:id
:operands:id
define-instructiontype-array
element-typelength
:opcode28
:result:id
:operands:id:id
define-instructiontype-runtime-array
element-type
:opcode29
:result:id
:operands:id
define-instructiontype-struct
&restmember-types
:opcode30
:result:id
:operands:id
define-instructiontype-function
return-type&restparameter-types
:opcode33
:result:id
:operands:id:id
define-instructionconstant
value
:opcode43
:result:typed
:operands:literal
define-instructionconstant-composite
&restconstituents
:opcode44
:result:typed
:operands:id
define-instructionvariable
:opcode59
:result:typed
:operands
define-instructionstore
pointerobject
:opcode62
:operands:id:id
define-instructionaccess-chain
base&restindexes
:opcode65
:result:typed
:operands:id:id
define-typed-unary-instructions
load61
convert-f-to-u109
convert-u-to-f112
u-convert113
f-negate127
logical-not168
d-pdx207
d-pdy208
define-instructionvector-shuffle
leftright&restcomponents
:opcode79
:result:typed
:operands:id:id:literal
define-instructioncomposite-construct
&restconstituents
:opcode80
:result:typed
:operands:id
define-instructioncomposite-extract
composite&restindices
:opcode81
:result:typed
:operands:id:literal
define-instructionsampled-image
imagesampler
:opcode86
:result:typed
:operands:id:id
define-instructionimage-sample-implicit-lod
sampled-imagecoordinate
:opcode87
:result:typed
:operands:id:id
define-instructionimage-sample-explicit-lod
sampled-imagecoordinateimage-operands&restoperands
:opcode88
:result:typed
:operands:id:id:id
define-instructionimage-sample-dref-implicit-lod
sampled-imagecoordinatedepth-reference
:opcode89
:result:typed
:operands:id:id:id
define-instructionimage-fetch
imagecoordinate
:opcode95
:result:typed
:operands:id:id
define-instructionimage-write
imagecoordinatetexel
:opcode99
:operands:id:id:id
define-instructionselect
conditiontrue-objectfalse-object
:opcode169
:result:typed
:operands:id:id:id
define-typed-binary-instructions
i-add128
f-add129
i-sub130
f-sub131
i-mul132
f-mul133
u-div134
f-div136
u-mod137
dot148
shift-right-logical194
shift-left-logical196
bitwise-and199
define-typed-binary-instructions
logical-and167
i-equal170
u-greater-than172
u-greater-than-equal174
u-less-than176
u-less-than-equal178
f-ord-equal180
f-ord-less-than184
f-ord-greater-than186
f-ord-less-than-equal188
f-ord-greater-than-equal190
define-instructionvector-times-scalar
vectorscalar
:opcode142
:result:typed
:operands:id:id
define-instructionfunction
controlfunction-type
:opcode54
:result:typed
:operands:id
define-instructionphi
&restpairs
:opcode245
:result:typed
:operands:id
define-instructionloop-merge
merge-blockcontinue-targetloop-control
:opcode246
:operands:id:id
define-instructionlabel
:opcode248
:result:id
define-instructionbranch
target
:opcode249
:operands:id
define-instructionbranch-conditional
conditiontrue-labelfalse-label
:opcode250
:operands:id:id:id
define-instructionemit-mesh-tasks-ext
group-count-xgroup-count-ygroup-count-z&restpayload
:opcode5294
:operands:id:id:id:id
define-instructionset-mesh-outputs-ext
vertex-countprimitive-count
:opcode5295
:operands:id:id
eval-when
:compile-toplevel:load-toplevel:execute
defvar*enumerants*nil
unless
hash-table-p*enumerants*
setf*enumerants*
make-hash-table:test#'equal
defunregister-enumeration
nameentries
let
values
make-hash-table:test#'equal
dolist
entryentries
destructuring-bind
enumerantvalue
entry
setf
gethash
registry-keyenumerant
values
value
setf
gethash
registry-keyname
*enumerants*
values
define-enumerationcapability
shader1
int6411
mesh-shading-ext5283
define-enumerationexecution-model
vertex0
fragment4
gl-compute5
task-ext5364
mesh-ext5365
define-enumerationexecution-mode
origin-upper-left7
local-size17
output-vertices26
output-points27
output-lines-ext5269
output-primitives-ext5270
output-triangles-ext5298
define-enumerationdecoration
block2
array-stride6
flat14
non-writable24
per-primitive-ext5271
location30
binding33
descriptor-set34
offset35
define-enumerationbuilt-in
num-workgroups24
workgroup-size25
workgroup-id26
local-invocation-id27
global-invocation-id28
local-invocation-index29
primitive-point-indices-ext5294
primitive-line-indices-ext5295
primitive-triangle-indices-ext5296
vertex-index42
instance-index43

GLSL.std.450 extended instruction numbers, spelled with this assembler's word conventions. Entries follow actual shader needs, like the opcodes.

define-enumerationglsl-std-450
f-abs4
f-sign6
sin13
cos14
pow26
exp27
log28
f-min37
f-max40
f-clamp43
smooth-step49
define-enumerationstorage-class
uniform-constant0
input1
uniform2
output3
storage-buffer12
task-payload-workgroup-ext5402
defunsame-name-p
leftright
and
symbolpleft
symbolpright
string-equal
symbol-nameleft
symbol-nameright
defuninstruction-class-for
name
when
symbolpname
let*
direct
find-classnamenil
local-symbol
find-symbol
symbol-namename
find-package'#:luv.spir-v
local
andlocal-symbol
find-classlocal-symbolnil
cond
defunenumerant-value
kindnameform
let
kind-values
and
symbolpkind
gethash
registry-keykind
*enumerants*
multiple-value-bind
valuefound-p
andkind-values
symbolpname
gethash
registry-keyname
kind-values
iffound-pvalue
error'spir-v-error:formform:reason:unknown-enumerant:details
listkindname
defunsplit-instruction-form
form
unless
and
conspform
symbolp
firstform
error'spir-v-error:formform:reason:malformed-instruction
cond
valuesnil
restform
values
firstform
cddrform
t
error'spir-v-error:formform:reason:unknown-instruction
defuninstruction-instance-initargs
classvaluesform
let*
lambda-list
instruction-class-lambda-listclass
rest-position
position'&restlambda-list
required
ifrest-position
subseqlambda-list0rest-position
lambda-list
remaining
copy-listvalues
initargsnil
dolist
namerequired
unlessremaining
error'spir-v-error:formform:reason:missing-operand:detailsname
setfinitargs
nconcinitargs
list
intern
symbol-namename
:keyword
popremaining
ifrest-position
let
name
eltlambda-list
1+rest-position
setfinitargs
nconcinitargs
list
intern
symbol-namename
:keyword
remaining
whenremaining
error'spir-v-error:formform:reason:extra-operands:detailsremaining
initargs
defunparse-instruction
form

Parse one surface form into an inspectable instruction occurrence.

multiple-value-bind
result-idclassoperands
let
result-convention
result-typenil
when
andresult-id
eqresult-convention:none
error'spir-v-error:formform:reason:unexpected-result
when
and
nullresult-id
not
eqresult-convention:none
error'spir-v-error:formform:reason:missing-result
when
eqresult-convention:typed
unlessoperands
error'spir-v-error:formform:reason:missing-result-type
setfresult-type
popoperands
apply#'make-instanceclass:result-idresult-id:result-typeresult-type
defunparse-module
forms

Parse surface forms into a vector of instruction occurrences.

map'vector
lambda
form
if
typepform'instruction
form
forms
defuninstruction-operand-values
let*
class
class-ofinstruction
lambda-list
instruction-class-lambda-listclass
valuesnil
loopwhilelambda-listforname=
poplambda-list
do
if
eqname'&rest
cl:return
nconc
nreversevalues
copy-list
slot-valueinstruction
poplambda-list
push
slot-valueinstructionname
values
finally
cl:return
nreversevalues
defmethodinstruction-form

Return the canonical s-expression surface form for instruction.

let
ecase
:none
list*nameoperands
:id
list*
instruction-result-idinstruction
nameoperands
:typed
list*
instruction-result-idinstruction
name
instruction-result-typeinstruction
operands
defmethodprint-object
print-unreadable-object
instructionstream:typet:identityt
handler-case
unbound-slot
write-string"uninitialized"stream
defuncollect-result-ids
instructions
let
ids
make-hash-table:test#'eq
next-id1
mapnil
lambda
let
result-id
instruction-result-idinstruction
whenresult-id
when
gethashresult-idids
error'spir-v-error:form:reason:duplicate-result:detailsresult-id
setf
gethashresult-idids
next-id
incfnext-id
instructions
valuesidsnext-id
defunid-word
nameidsform
or
and
symbolpname
gethashnameids
error'spir-v-error:formform:reason:unknown-id:detailsname
defunsingle-float-word
value
cffi:with-foreign-object
storage:float
setf
cffi:mem-refstorage:float
coercevalue'single-float
cffi:mem-refstorage:uint32
defunliteral-word
valueform
cond
typepvalue'
unsigned-byte32
value
and
integerpvalue
<=
-
ash131
value-1
ldb
byte320
value
realpvalue
and
conspvalue
same-name-p
firstvalue
'float
=2
lengthvalue
realp
secondvalue
and
conspvalue
same-name-p
firstvalue
'enum
=3
lengthvalue
enumerant-value
secondvalue
thirdvalue
form
t
error'spir-v-error:formform:reason:invalid-literal:detailsvalue
defunstring-words
stringform
unless
stringpstring
error'spir-v-error:formform:reason:expected-string:detailsstring
let*
octets
append
loopforcharacteracrossstringforcode=
char-codecharacter
unless
<=code#xff
do
error'spir-v-error:formform:reason:non-octet-string:detailsstring
collectcode
'
0
word-count
ceiling
lengthoctets
4
loopforword-indexbelowword-countcollect
loopforbyte-indexbelow4forindex=
+
*word-index4
byte-index
when
<index
lengthoctets
sum
ash
nthindexoctets
*byte-index8
defunencode-one-operand
specvalueidsform
cond
eqspec:id
list
id-wordvalueidsform
eqspec:literal
list
literal-wordvalueform
eqspec:string
string-wordsvalueform
and
conspspec
eq:enum
firstspec
list
t
error'spir-v-error:formform:reason:invalid-operand-spec:detailsspec
defunencode-operands
specsvaluesidsform
let
wordsnil
loopwhilespecsforspec=
popspecs
do
if
and
conspspec
eq:rest
firstspec
progn
dolist
valuevalues
setfwords
nconcwords
setfvaluesnilspecsnil
progn
unlessvalues
error'spir-v-error:formform:reason:missing-operand:detailsspec
setfwords
nconcwords
encode-one-operandspec
popvalues
idsform
whenvalues
error'spir-v-error:formform:reason:extra-operands:detailsvalues
words
defmethodencode-instruction
let*
class
class-ofinstruction
prefix
ecaseresult-style
:nonenil
:id
list
id-word
instruction-result-idinstruction
idsform
:typed
list
id-word
instruction-result-typeinstruction
idsform
id-word
instruction-result-idinstruction
idsform
operand-words
encode-operands
copy-list
instruction-class-operand-specsclass
operandsidsform
words
nconcprefixoperand-words
word-count
1+
lengthwords
cons
logior
ashword-count16
words
defunassemble
forms&key
version#x00010000
generator0

Assemble surface forms or instruction occurrences into SPIR-V words.

This assembler intentionally recognizes only the vocabulary declared in instruction classes and *ENUMERANTS*. Result symbols may be referenced before their definitions.

let
instructions
multiple-value-bind
idsbound
collect-result-idsinstructions
let
words
make-array64:element-type'
unsigned-byte32
:adjustablet:fill-pointer0
dolist
word
list#x07230203versiongeneratorbound0
vector-push-extendwordwords
mapnil
lambda
dolist
vector-push-extendwordwords
instructions
words
defunwrite-spir-v
wordspathname

Write SPIR-V words to pathname in its defined little-endian byte order.

with-open-file
streampathname:direction:output:if-exists:supersede:element-type'
unsigned-byte8
loopforwordacrosswordsdo
dotimes
byte4
write-byte
ldb
byte8
*byte8
word
stream
pathname