Agent skill

Glslang

by LuisaGroup in LuisaGroup/LuisaCompute

glslang SPIR-V Builder API for types, instructions, control flow, and decorations.

Apache-2.0Auto-check passed

Install Glslang

skills CLI
$ npx skills add LuisaGroup/LuisaCompute --skill glslang -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install LuisaGroup/LuisaCompute glslang --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/LuisaGroup/LuisaCompute.git skills-src && mkdir -p .claude/skills && cp -r skills-src/.agents/skills/glslang .claude/skills/glslang && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
glslang
GitHub stars
1.1k
Token cost
~6.4k tokens
SKILL.md length
441 words
Files
1
Skills in repo
12
Repo updated
First seen
Licence
Apache-2.0

At a glance

glslang SPIR-V Builder API for types, instructions, control flow, and decorations.

  • SKILL.md covers SpvBuilder Lifecycle, Module Setup, Types (canonicalized) and Type Queries, plus 16 more sections
  • Instructions only: no scripts, shell commands, URLs or credentials in SKILL.md

What it does

Glslang is an agent skill from LuisaGroup/LuisaCompute. glslang SPIR-V Builder API for types, instructions, control flow, and decorations.

Its SKILL.md is about 6.4k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

The repository describes itself as: High-Performance Rendering Framework on Stream Architectures. The licence is Apache-2.0.

Example prompts

  • “/glslang”

What it can do on your machine

Read from SKILL.md and the folder at commit 0c84a1a. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    No scripts in the folder and no shell commands in SKILL.md (its code samples are cpp).

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Glslang loads about 6.4k tokens when it runs. Until then it costs about 23 tokens; SKILL.md has 441 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~23
When it runs · the whole SKILL.md, loaded when a task matches
~6.4k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from LuisaGroup/LuisaCompute at commit 0c84a1a, republished under its Apache-2.0 licence (© LuisaGroup). 441 words, ~6,372 tokens.

Download SKILL.mdSave it as .claude/skills/glslang/SKILL.md (or your agent's skills folder).
name
glslang
description
glslang SPIR-V Builder API for types, instructions, control flow, and decorations.

glslang SPIR-V Usage

Located in src/ext/glslang/SPIRV. Headers:

cpp
#include "SPIRV/SpvBuilder.h"
#include "SPIRV/spvIR.h"
#include "SPIRV/GlslangToSpv.h"
#include "SPIRV/disassemble.h"

Code snippets follow glslang's own conventions (e.g. camelCase builder methods). LuisaCompute project style rules apply to project code, while src/ext/glslang is third-party code.

SpvBuilder Lifecycle

spv::Builder owns one SPIR-V module. Thread-safe internal IR.

cpp
spv::SpvBuildLogger logger;
spv::Builder builder(spv::Spv_1_5, 0, &logger);
builder.setSource(spv::SourceLanguage::GLSL, 450);
builder.setMemoryModel(spv::AddressingModel::Logical, spv::MemoryModel::GLSL450);
builder.addCapability(spv::Capability::Shader);
// ... build ...
std::vector<unsigned int> spirv;
builder.dump(spirv);

Module Setup

cpp
builder.setSource(spv::SourceLanguage::GLSL, 450);
builder.setEmitSpirvDebugInfo();                    // required before setting debug locations
builder.setDebugMainSourceFile("shader.frag");
builder.setDebugSourceLocation(10, "shader.frag");
builder.addCapability(spv::Capability::Shader);
builder.addExtension("SPV_KHR_ray_tracing");
builder.setMemoryModel(spv::AddressingModel::Logical, spv::MemoryModel::GLSL450);
spv::Id glsl450 = builder.import("GLSL.std.450");

Types (canonicalized)

cpp
spv::Id voidTy   = builder.makeVoidType();
spv::Id boolTy   = builder.makeBoolType();
spv::Id int32Ty  = builder.makeIntType(32);
spv::Id uint32Ty = builder.makeUintType(32);
spv::Id uint64Ty = builder.makeUintType(64);
spv::Id floatTy  = builder.makeFloatType(32);
spv::Id doubleTy = builder.makeFloatType(64);
spv::Id halfTy   = builder.makeFloatType(16);
spv::Id bfloat16 = builder.makeBFloat16Type();
spv::Id float8e5 = builder.makeFloatE5M2Type();
spv::Id float8e4 = builder.makeFloatE4M3Type();

spv::Id vec4Ty   = builder.makeVectorType(floatTy, 4);
spv::Id mat4x4Ty = builder.makeMatrixType(floatTy, 4, 4);
spv::Id arrTy    = builder.makeArrayType(floatTy, builder.makeUintConstant(16), 0);
spv::Id runArrTy = builder.makeRuntimeArray(floatTy);

std::vector<spv::Id> members = {floatTy, int32Ty};
// Second argument is member debug info; use {} when no per-member debug data is needed.
spv::Id structTy = builder.makeStructType(members, {}, "MyStruct", false);

spv::Id ptrTy     = builder.makePointer(spv::StorageClass::Function, floatTy);
spv::Id fwdPtrTy  = builder.makeForwardPointer(spv::StorageClass::PhysicalStorageBuffer);
// Resolve a forward pointer to its pointee type once the pointee is known.
spv::Id resolvedPtrTy = builder.makePointerFromForwardPointer(spv::StorageClass::PhysicalStorageBuffer, fwdPtrTy, floatTy);
spv::Id untypedPtr= builder.makeUntypedPointer(spv::StorageClass::StorageBuffer);
spv::Id fnTy      = builder.makeFunctionType(voidTy, {floatTy, int32Ty});

spv::Id imgTy       = builder.makeImageType(floatTy, spv::Dim::Dim2D, false, false, false, 1, spv::ImageFormat::Rgba32f, "texture2D");
spv::Id sampledImgTy= builder.makeSampledImageType(imgTy, "sampler2D");
spv::Id samplerTy   = builder.makeSamplerType("sampler");

spv::Id asTy = builder.makeAccelerationStructureType();
spv::Id rqTy = builder.makeRayQueryType();
spv::Id hoTy = builder.makeHitObjectEXTType();

spv::Id coopMatTy = builder.makeCooperativeMatrixTypeKHR(floatTy, scopeId, rowsId, colsId, useId);
spv::Id coopVecTy = builder.makeCooperativeVectorTypeNV(floatTy, componentsId);
spv::Id tensorTy  = builder.makeTensorTypeARM(floatTy, rankId);

// Generic
std::vector<spv::IdImmediate> ops = {{true, someId}};
spv::Id genericTy = builder.makeGenericType(spv::Op::OpType..., ops);

Type Queries

cpp
spv::Id typeId = builder.getTypeId(resultId);
spv::Op opCode = builder.getOpCode(id);
spv::Op cls    = builder.getTypeClass(typeId);
bool isPtr     = builder.isPointer(id);
bool isScalar  = builder.isScalar(id);
bool isVec     = builder.isVector(id);
bool isMat     = builder.isMatrix(id);
bool isArray   = builder.isArrayType(typeId);
bool isStruct  = builder.isStructType(typeId);
bool isImage   = builder.isImageType(typeId);
bool isSampler = builder.isSamplerType(typeId);
int  width     = builder.getScalarTypeWidth(typeId);
spv::Id scalar = builder.getScalarTypeId(typeId);
spv::Id contained = builder.getContainedTypeId(typeId);     // single
spv::Id contained = builder.getContainedTypeId(typeId, n);  // nth
unsigned cols = builder.getNumColumns(id);
unsigned rows = builder.getNumRows(id);
unsigned comps= builder.getNumComponents(id);

Constants (deduplicated; spec constants not)

cpp
spv::Id t = builder.makeBoolConstant(true), f = builder.makeBoolConstant(false);
spv::Id i32 = builder.makeIntConstant(5), u32 = builder.makeUintConstant(7);
spv::Id i64 = builder.makeInt64Constant(9), u64 = builder.makeUint64Constant(11);
spv::Id i8  = builder.makeInt8Constant(1),  u8  = builder.makeUint8Constant(2);
spv::Id i16 = builder.makeInt16Constant(3), u16 = builder.makeUint16Constant(4);
spv::Id f32 = builder.makeFloatConstant(1.0f), f64 = builder.makeDoubleConstant(2.0);
spv::Id f16 = builder.makeFloat16Constant(3.0f), bf16 = builder.makeBFloat16Constant(4.0f);
spv::Id fp  = builder.makeFpConstant(floatTy, 1.5, false);
spv::Id null= builder.makeNullConstant(structTy);

// Composite
spv::Id vec4 = builder.makeCompositeConstant(vec4Ty, {f32, f32, f32, f32});

// Spec constants
spv::Id specI32 = builder.makeIntConstant(builder.makeIntType(32), 10, true);
spv::Id specVec = builder.makeCompositeConstant(vec4Ty, {f32, f32, f32, f32}, true);

Variables

cpp
spv::Id global = builder.createVariable(spv::Decoration::NoPrecision, spv::StorageClass::Private, floatTy, "g", builder.makeFloatConstant(0.0f));
spv::Id local  = builder.createVariable(spv::Decoration::NoPrecision, spv::StorageClass::Function, floatTy, "l");
spv::Id untyped= builder.createUntypedVariable(spv::Decoration::NoPrecision, spv::StorageClass::StorageBuffer, "u", dataTypeId, initId);
spv::Id undef  = builder.createUndefined(floatTy);

Functions

cpp
// Entry point
spv::Function* entry = builder.makeEntryPoint("main");
builder.addEntryPoint(spv::ExecutionModel::Fragment, entry, "main");
builder.addExecutionMode(entry, spv::ExecutionMode::OriginUpperLeft);

// Regular function
spv::Block* entryBlock = nullptr;
spv::Function* func = builder.makeFunctionEntry(
    spv::Decoration::NoPrecision, floatTy, "myFunc", spv::LinkageType::Max,
    {floatTy, int32Ty},
    {{spv::Decoration::NoPrecision}, {spv::Decoration::NoPrecision}},
    &entryBlock);

builder.enterFunction(func);
builder.setBuildPoint(entryBlock);
spv::Id p0 = func->getParamId(0);
spv::Id p1 = func->getParamId(1);
builder.makeReturn(false, resultId);  // or makeReturn(false) for void
builder.leaveFunction();

Control Flow

If-Then-Else
cpp
spv::Builder::If ifBuilder(cond, spv::SelectionControlMask::MaskNone, builder);
// then block
ifBuilder.makeBeginElse();
// else block
ifBuilder.makeEndIf();
// merge block
Switch
cpp
std::vector<int> caseValues = {0, 1}, valueToSegment = {0, 1};
int defaultSegment = 2, numSegments = 3;
std::vector<Block*> segmentBB;
builder.makeSwitch(selectorId, spv::SelectionControlMask::MaskNone, numSegments, caseValues, valueToSegment, defaultSegment, segmentBB);
builder.nextSwitchSegment(segmentBB, 0); /* ... */ builder.addSwitchBreak(false);
builder.nextSwitchSegment(segmentBB, 1); /* ... */ builder.addSwitchBreak(false);
builder.nextSwitchSegment(segmentBB, 2); /* ... */ builder.addSwitchBreak(false);
builder.endSwitch(segmentBB);
Loops
cpp
spv::Builder::LoopBlocks& loop = builder.makeNewLoop();
builder.setBuildPoint(&loop.head);
builder.createLoopMerge(&loop.merge, &loop.continue_target, spv::LoopControlMask::MaskNone, {});
builder.createConditionalBranch(cond, &loop.body, &loop.merge);
builder.setBuildPoint(&loop.body);
// loop body
builder.createLoopContinue();
builder.setBuildPoint(&loop.continue_target);
// loop increment (optional)
builder.createBranch(false, &loop.head);
builder.setBuildPoint(&loop.merge);
builder.closeLoop();
// break: builder.createLoopExit();  continue: builder.createLoopContinue();

Arithmetic & Logic

cpp
spv::Id neg  = builder.createUnaryOp(spv::Op::OpSNegate, int32Ty, val);
spv::Id notb = builder.createUnaryOp(spv::Op::OpLogicalNot, boolTy, bval);
spv::Id add  = builder.createBinOp(spv::Op::OpFAdd, floatTy, a, b);
spv::Id sub  = builder.createBinOp(spv::Op::OpISub, int32Ty, a, b);
spv::Id mul  = builder.createBinOp(spv::Op::OpIMul, int32Ty, a, b);
spv::Id div  = builder.createBinOp(spv::Op::OpFDiv, floatTy, a, b);
spv::Id and_ = builder.createBinOp(spv::Op::OpBitwiseAnd, uint32Ty, a, b);

// ExtInst (ternary)
spv::Id fma = builder.createOp(spv::Op::OpExtInst, floatTy, {glsl450, GLSLstd450Fma, a, b, c});

// Generic n-ary
spv::Id r = builder.createOp(spv::Op::OpVectorTimesMatrix, vec4Ty, {a, b, c});

// Mixed ID/immediates
std::vector<spv::IdImmediate> mixed = {{true, idOp}, {false, (unsigned)spv::MemoryAccessMask::Aligned}};
spv::Id r = builder.createOp(spv::Op::Op..., typeId, mixed);

// SpecConstantOp
spv::Id specAdd = builder.createSpecConstantOp(spv::Op::OpIAdd, int32Ty, {specA, specB}, {});

Memory Instructions

cpp
spv::Id loaded = builder.createLoad(ptrId, spv::Decoration::NoPrecision);
builder.createStore(valueId, ptrId);
builder.createStore(valueId, ptrId, spv::MemoryAccessMask::NonUniformPointerEXT, spv::Scope::Device, 4);

// Access chain
std::vector<spv::Id> indexes = {builder.makeUintConstant(0), builder.makeUintConstant(2)};
spv::Id chain = builder.createAccessChain(spv::StorageClass::Function, basePtr, indexes);

// Composite
spv::Id elem  = builder.createCompositeExtract(composite, elemType, 2);
spv::Id elem  = builder.createCompositeExtract(composite, elemType, std::vector<unsigned>{0, 1});
spv::Id ins   = builder.createCompositeInsert(newVal, composite, compositeType, 0);
spv::Id dynEl = builder.createVectorExtractDynamic(vec, elemType, indexId);
spv::Id dynVec= builder.createVectorInsertDynamic(vec, vecType, newElem, indexId);
spv::Id comp  = builder.createCompositeConstruct(vec4Ty, {a, b, c, d});

spv::Id vec4 = builder.createConstructor(spv::Decoration::NoPrecision, {scalarId}, vec4Ty);
spv::Id mat  = builder.createMatrixConstructor(spv::Decoration::NoPrecision, srcs, mat4x4Ty);

// Swizzle
spv::Id swz = builder.createRvalueSwizzle(spv::Decoration::NoPrecision, vec4Ty, vec, {2, 1, 0, 3});
spv::Id lswz= builder.createLvalueSwizzle(vec4Ty, target, source, {2, 1, 0, 3});

// Scalar promotion (in-place)
builder.promoteScalar(spv::Decoration::NoPrecision, left, right);
spv::Id smeared = builder.smearScalar(spv::Decoration::NoPrecision, scalarId, vec4Ty);

Access Chain Helper

Builder maintains one active access chain for l-value/r-value tracking:

cpp
builder.clearAccessChain();
builder.setAccessChainLValue(ptrId);    // base is pointer
builder.setAccessChainRValue(valueId);  // base is r-value
builder.accessChainPush(indexId, coherentFlags, alignment);
builder.accessChainPushSwizzle(channels, preSwizzleBaseType, coherentFlags, alignment);
builder.accessChainPushComponent(componentId, preSwizzleBaseType, coherentFlags, alignment);

spv::Id result = builder.accessChainLoad(precision, lvalNonUniform, rvalNonUniform, resultType, memAccess, scope, n);
builder.accessChainStore(valueId, spv::Decoration::NonUniform,
                         spv::MemoryAccessMask::MaskNone, spv::Scope::Max, 0);
spv::Id lval = builder.accessChainGetLValue();
spv::Id inferred = builder.accessChainGetInferredType();
bool canBeLvalue = builder.isSpvLvalue();  // false for multi-component swizzles like .yx

// Save/restore
spv::Builder::AccessChain saved = builder.getAccessChain();
builder.setAccessChain(saved);

Texture Operations

cpp
spv::Builder::TextureParameters params = {};
params.sampler = sampledImageId;
params.coords = coordsId;
params.lod = lodId;  // etc: bias, Dref, offset, gradX, gradY, component, sample, lodClamp, ...
// nonprivate, volatil, nontemporal = false

spv::Id tex = builder.createTextureCall(precision, resultType,
    false/*sparse*/, false/*fetch*/, false/*proj*/, false/*gather*/, false/*noImplicit*/,
    params, spv::ImageOperandsMask::MaskNone);

Decorations & Names

cpp
builder.addName(id, "myVar");
builder.addMemberName(structTy, 0, "field0");
builder.addDecoration(id, spv::Decoration::Location, 0);
builder.addDecoration(id, spv::Decoration::Binding, 2);
builder.addDecoration(id, spv::Decoration::DescriptorSet, 0);
builder.addDecoration(id, spv::Decoration::NoContraction);
builder.addDecoration(id, spv::Decoration::RelaxedPrecision);
builder.addDecoration(id, spv::Decoration::BuiltIn, (int)spv::BuiltIn::Position);
builder.addMemberDecoration(structTy, 0, spv::Decoration::Offset, 0);
builder.addMemberDecoration(structTy, 1, spv::Decoration::Offset, 16);
builder.addDecoration(id, spv::Decoration::WorkgroupSize, std::vector<unsigned>{64, 1, 1});
builder.addDecorationId(id, spv::Decoration::ArrayStrideIdEXT, strideId);
builder.addLinkageDecoration(id, "myFunc", spv::LinkageType::Export);

Barriers

cpp
builder.createControlBarrier(spv::Scope::Workgroup, spv::Scope::Device,
    spv::MemorySemanticsMask::UniformMemory | spv::MemorySemanticsMask::WorkgroupMemory);
builder.createMemoryBarrier(spv::Scope::Device, spv::MemorySemanticsMask::ImageMemory);

Debug Info

SPIR-V Standard (OpLine/OpSource)
cpp
builder.setEmitSpirvDebugInfo();  // enables OpLine/OpSource tracking
builder.setDebugMainSourceFile("shader.glsl");
builder.setDebugSourceLocation(42, "shader.glsl");
builder.setSourceText(sourceText);
NonSemantic Shader Debug Info
cpp
builder.setEmitNonSemanticShaderDebugInfo(true);  // also enables OpLine-style tracking
spv::Id debugType = builder.getDebugType(spirvTypeId);
builder.enterLexicalBlock(line, column);
builder.leaveLexicalBlock();
builder.setupFunctionDebugInfo(func, "myFunc", paramTypes, paramNames);
spv::Id dbgGlobal = builder.createDebugGlobalVariable(debugType, "globalVar", varId);
spv::Id dbgLocal  = builder.createDebugLocalVariable(debugType, "localVar", argNumber);
spv::Id dbgDecl   = builder.makeDebugDeclare(dbgLocal, ptrId);
spv::Id dbgVal    = builder.makeDebugValue(dbgLocal, valueId);

Function Calls & Builtins

cpp
spv::Id result = builder.createFunctionCall(calleeFunc, {arg0, arg1, arg2});
spv::Id sqrtVal = builder.createBuiltinCall(floatTy, glsl450, GLSLstd450Sqrt, {val});

Post-Processing & Serialization

cpp
builder.postProcess(false);       // prune + caps/extensions
builder.postProcessCFG();         // prune unreachable
builder.postProcessFeatures();    // add caps/extensions from instructions
builder.postProcessSamplers();    // move OpSampledImage near users

std::vector<unsigned int> spirv;
builder.dump(spirv);
spv::Disassemble(std::cout, spirv);
glslang::OutputSpvBin(spirv, "out.spv");
glslang::OutputSpvHex(spirv, "out.h", "g_spv");

Both postProcessCFG() and Function::dump() traverse physical blocks with inReadableOrder(), which assumes structured merge roles already nest. If an outer selection merge is also an inner arm and then branches to the inner merge, the physical graph exits the inner construct and re-enters it. The traversal can initially mask that invalid topology by classifying the inner merge as dead, replacing live code with OpUnreachable, and serializing it before its dominator. Fix the producer's physical control-flow plan: preserve the payload blocks but rotate the adjacent merge declarations so the inner merge physically precedes the outer merge. Do not patch serialization order or disable post-processing/validation around an invalid graph.

OpSwitch case literals are sized by the selector's OpTypeInt, not by the generated operand-table class alone. A selector up to 32 bits uses one literal word; a 64-bit selector uses two low-word-first literal words followed by one target label ID. Disassemblers and binary walkers must resolve the selector type and consume ceil(bit_width / 32) words per case before reading the label. Never infer case boundaries by alternating one literal word and one ID.

Show full SKILL.md (170 more words)Show less

Treat disassembly input as untrusted. Validate each instruction-local word count before reading operands: reject zero, undersized, or module-truncated instructions. When resolving an OpSwitch selector, also validate the mapped defining instruction bounds and result ID; accept OpTypeInt only with its exact four-word layout and a width of 8, 16, 32, or 64. Validate a directly visited OpTypeInt before reading its width operand. The disassembler's fatal path exits the process, so malformed-input regressions must run it in a child process and assert the deterministic nonzero exit.

IR Classes (spvIR.h)

cpp
spv::Instruction* inst = new spv::Instruction(resultId, typeId, spv::Op::OpIAdd);
inst->addIdOperand(opA);
inst->addIdOperand(opB);

spv::Block* block = new spv::Block(blockId, *function);
block->addInstruction(std::unique_ptr<spv::Instruction>(inst));
block->addLocalVariable(std::unique_ptr<spv::Instruction>(varInst));
bool terminated = block->isTerminated();

spv::Function* func = new spv::Function(funcId, retType, funcType, firstParamId, linkage, name, module);
func->addBlock(block);
func->setReturnPrecision(spv::Decoration::RelaxedPrecision);
func->addParamPrecision(0, spv::Decoration::RelaxedPrecision);

spv::Module module;
module.addFunction(func);
module.mapInstruction(inst);
spv::Instruction* found = module.getInstruction(id);
spv::Id typeId = module.getTypeId(resultId);

Key Types

TypePurpose
spv::BuilderSPIR-V module construction
spv::InstructionSingle SPIR-V instruction
spv::BlockBasic block
spv::FunctionSPIR-V function
spv::ModuleModule root, ID→instruction map
spv::Builder::IfStructured if-then-else helper
spv::Builder::LoopBlocksStructured loop blocks
spv::Builder::AccessChainL-value/R-value access chain
spv::Builder::TextureParametersTexture op parameters
spv::IdImmediateOperand: ID or immediate
glslang::SpvOptionsGlslangToSpv options

GlslangToSpv Patterns

From TGlslangToSpvTraverser (src/ext/glslang/SPIRV/GlslangToSpv.cpp). Common pattern: clear access chain → traverse → load/store → set R-value.

visitSymbol
cpp
builder.clearAccessChain();
// Treat spec constants, r-value parameters, and non-pointer/untyped values as r-values.
if (isRValue || rValueParameters.count(symbolId) ||
    (!builder.isPointerType(builder.getTypeId(id)) && !builder.isUntypedPointer(id)))
    builder.setAccessChainRValue(id);
else
    builder.setAccessChainLValue(id);

spv::StorageClass sc = builder.getStorageClass(id);
if (builder.isGlobalVariable(id))
    iOSet.insert(id);

builder.addExtension("SPV_GOOGLE_hlsl_functionality1");
builder.addDecorationId(id, spv::Decoration::HlslCounterBufferGOOGLE, counterId);
visitBinary (Assignment)
cpp
builder.clearAccessChain(); node->getLeft()->traverse(this);
auto lValue = builder.getAccessChain();
builder.clearAccessChain(); node->getRight()->traverse(this);
spv::Id rValue = accessChainLoad(node->getRight()->getType());
builder.setAccessChain(lValue);
multiTypeStore(node->getLeft()->getType(), rValue);
builder.clearAccessChain(); builder.setAccessChainRValue(rValue);
visitBinary (Array/Vector Index)
cpp
// zero-extend narrow uint indexes to 32-bit
if (builder.isUintType(indexType) && builder.getScalarTypeWidth(indexType) < 32)
    index = builder.createUnaryOp(spv::Op::OpUConvert, builder.makeUintType(32), index);
builder.accessChainPush(index, coherentFlags, alignment);
visitBinary (Swizzle)
cpp
builder.accessChainPushSwizzle(swizzle, convertGlslangToSpvType(node->getLeft()->getType()),
                               coherentFlags, alignment);
visitUnary (Inc/Dec)
cpp
spv::Id operand = builder.accessChainGetLValue();
spv::Id one = builder.makeIntConstant(1);
spv::Id result = builder.createBinOp(op, type, operand, one);
builder.accessChainStore(result, ...);
builder.clearAccessChain(); builder.setAccessChainRValue(result);
visitUnary (Builtin / NoResult / ArrayLength)
cpp
// Builtin
spv::Id result = builder.createBuiltinCall(resultType(), glsl450, opcode, {operand});
// No-result
builder.createNoResultOp(spv::Op::OpKill);
builder.createNoResultOp(spv::Op::OpTerminateInvocation);
builder.createNoResultOp(spv::Op::OpDemoteToHelperInvocationEXT);
builder.createNoResultOp(spv::Op::OpAssumeTrueKHR, operand);
// Array length
spv::Id len = builder.createArrayLength(builder.accessChainGetLValue(), member, bits);
len = builder.createUnaryOp(spv::Op::OpBitcast, builder.makeIntType(bits), len);
// Cooperative matrix/vector
spv::Id lenKHR = builder.createCooperativeMatrixLengthKHR(typeId);
spv::Id lenNV  = builder.createCooperativeMatrixLengthNV(typeId);
spv::Id lenVec = builder.getCooperativeVectorNumComponents(typeId);
// Tensor
spv::Id layout = builder.createOp(spv::Op::OpCreateTensorLayoutNV, resultType(), {});
spv::Id view   = builder.createOp(spv::Op::OpCreateTensorViewNV, resultType(), {});
visitAggregate
cpp
// Function entry/leave
builder.setBuildPoint(shaderEntry->getLastBlock());
builder.enterFunction(shaderEntry); /* body */ builder.leaveFunction();
// Function call
spv::Id result = builder.createFunctionCall(callee, arguments);
// Constructors
spv::Id c = builder.createConstructor(precision, arguments, resultType());
spv::Id m = builder.createMatrixConstructor(precision, arguments, resultType());
// Builtin
spv::Id r = builder.createBuiltinCall(resultType(), extInst, opcode, arguments);
// Texture
spv::Builder::TextureParameters params = {sampledImageId, coordsId, /*...*/};
spv::Id tex = builder.createTextureCall(precision, resultType(), sparse, fetch, proj, gather, noImplicit, params, mask);
// Sampled image
spv::Id sampled = builder.createOp(spv::Op::OpSampledImage, resultType(), {imageId, samplerId});
// Cooperative matrix conversion
spv::Id coop = builder.createCooperativeMatrixConversion(resultType(), arguments[0]);
// Variable
spv::Id var = builder.createVariable(precision, spv::StorageClass::Function, type, name, init);
// Load/store
spv::Id loaded = builder.createLoad(ptrId, precision);
builder.createStore(valueId, ptrId);
// Debug scopes
builder.enterLexicalBlock(loc.line, loc.column); /* body */ builder.leaveLexicalBlock();
visitSelection
cpp
// Scalar ternary
spv::Id result = builder.createTriOp(spv::Op::OpSelect, resultType, cond, trueVal, falseVal);
// Vector selection: for SPIR-V < 1.4 smear the scalar condition to the vector width;
// for SPIR-V >= 1.4 OpSelect accepts a scalar condition directly.
if (builder.getSpvVersion() < spv::Spv_1_4 && builder.isVector(trueVal)) {
    cond = builder.smearScalar(precision, cond,
                               builder.makeVectorType(builder.makeBoolType(),
                                                      builder.getNumComponents(trueVal)));
}
// If aggregate decorations cause type mismatches, normalize with OpCopyLogical.
if (builder.getTypeId(trueVal) != resultType)
    trueVal = builder.createUnaryOp(spv::Op::OpCopyLogical, resultType, trueVal);
if (builder.getTypeId(falseVal) != resultType)
    falseVal = builder.createUnaryOp(spv::Op::OpCopyLogical, resultType, falseVal);
spv::Id result = builder.createTriOp(spv::Op::OpSelect, resultType, cond, trueVal, falseVal);
visitSwitch
cpp
std::vector<int> caseValues = {0,1,2}, valueToSegment = {0,1,2};
builder.makeSwitch(selectorId, spv::SelectionControlMask::MaskNone, 4, caseValues, valueToSegment, 3, segmentBB);
builder.nextSwitchSegment(segmentBB, 0); /* case 0 */ builder.addSwitchBreak(false);
// ...
builder.endSwitch(segmentBB);
visitLoop
cpp
spv::Builder::LoopBlocks& loop = builder.makeNewLoop();
builder.setBuildPoint(&loop.head);
builder.createLoopMerge(&loop.merge, &loop.continue_target, spv::LoopControlMask::MaskNone, {});
builder.createConditionalBranch(cond, &loop.body, &loop.merge);
builder.setBuildPoint(&loop.body); /* body */ builder.createLoopContinue();
builder.setBuildPoint(&loop.continue_target); /* increment */ builder.createBranch(false, &loop.head);
builder.setBuildPoint(&loop.merge);
builder.closeLoop();
visitBranch
cpp
builder.makeReturn(false, returnValue);   // with value
builder.makeReturn(false);                // void
builder.createLoopExit();                 // break
builder.createLoopContinue();             // continue
builder.makeStatementTerminator(spv::Op::OpKill, "post-discard");
builder.makeStatementTerminator(spv::Op::OpTerminateInvocation, "post-terminate");
builder.createNoResultOp(spv::Op::OpDemoteToHelperInvocationEXT);
builder.makeStatementTerminator(spv::Op::OpTerminateRayKHR, "post-terminate-ray");
builder.makeStatementTerminator(spv::Op::OpIgnoreIntersectionKHR, "post-ignore");
visitConstantUnion
cpp
spv::Id constantId = createSpvConstant(node);
builder.clearAccessChain();
builder.setAccessChainRValue(constantId);
visitVariableDecl
cpp
builder.setDebugSourceLocation(node->getLoc().line, node->getLoc().getFilename());
visitFunctions
cpp
// No direct builder usage; drives traversal of the translation unit.

© LuisaGroup, Apache-2.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in .agents/skills/glslang of LuisaGroup/LuisaCompute.

Open the folder on GitHubat commit 0c84a1a

Compare with similar skills

Glslang next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Glslang compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Glslang this skillLuisaGroup/LuisaCompute1.1k—~6.4kAutomated safety check: PassApache-2.0
Rust Path Typesopeninterpreter/openinterpreter69k2 repos~605Automated safety check: PassApache-2.0
Python Type Safetywshobson/agents40k—~1.4kAutomated safety check: PassMIT
Pyrefly Type Coveragepytorch/pytorch104k—~3kAutomated safety check: PassCustom licence
Typescript Advanced Typesrolling-scopes/rsschool-app10k25 repos~4.2kAutomated safety check: PassMPL-2.0
API Typessupabase/supabase111k—~557Automated safety check: PassApache-2.0

Similar skills

  • Rust Path Types

    openinterpreter/openinterpreter

    Rules for choosing Rust types for filesystem paths in new Codex code, covering protocol types, internal use and model tool arguments.

    69k GitHub starsUsed in 2 repos~605 tokens
    DevelopmentAuto-check passed
  • Python Type Safety

    wshobson/agents

    Python type safety with type hints, generics, protocols, and strict type checking.

    40k GitHub stars~1.4k tokensUpdated 5 days ago
    DevelopmentAuto-check passed
  • Pyrefly Type Coverage

    pytorch/pytorch

    Migrate a file to use stricter Pyrefly type checking with annotations required for all functions, classes, and attributes.

    104k GitHub stars~3k tokensUpdated today
    DevelopmentAuto-check passed
  • Typescript Advanced Types

    rolling-scopes/rsschool-app

    Master TypeScript's advanced type system including generics, conditional types, mapped types, template literals, and utility types for building type-safe applications.

    10k GitHub starsUsed in 25 repos~4.2k tokens
    DevelopmentAuto-check passed
  • API Types

    supabase/supabase

    Official

    Maintain Supabase API types. An agent skill from supabase/supabase.

    111k GitHub stars~557 tokensUpdated today
    Backend & APIsAuto-check passed
  • Walks through the first of six steps for adding a syncable entity to Twenty's server: metadata name, TypeORM entity, flat types and central constants.

    58k GitHub stars~2.8k tokensUpdated today
    DevelopmentAuto-check passed

More from LuisaGroup/LuisaCompute

All 12 skills in this repo
  • Git

    LuisaGroup/LuisaCompute

    Show uncommitted changes and commit history via git. An agent skill from LuisaGroup/LuisaCompute.

    1.1k GitHub stars~544 tokensUpdated today
    Auto-check passed
  • Ast

    LuisaGroup/LuisaCompute

    Manual AST construction with FunctionBuilder for kernels and callables without DSL sugar.

    1.1k GitHub stars~4.2k tokensUpdated today
    Auto-check passed
  • Cmake

    LuisaGroup/LuisaCompute

    CMake build options, custom functions, and backend patterns for LuisaCompute.

    1.1k GitHub stars~2.4k tokensUpdated today
    Auto-check passed
  • Cpp Style

    LuisaGroup/LuisaCompute

    C++ naming, formatting, static analysis, and RTTI rules for LuisaCompute.

    1.1k GitHub stars~1.1k tokensUpdated today
    Auto-check passed
  • Debug

    LuisaGroup/LuisaCompute

    Debug crashes and test failures via stack-traces, host/device logging, and DSL buffer inspection.

    1.1k GitHub stars~2.3k tokensUpdated today
    Auto-check passed
  • Hlsl

    LuisaGroup/LuisaCompute

    HLSL code generation, StringBuilder patterns, builtin headers, and DXIL embedding.

    1.1k GitHub stars~1.6k tokensUpdated today
    Auto-check passed

Questions about Glslang

What does Glslang do?

glslang SPIR-V Builder API for types, instructions, control flow, and decorations. Glslang is an agent skill from LuisaGroup/LuisaCompute. glslang SPIR-V Builder API for types, instructions, control flow, and decorations.

How do I install Glslang in Claude Code?

Run `npx skills add LuisaGroup/LuisaCompute --skill glslang -a claude-code`. Or copy the skill folder (.agents/skills/glslang in LuisaGroup/LuisaCompute) into .claude/skills/glslang in your project. Claude Code loads it when a task matches its description.

How do I install Glslang in Codex?

Run `npx skills add LuisaGroup/LuisaCompute --skill glslang -a codex`. Or copy the skill folder (.agents/skills/glslang in LuisaGroup/LuisaCompute) into .agents/skills/glslang in your project. Codex loads it when a task matches its description.

Can I use Glslang in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add LuisaGroup/LuisaCompute --skill glslang -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/glslang, .gemini/skills/glslang, .github/skills/glslang and .opencode/skills/glslang in your project.

What does Glslang need to run?

SKILL.md names no scripts, command-line tools or credentials: Glslang is instructions for the agent only.

Does Glslang access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Glslang safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Glslang use?

Glslang is published under the Apache-2.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Glslang use?

About 6.4k tokens (SKILL.md is roughly 25k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Glslang?

Skills that share tags, products or a category with Glslang: Rust Path Types (openinterpreter/openinterpreter, 69k stars), Python Type Safety (wshobson/agents, 40k stars), Pyrefly Type Coverage (pytorch/pytorch, 104k stars) and Typescript Advanced Types (rolling-scopes/rsschool-app, 10k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Glslang?

LuisaGroup (a GitHub organization) maintains it in LuisaGroup/LuisaCompute, which has 1,053 GitHub stars. The repository holds 12 skills in this directory. The repository was last updated on October 10, 2026.

Source: LuisaGroup/LuisaCompute on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.