nir/spirv: Update to the latest revision
authorJason Ekstrand <jason.ekstrand@intel.com>
Mon, 31 Aug 2015 19:48:04 +0000 (12:48 -0700)
committerJason Ekstrand <jason.ekstrand@intel.com>
Tue, 1 Sep 2015 00:05:23 +0000 (17:05 -0700)
src/glsl/nir/nir_spirv.h
src/glsl/nir/spirv.h
src/glsl/nir/spirv_glsl450_to_nir.c
src/glsl/nir/spirv_to_nir.c
src/glsl/nir/spirv_to_nir_private.h

index 5f4140db3d9b481b676bf397e95dda914c25b1a6..1f09174ad7f44c68be493744db34b2c55cfed012 100644 (file)
 
 #include "nir.h"
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 nir_shader *spirv_to_nir(const uint32_t *words, size_t word_count,
                          gl_shader_stage stage,
                          const nir_shader_compiler_options *options);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _NIR_SPIRV_H_ */
index da717ecd34280b85c15c47b5d52aad14ca2374b5..d289c687c765c78764512de4b8dc24a947cbda49 100644 (file)
@@ -1,5 +1,5 @@
 /*
-** Copyright (c) 2015 The Khronos Group Inc.
+** Copyright (c) 2014-2015 The Khronos Group Inc.
 **
 ** Permission is hereby granted, free of charge, to any person obtaining a copy
 ** of this software and/or associated documentation files (the "Materials"),
 */
 
 /*
-** Specification revision 30.
-** Enumeration tokens for SPIR-V, in three styles: C, C++, generic.
-** - C++ will have the tokens in the "spv" name space, with no prefix.
-** - C will have tokens with as "Spv" prefix.
+** Specification revision 31.
+** Enumeration tokens for SPIR-V, in various styles:
+**   C, C++, C++11, JSON, Lua, Python
+**
+** - C will have tokens with a "Spv" prefix, e.g.: SpvSourceLanguageGLSL
+** - C++ will have tokens in the "spv" name space, e.g.: spv::SourceLanguageGLSL
+** - C++11 will use enum classes in the spv namespace, e.g.: spv::SourceLanguage::GLSL
+** - Lua will use tables, e.g.: spv.SourceLanguage.GLSL
+** - Python will use dictionaries, e.g.: spv['SourceLanguage']['GLSL']
 **
 ** Some tokens act like mask values, which can be OR'd together,
 ** while others are mutually exclusive.  The mask-like ones have
 #ifndef spirv_H
 #define spirv_H
 
-#ifdef __cplusplus
-
-namespace spv {
-
-static const int MagicNumber = 0x07230203;
-static const int Version = 99;
-
-typedef unsigned int Id;
-
-static const unsigned int OpCodeMask = 0xFFFF;
-static const unsigned int WordCountShift = 16;
-
-enum SourceLanguage {
-    SourceLanguageUnknown = 0,
-    SourceLanguageESSL = 1,
-    SourceLanguageGLSL = 2,
-    SourceLanguageOpenCL = 3,
-};
-
-enum ExecutionModel {
-    ExecutionModelVertex = 0,
-    ExecutionModelTessellationControl = 1,
-    ExecutionModelTessellationEvaluation = 2,
-    ExecutionModelGeometry = 3,
-    ExecutionModelFragment = 4,
-    ExecutionModelGLCompute = 5,
-    ExecutionModelKernel = 6,
-};
-
-enum AddressingModel {
-    AddressingModelLogical = 0,
-    AddressingModelPhysical32 = 1,
-    AddressingModelPhysical64 = 2,
-};
-
-enum MemoryModel {
-    MemoryModelSimple = 0,
-    MemoryModelGLSL450 = 1,
-    MemoryModelOpenCL12 = 2,
-    MemoryModelOpenCL20 = 3,
-    MemoryModelOpenCL21 = 4,
-};
-
-enum ExecutionMode {
-    ExecutionModeInvocations = 0,
-    ExecutionModeSpacingEqual = 1,
-    ExecutionModeSpacingFractionalEven = 2,
-    ExecutionModeSpacingFractionalOdd = 3,
-    ExecutionModeVertexOrderCw = 4,
-    ExecutionModeVertexOrderCcw = 5,
-    ExecutionModePixelCenterInteger = 6,
-    ExecutionModeOriginUpperLeft = 7,
-    ExecutionModeEarlyFragmentTests = 8,
-    ExecutionModePointMode = 9,
-    ExecutionModeXfb = 10,
-    ExecutionModeDepthReplacing = 11,
-    ExecutionModeDepthAny = 12,
-    ExecutionModeDepthGreater = 13,
-    ExecutionModeDepthLess = 14,
-    ExecutionModeDepthUnchanged = 15,
-    ExecutionModeLocalSize = 16,
-    ExecutionModeLocalSizeHint = 17,
-    ExecutionModeInputPoints = 18,
-    ExecutionModeInputLines = 19,
-    ExecutionModeInputLinesAdjacency = 20,
-    ExecutionModeInputTriangles = 21,
-    ExecutionModeInputTrianglesAdjacency = 22,
-    ExecutionModeInputQuads = 23,
-    ExecutionModeInputIsolines = 24,
-    ExecutionModeOutputVertices = 25,
-    ExecutionModeOutputPoints = 26,
-    ExecutionModeOutputLineStrip = 27,
-    ExecutionModeOutputTriangleStrip = 28,
-    ExecutionModeVecTypeHint = 29,
-    ExecutionModeContractionOff = 30,
-};
-
-enum StorageClass {
-    StorageClassUniformConstant = 0,
-    StorageClassInput = 1,
-    StorageClassUniform = 2,
-    StorageClassOutput = 3,
-    StorageClassWorkgroupLocal = 4,
-    StorageClassWorkgroupGlobal = 5,
-    StorageClassPrivateGlobal = 6,
-    StorageClassFunction = 7,
-    StorageClassGeneric = 8,
-    StorageClassPrivate = 9,
-    StorageClassAtomicCounter = 10,
-};
-
-enum Dim {
-    Dim1D = 0,
-    Dim2D = 1,
-    Dim3D = 2,
-    DimCube = 3,
-    DimRect = 4,
-    DimBuffer = 5,
-};
-
-enum SamplerAddressingMode {
-    SamplerAddressingModeNone = 0,
-    SamplerAddressingModeClampToEdge = 1,
-    SamplerAddressingModeClamp = 2,
-    SamplerAddressingModeRepeat = 3,
-    SamplerAddressingModeRepeatMirrored = 4,
-};
-
-enum SamplerFilterMode {
-    SamplerFilterModeNearest = 0,
-    SamplerFilterModeLinear = 1,
-};
-
-enum FPFastMathModeShift {
-    FPFastMathModeNotNaNShift = 0,
-    FPFastMathModeNotInfShift = 1,
-    FPFastMathModeNSZShift = 2,
-    FPFastMathModeAllowRecipShift = 3,
-    FPFastMathModeFastShift = 4,
-};
-
-enum FPFastMathModeMask {
-    FPFastMathModeMaskNone = 0,
-    FPFastMathModeNotNaNMask = 0x00000001,
-    FPFastMathModeNotInfMask = 0x00000002,
-    FPFastMathModeNSZMask = 0x00000004,
-    FPFastMathModeAllowRecipMask = 0x00000008,
-    FPFastMathModeFastMask = 0x00000010,
-};
-
-enum FPRoundingMode {
-    FPRoundingModeRTE = 0,
-    FPRoundingModeRTZ = 1,
-    FPRoundingModeRTP = 2,
-    FPRoundingModeRTN = 3,
-};
-
-enum LinkageType {
-    LinkageTypeExport = 0,
-    LinkageTypeImport = 1,
-};
-
-enum AccessQualifier {
-    AccessQualifierReadOnly = 0,
-    AccessQualifierWriteOnly = 1,
-    AccessQualifierReadWrite = 2,
-};
-
-enum FunctionParameterAttribute {
-    FunctionParameterAttributeZext = 0,
-    FunctionParameterAttributeSext = 1,
-    FunctionParameterAttributeByVal = 2,
-    FunctionParameterAttributeSret = 3,
-    FunctionParameterAttributeNoAlias = 4,
-    FunctionParameterAttributeNoCapture = 5,
-    FunctionParameterAttributeSVM = 6,
-    FunctionParameterAttributeNoWrite = 7,
-    FunctionParameterAttributeNoReadWrite = 8,
-};
-
-enum Decoration {
-    DecorationPrecisionLow = 0,
-    DecorationPrecisionMedium = 1,
-    DecorationPrecisionHigh = 2,
-    DecorationBlock = 3,
-    DecorationBufferBlock = 4,
-    DecorationRowMajor = 5,
-    DecorationColMajor = 6,
-    DecorationGLSLShared = 7,
-    DecorationGLSLStd140 = 8,
-    DecorationGLSLStd430 = 9,
-    DecorationGLSLPacked = 10,
-    DecorationSmooth = 11,
-    DecorationNoperspective = 12,
-    DecorationFlat = 13,
-    DecorationPatch = 14,
-    DecorationCentroid = 15,
-    DecorationSample = 16,
-    DecorationInvariant = 17,
-    DecorationRestrict = 18,
-    DecorationAliased = 19,
-    DecorationVolatile = 20,
-    DecorationConstant = 21,
-    DecorationCoherent = 22,
-    DecorationNonwritable = 23,
-    DecorationNonreadable = 24,
-    DecorationUniform = 25,
-    DecorationNoStaticUse = 26,
-    DecorationCPacked = 27,
-    DecorationSaturatedConversion = 28,
-    DecorationStream = 29,
-    DecorationLocation = 30,
-    DecorationComponent = 31,
-    DecorationIndex = 32,
-    DecorationBinding = 33,
-    DecorationDescriptorSet = 34,
-    DecorationOffset = 35,
-    DecorationAlignment = 36,
-    DecorationXfbBuffer = 37,
-    DecorationStride = 38,
-    DecorationBuiltIn = 39,
-    DecorationFuncParamAttr = 40,
-    DecorationFPRoundingMode = 41,
-    DecorationFPFastMathMode = 42,
-    DecorationLinkageAttributes = 43,
-    DecorationSpecId = 44,
-};
-
-enum BuiltIn {
-    BuiltInPosition = 0,
-    BuiltInPointSize = 1,
-    BuiltInClipVertex = 2,
-    BuiltInClipDistance = 3,
-    BuiltInCullDistance = 4,
-    BuiltInVertexId = 5,
-    BuiltInInstanceId = 6,
-    BuiltInPrimitiveId = 7,
-    BuiltInInvocationId = 8,
-    BuiltInLayer = 9,
-    BuiltInViewportIndex = 10,
-    BuiltInTessLevelOuter = 11,
-    BuiltInTessLevelInner = 12,
-    BuiltInTessCoord = 13,
-    BuiltInPatchVertices = 14,
-    BuiltInFragCoord = 15,
-    BuiltInPointCoord = 16,
-    BuiltInFrontFacing = 17,
-    BuiltInSampleId = 18,
-    BuiltInSamplePosition = 19,
-    BuiltInSampleMask = 20,
-    BuiltInFragColor = 21,
-    BuiltInFragDepth = 22,
-    BuiltInHelperInvocation = 23,
-    BuiltInNumWorkgroups = 24,
-    BuiltInWorkgroupSize = 25,
-    BuiltInWorkgroupId = 26,
-    BuiltInLocalInvocationId = 27,
-    BuiltInGlobalInvocationId = 28,
-    BuiltInLocalInvocationIndex = 29,
-    BuiltInWorkDim = 30,
-    BuiltInGlobalSize = 31,
-    BuiltInEnqueuedWorkgroupSize = 32,
-    BuiltInGlobalOffset = 33,
-    BuiltInGlobalLinearId = 34,
-    BuiltInWorkgroupLinearId = 35,
-    BuiltInSubgroupSize = 36,
-    BuiltInSubgroupMaxSize = 37,
-    BuiltInNumSubgroups = 38,
-    BuiltInNumEnqueuedSubgroups = 39,
-    BuiltInSubgroupId = 40,
-    BuiltInSubgroupLocalInvocationId = 41,
-};
-
-enum SelectionControlShift {
-    SelectionControlFlattenShift = 0,
-    SelectionControlDontFlattenShift = 1,
-};
-
-enum SelectionControlMask {
-    SelectionControlMaskNone = 0,
-    SelectionControlFlattenMask = 0x00000001,
-    SelectionControlDontFlattenMask = 0x00000002,
-};
-
-enum LoopControlShift {
-    LoopControlUnrollShift = 0,
-    LoopControlDontUnrollShift = 1,
-};
-
-enum LoopControlMask {
-    LoopControlMaskNone = 0,
-    LoopControlUnrollMask = 0x00000001,
-    LoopControlDontUnrollMask = 0x00000002,
-};
-
-enum FunctionControlShift {
-    FunctionControlInlineShift = 0,
-    FunctionControlDontInlineShift = 1,
-    FunctionControlPureShift = 2,
-    FunctionControlConstShift = 3,
-};
-
-enum FunctionControlMask {
-    FunctionControlMaskNone = 0,
-    FunctionControlInlineMask = 0x00000001,
-    FunctionControlDontInlineMask = 0x00000002,
-    FunctionControlPureMask = 0x00000004,
-    FunctionControlConstMask = 0x00000008,
-};
-
-enum MemorySemanticsShift {
-    MemorySemanticsRelaxedShift = 0,
-    MemorySemanticsSequentiallyConsistentShift = 1,
-    MemorySemanticsAcquireShift = 2,
-    MemorySemanticsReleaseShift = 3,
-    MemorySemanticsUniformMemoryShift = 4,
-    MemorySemanticsSubgroupMemoryShift = 5,
-    MemorySemanticsWorkgroupLocalMemoryShift = 6,
-    MemorySemanticsWorkgroupGlobalMemoryShift = 7,
-    MemorySemanticsAtomicCounterMemoryShift = 8,
-    MemorySemanticsImageMemoryShift = 9,
-};
-
-enum MemorySemanticsMask {
-    MemorySemanticsMaskNone = 0,
-    MemorySemanticsRelaxedMask = 0x00000001,
-    MemorySemanticsSequentiallyConsistentMask = 0x00000002,
-    MemorySemanticsAcquireMask = 0x00000004,
-    MemorySemanticsReleaseMask = 0x00000008,
-    MemorySemanticsUniformMemoryMask = 0x00000010,
-    MemorySemanticsSubgroupMemoryMask = 0x00000020,
-    MemorySemanticsWorkgroupLocalMemoryMask = 0x00000040,
-    MemorySemanticsWorkgroupGlobalMemoryMask = 0x00000080,
-    MemorySemanticsAtomicCounterMemoryMask = 0x00000100,
-    MemorySemanticsImageMemoryMask = 0x00000200,
-};
-
-enum MemoryAccessShift {
-    MemoryAccessVolatileShift = 0,
-    MemoryAccessAlignedShift = 1,
-};
-
-enum MemoryAccessMask {
-    MemoryAccessMaskNone = 0,
-    MemoryAccessVolatileMask = 0x00000001,
-    MemoryAccessAlignedMask = 0x00000002,
-};
-
-enum ExecutionScope {
-    ExecutionScopeCrossDevice = 0,
-    ExecutionScopeDevice = 1,
-    ExecutionScopeWorkgroup = 2,
-    ExecutionScopeSubgroup = 3,
-};
-
-enum GroupOperation {
-    GroupOperationReduce = 0,
-    GroupOperationInclusiveScan = 1,
-    GroupOperationExclusiveScan = 2,
-};
-
-enum KernelEnqueueFlags {
-    KernelEnqueueFlagsNoWait = 0,
-    KernelEnqueueFlagsWaitKernel = 1,
-    KernelEnqueueFlagsWaitWorkGroup = 2,
-};
-
-enum KernelProfilingInfoShift {
-    KernelProfilingInfoCmdExecTimeShift = 0,
-};
-
-enum KernelProfilingInfoMask {
-    KernelProfilingInfoMaskNone = 0,
-    KernelProfilingInfoCmdExecTimeMask = 0x00000001,
-};
-
-enum Op {
-    OpNop = 0,
-    OpSource = 1,
-    OpSourceExtension = 2,
-    OpExtension = 3,
-    OpExtInstImport = 4,
-    OpMemoryModel = 5,
-    OpEntryPoint = 6,
-    OpExecutionMode = 7,
-    OpTypeVoid = 8,
-    OpTypeBool = 9,
-    OpTypeInt = 10,
-    OpTypeFloat = 11,
-    OpTypeVector = 12,
-    OpTypeMatrix = 13,
-    OpTypeSampler = 14,
-    OpTypeFilter = 15,
-    OpTypeArray = 16,
-    OpTypeRuntimeArray = 17,
-    OpTypeStruct = 18,
-    OpTypeOpaque = 19,
-    OpTypePointer = 20,
-    OpTypeFunction = 21,
-    OpTypeEvent = 22,
-    OpTypeDeviceEvent = 23,
-    OpTypeReserveId = 24,
-    OpTypeQueue = 25,
-    OpTypePipe = 26,
-    OpConstantTrue = 27,
-    OpConstantFalse = 28,
-    OpConstant = 29,
-    OpConstantComposite = 30,
-    OpConstantSampler = 31,
-    OpConstantNullPointer = 32,
-    OpConstantNullObject = 33,
-    OpSpecConstantTrue = 34,
-    OpSpecConstantFalse = 35,
-    OpSpecConstant = 36,
-    OpSpecConstantComposite = 37,
-    OpVariable = 38,
-    OpVariableArray = 39,
-    OpFunction = 40,
-    OpFunctionParameter = 41,
-    OpFunctionEnd = 42,
-    OpFunctionCall = 43,
-    OpExtInst = 44,
-    OpUndef = 45,
-    OpLoad = 46,
-    OpStore = 47,
-    OpPhi = 48,
-    OpDecorationGroup = 49,
-    OpDecorate = 50,
-    OpMemberDecorate = 51,
-    OpGroupDecorate = 52,
-    OpGroupMemberDecorate = 53,
-    OpName = 54,
-    OpMemberName = 55,
-    OpString = 56,
-    OpLine = 57,
-    OpVectorExtractDynamic = 58,
-    OpVectorInsertDynamic = 59,
-    OpVectorShuffle = 60,
-    OpCompositeConstruct = 61,
-    OpCompositeExtract = 62,
-    OpCompositeInsert = 63,
-    OpCopyObject = 64,
-    OpCopyMemory = 65,
-    OpCopyMemorySized = 66,
-    OpSampler = 67,
-    OpTextureSample = 68,
-    OpTextureSampleDref = 69,
-    OpTextureSampleLod = 70,
-    OpTextureSampleProj = 71,
-    OpTextureSampleGrad = 72,
-    OpTextureSampleOffset = 73,
-    OpTextureSampleProjLod = 74,
-    OpTextureSampleProjGrad = 75,
-    OpTextureSampleLodOffset = 76,
-    OpTextureSampleProjOffset = 77,
-    OpTextureSampleGradOffset = 78,
-    OpTextureSampleProjLodOffset = 79,
-    OpTextureSampleProjGradOffset = 80,
-    OpTextureFetchTexelLod = 81,
-    OpTextureFetchTexelOffset = 82,
-    OpTextureFetchSample = 83,
-    OpTextureFetchTexel = 84,
-    OpTextureGather = 85,
-    OpTextureGatherOffset = 86,
-    OpTextureGatherOffsets = 87,
-    OpTextureQuerySizeLod = 88,
-    OpTextureQuerySize = 89,
-    OpTextureQueryLod = 90,
-    OpTextureQueryLevels = 91,
-    OpTextureQuerySamples = 92,
-    OpAccessChain = 93,
-    OpInBoundsAccessChain = 94,
-    OpSNegate = 95,
-    OpFNegate = 96,
-    OpNot = 97,
-    OpAny = 98,
-    OpAll = 99,
-    OpConvertFToU = 100,
-    OpConvertFToS = 101,
-    OpConvertSToF = 102,
-    OpConvertUToF = 103,
-    OpUConvert = 104,
-    OpSConvert = 105,
-    OpFConvert = 106,
-    OpConvertPtrToU = 107,
-    OpConvertUToPtr = 108,
-    OpPtrCastToGeneric = 109,
-    OpGenericCastToPtr = 110,
-    OpBitcast = 111,
-    OpTranspose = 112,
-    OpIsNan = 113,
-    OpIsInf = 114,
-    OpIsFinite = 115,
-    OpIsNormal = 116,
-    OpSignBitSet = 117,
-    OpLessOrGreater = 118,
-    OpOrdered = 119,
-    OpUnordered = 120,
-    OpArrayLength = 121,
-    OpIAdd = 122,
-    OpFAdd = 123,
-    OpISub = 124,
-    OpFSub = 125,
-    OpIMul = 126,
-    OpFMul = 127,
-    OpUDiv = 128,
-    OpSDiv = 129,
-    OpFDiv = 130,
-    OpUMod = 131,
-    OpSRem = 132,
-    OpSMod = 133,
-    OpFRem = 134,
-    OpFMod = 135,
-    OpVectorTimesScalar = 136,
-    OpMatrixTimesScalar = 137,
-    OpVectorTimesMatrix = 138,
-    OpMatrixTimesVector = 139,
-    OpMatrixTimesMatrix = 140,
-    OpOuterProduct = 141,
-    OpDot = 142,
-    OpShiftRightLogical = 143,
-    OpShiftRightArithmetic = 144,
-    OpShiftLeftLogical = 145,
-    OpLogicalOr = 146,
-    OpLogicalXor = 147,
-    OpLogicalAnd = 148,
-    OpBitwiseOr = 149,
-    OpBitwiseXor = 150,
-    OpBitwiseAnd = 151,
-    OpSelect = 152,
-    OpIEqual = 153,
-    OpFOrdEqual = 154,
-    OpFUnordEqual = 155,
-    OpINotEqual = 156,
-    OpFOrdNotEqual = 157,
-    OpFUnordNotEqual = 158,
-    OpULessThan = 159,
-    OpSLessThan = 160,
-    OpFOrdLessThan = 161,
-    OpFUnordLessThan = 162,
-    OpUGreaterThan = 163,
-    OpSGreaterThan = 164,
-    OpFOrdGreaterThan = 165,
-    OpFUnordGreaterThan = 166,
-    OpULessThanEqual = 167,
-    OpSLessThanEqual = 168,
-    OpFOrdLessThanEqual = 169,
-    OpFUnordLessThanEqual = 170,
-    OpUGreaterThanEqual = 171,
-    OpSGreaterThanEqual = 172,
-    OpFOrdGreaterThanEqual = 173,
-    OpFUnordGreaterThanEqual = 174,
-    OpDPdx = 175,
-    OpDPdy = 176,
-    OpFwidth = 177,
-    OpDPdxFine = 178,
-    OpDPdyFine = 179,
-    OpFwidthFine = 180,
-    OpDPdxCoarse = 181,
-    OpDPdyCoarse = 182,
-    OpFwidthCoarse = 183,
-    OpEmitVertex = 184,
-    OpEndPrimitive = 185,
-    OpEmitStreamVertex = 186,
-    OpEndStreamPrimitive = 187,
-    OpControlBarrier = 188,
-    OpMemoryBarrier = 189,
-    OpImagePointer = 190,
-    OpAtomicInit = 191,
-    OpAtomicLoad = 192,
-    OpAtomicStore = 193,
-    OpAtomicExchange = 194,
-    OpAtomicCompareExchange = 195,
-    OpAtomicCompareExchangeWeak = 196,
-    OpAtomicIIncrement = 197,
-    OpAtomicIDecrement = 198,
-    OpAtomicIAdd = 199,
-    OpAtomicISub = 200,
-    OpAtomicUMin = 201,
-    OpAtomicUMax = 202,
-    OpAtomicAnd = 203,
-    OpAtomicOr = 204,
-    OpAtomicXor = 205,
-    OpLoopMerge = 206,
-    OpSelectionMerge = 207,
-    OpLabel = 208,
-    OpBranch = 209,
-    OpBranchConditional = 210,
-    OpSwitch = 211,
-    OpKill = 212,
-    OpReturn = 213,
-    OpReturnValue = 214,
-    OpUnreachable = 215,
-    OpLifetimeStart = 216,
-    OpLifetimeStop = 217,
-    OpCompileFlag = 218,
-    OpAsyncGroupCopy = 219,
-    OpWaitGroupEvents = 220,
-    OpGroupAll = 221,
-    OpGroupAny = 222,
-    OpGroupBroadcast = 223,
-    OpGroupIAdd = 224,
-    OpGroupFAdd = 225,
-    OpGroupFMin = 226,
-    OpGroupUMin = 227,
-    OpGroupSMin = 228,
-    OpGroupFMax = 229,
-    OpGroupUMax = 230,
-    OpGroupSMax = 231,
-    OpGenericCastToPtrExplicit = 232,
-    OpGenericPtrMemSemantics = 233,
-    OpReadPipe = 234,
-    OpWritePipe = 235,
-    OpReservedReadPipe = 236,
-    OpReservedWritePipe = 237,
-    OpReserveReadPipePackets = 238,
-    OpReserveWritePipePackets = 239,
-    OpCommitReadPipe = 240,
-    OpCommitWritePipe = 241,
-    OpIsValidReserveId = 242,
-    OpGetNumPipePackets = 243,
-    OpGetMaxPipePackets = 244,
-    OpGroupReserveReadPipePackets = 245,
-    OpGroupReserveWritePipePackets = 246,
-    OpGroupCommitReadPipe = 247,
-    OpGroupCommitWritePipe = 248,
-    OpEnqueueMarker = 249,
-    OpEnqueueKernel = 250,
-    OpGetKernelNDrangeSubGroupCount = 251,
-    OpGetKernelNDrangeMaxSubGroupSize = 252,
-    OpGetKernelWorkGroupSize = 253,
-    OpGetKernelPreferredWorkGroupSizeMultiple = 254,
-    OpRetainEvent = 255,
-    OpReleaseEvent = 256,
-    OpCreateUserEvent = 257,
-    OpIsValidEvent = 258,
-    OpSetUserEventStatus = 259,
-    OpCaptureEventProfilingInfo = 260,
-    OpGetDefaultQueue = 261,
-    OpBuildNDRange = 262,
-    OpSatConvertSToU = 263,
-    OpSatConvertUToS = 264,
-    OpAtomicIMin = 265,
-    OpAtomicIMax = 266,
-};
-
-};  // end namespace spv
-
-#endif  // #ifdef __cplusplus
-
-
-#ifndef __cplusplus
-
-static const int SpvMagicNumber = 0x07230203;
-static const int SpvVersion = 99;
-
 typedef unsigned int SpvId;
 
-static const unsigned int SpvOpCodeMask = 0xFFFF;
+static const unsigned int SpvMagicNumber = 0x07230203;
+static const unsigned int SpvVersion = 99;
+static const unsigned int SpvRevision = 31;
+static const unsigned int SpvOpCodeMask = 0xffff;
 static const unsigned int SpvWordCountShift = 16;
 
 typedef enum SpvSourceLanguage_ {
@@ -711,9 +83,7 @@ typedef enum SpvAddressingModel_ {
 typedef enum SpvMemoryModel_ {
     SpvMemoryModelSimple = 0,
     SpvMemoryModelGLSL450 = 1,
-    SpvMemoryModelOpenCL12 = 2,
-    SpvMemoryModelOpenCL20 = 3,
-    SpvMemoryModelOpenCL21 = 4,
+    SpvMemoryModelOpenCL = 2,
 } SpvMemoryModel;
 
 typedef enum SpvExecutionMode_ {
@@ -725,29 +95,30 @@ typedef enum SpvExecutionMode_ {
     SpvExecutionModeVertexOrderCcw = 5,
     SpvExecutionModePixelCenterInteger = 6,
     SpvExecutionModeOriginUpperLeft = 7,
-    SpvExecutionModeEarlyFragmentTests = 8,
-    SpvExecutionModePointMode = 9,
-    SpvExecutionModeXfb = 10,
-    SpvExecutionModeDepthReplacing = 11,
-    SpvExecutionModeDepthAny = 12,
-    SpvExecutionModeDepthGreater = 13,
-    SpvExecutionModeDepthLess = 14,
-    SpvExecutionModeDepthUnchanged = 15,
-    SpvExecutionModeLocalSize = 16,
-    SpvExecutionModeLocalSizeHint = 17,
-    SpvExecutionModeInputPoints = 18,
-    SpvExecutionModeInputLines = 19,
-    SpvExecutionModeInputLinesAdjacency = 20,
-    SpvExecutionModeInputTriangles = 21,
-    SpvExecutionModeInputTrianglesAdjacency = 22,
-    SpvExecutionModeInputQuads = 23,
-    SpvExecutionModeInputIsolines = 24,
-    SpvExecutionModeOutputVertices = 25,
-    SpvExecutionModeOutputPoints = 26,
-    SpvExecutionModeOutputLineStrip = 27,
-    SpvExecutionModeOutputTriangleStrip = 28,
-    SpvExecutionModeVecTypeHint = 29,
-    SpvExecutionModeContractionOff = 30,
+    SpvExecutionModeOriginLowerLeft = 8,
+    SpvExecutionModeEarlyFragmentTests = 9,
+    SpvExecutionModePointMode = 10,
+    SpvExecutionModeXfb = 11,
+    SpvExecutionModeDepthReplacing = 12,
+    SpvExecutionModeDepthAny = 13,
+    SpvExecutionModeDepthGreater = 14,
+    SpvExecutionModeDepthLess = 15,
+    SpvExecutionModeDepthUnchanged = 16,
+    SpvExecutionModeLocalSize = 17,
+    SpvExecutionModeLocalSizeHint = 18,
+    SpvExecutionModeInputPoints = 19,
+    SpvExecutionModeInputLines = 20,
+    SpvExecutionModeInputLinesAdjacency = 21,
+    SpvExecutionModeInputTriangles = 22,
+    SpvExecutionModeInputTrianglesAdjacency = 23,
+    SpvExecutionModeInputQuads = 24,
+    SpvExecutionModeInputIsolines = 25,
+    SpvExecutionModeOutputVertices = 26,
+    SpvExecutionModeOutputPoints = 27,
+    SpvExecutionModeOutputLineStrip = 28,
+    SpvExecutionModeOutputTriangleStrip = 29,
+    SpvExecutionModeVecTypeHint = 30,
+    SpvExecutionModeContractionOff = 31,
 } SpvExecutionMode;
 
 typedef enum SpvStorageClass_ {
@@ -760,8 +131,8 @@ typedef enum SpvStorageClass_ {
     SpvStorageClassPrivateGlobal = 6,
     SpvStorageClassFunction = 7,
     SpvStorageClassGeneric = 8,
-    SpvStorageClassPrivate = 9,
     SpvStorageClassAtomicCounter = 10,
+    SpvStorageClassImage = 11,
 } SpvStorageClass;
 
 typedef enum SpvDim_ {
@@ -786,6 +157,111 @@ typedef enum SpvSamplerFilterMode_ {
     SpvSamplerFilterModeLinear = 1,
 } SpvSamplerFilterMode;
 
+typedef enum SpvImageFormat_ {
+    SpvImageFormatUnknown = 0,
+    SpvImageFormatRgba32f = 1,
+    SpvImageFormatRgba16f = 2,
+    SpvImageFormatR32f = 3,
+    SpvImageFormatRgba8 = 4,
+    SpvImageFormatRgba8Snorm = 5,
+    SpvImageFormatRg32f = 6,
+    SpvImageFormatRg16f = 7,
+    SpvImageFormatR11fG11fB10f = 8,
+    SpvImageFormatR16f = 9,
+    SpvImageFormatRgba16 = 10,
+    SpvImageFormatRgb10A2 = 11,
+    SpvImageFormatRg16 = 12,
+    SpvImageFormatRg8 = 13,
+    SpvImageFormatR16 = 14,
+    SpvImageFormatR8 = 15,
+    SpvImageFormatRgba16Snorm = 16,
+    SpvImageFormatRg16Snorm = 17,
+    SpvImageFormatRg8Snorm = 18,
+    SpvImageFormatR16Snorm = 19,
+    SpvImageFormatR8Snorm = 20,
+    SpvImageFormatRgba32i = 21,
+    SpvImageFormatRgba16i = 22,
+    SpvImageFormatRgba8i = 23,
+    SpvImageFormatR32i = 24,
+    SpvImageFormatRg32i = 25,
+    SpvImageFormatRg16i = 26,
+    SpvImageFormatRg8i = 27,
+    SpvImageFormatR16i = 28,
+    SpvImageFormatR8i = 29,
+    SpvImageFormatRgba32ui = 30,
+    SpvImageFormatRgba16ui = 31,
+    SpvImageFormatRgba8ui = 32,
+    SpvImageFormatR32ui = 33,
+    SpvImageFormatRgb10a2ui = 34,
+    SpvImageFormatRg32ui = 35,
+    SpvImageFormatRg16ui = 36,
+    SpvImageFormatRg8ui = 37,
+    SpvImageFormatR16ui = 38,
+    SpvImageFormatR8ui = 39,
+} SpvImageFormat;
+
+typedef enum SpvImageChannelOrder_ {
+    SpvImageChannelOrderR = 0,
+    SpvImageChannelOrderA = 1,
+    SpvImageChannelOrderRG = 2,
+    SpvImageChannelOrderRA = 3,
+    SpvImageChannelOrderRGB = 4,
+    SpvImageChannelOrderRGBA = 5,
+    SpvImageChannelOrderBGRA = 6,
+    SpvImageChannelOrderARGB = 7,
+    SpvImageChannelOrderIntensity = 8,
+    SpvImageChannelOrderLuminance = 9,
+    SpvImageChannelOrderRx = 10,
+    SpvImageChannelOrderRGx = 11,
+    SpvImageChannelOrderRGBx = 12,
+    SpvImageChannelOrderDepth = 13,
+    SpvImageChannelOrderDepthStencil = 14,
+    SpvImageChannelOrdersRGB = 15,
+    SpvImageChannelOrdersRGBx = 16,
+    SpvImageChannelOrdersRGBA = 17,
+    SpvImageChannelOrdersBGRA = 18,
+} SpvImageChannelOrder;
+
+typedef enum SpvImageChannelDataType_ {
+    SpvImageChannelDataTypeSnormInt8 = 0,
+    SpvImageChannelDataTypeSnormInt16 = 1,
+    SpvImageChannelDataTypeUnormInt8 = 2,
+    SpvImageChannelDataTypeUnormInt16 = 3,
+    SpvImageChannelDataTypeUnormShort565 = 4,
+    SpvImageChannelDataTypeUnormShort555 = 5,
+    SpvImageChannelDataTypeUnormInt101010 = 6,
+    SpvImageChannelDataTypeSignedInt8 = 7,
+    SpvImageChannelDataTypeSignedInt16 = 8,
+    SpvImageChannelDataTypeSignedInt32 = 9,
+    SpvImageChannelDataTypeUnsignedInt8 = 10,
+    SpvImageChannelDataTypeUnsignedInt16 = 11,
+    SpvImageChannelDataTypeUnsignedInt32 = 12,
+    SpvImageChannelDataTypeHalfFloat = 13,
+    SpvImageChannelDataTypeFloat = 14,
+    SpvImageChannelDataTypeUnormInt24 = 15,
+} SpvImageChannelDataType;
+
+typedef enum SpvImageOperandsShift_ {
+    SpvImageOperandsBiasShift = 0,
+    SpvImageOperandsLodShift = 1,
+    SpvImageOperandsGradShift = 2,
+    SpvImageOperandsConstOffsetShift = 3,
+    SpvImageOperandsOffsetShift = 4,
+    SpvImageOperandsConstOffsetsShift = 5,
+    SpvImageOperandsSampleShift = 6,
+} SpvImageOperandsShift;
+
+typedef enum SpvImageOperandsMask_ {
+    SpvImageOperandsMaskNone = 0,
+    SpvImageOperandsBiasMask = 0x00000001,
+    SpvImageOperandsLodMask = 0x00000002,
+    SpvImageOperandsGradMask = 0x00000004,
+    SpvImageOperandsConstOffsetMask = 0x00000008,
+    SpvImageOperandsOffsetMask = 0x00000010,
+    SpvImageOperandsConstOffsetsMask = 0x00000020,
+    SpvImageOperandsSampleMask = 0x00000040,
+} SpvImageOperandsMask;
+
 typedef enum SpvFPFastMathModeShift_ {
     SpvFPFastMathModeNotNaNShift = 0,
     SpvFPFastMathModeNotInfShift = 1,
@@ -828,40 +304,39 @@ typedef enum SpvFunctionParameterAttribute_ {
     SpvFunctionParameterAttributeSret = 3,
     SpvFunctionParameterAttributeNoAlias = 4,
     SpvFunctionParameterAttributeNoCapture = 5,
-    SpvFunctionParameterAttributeSVM = 6,
-    SpvFunctionParameterAttributeNoWrite = 7,
-    SpvFunctionParameterAttributeNoReadWrite = 8,
+    SpvFunctionParameterAttributeNoWrite = 6,
+    SpvFunctionParameterAttributeNoReadWrite = 7,
 } SpvFunctionParameterAttribute;
 
 typedef enum SpvDecoration_ {
-    SpvDecorationPrecisionLow = 0,
-    SpvDecorationPrecisionMedium = 1,
-    SpvDecorationPrecisionHigh = 2,
-    SpvDecorationBlock = 3,
-    SpvDecorationBufferBlock = 4,
-    SpvDecorationRowMajor = 5,
-    SpvDecorationColMajor = 6,
-    SpvDecorationGLSLShared = 7,
-    SpvDecorationGLSLStd140 = 8,
-    SpvDecorationGLSLStd430 = 9,
-    SpvDecorationGLSLPacked = 10,
-    SpvDecorationSmooth = 11,
-    SpvDecorationNoperspective = 12,
-    SpvDecorationFlat = 13,
-    SpvDecorationPatch = 14,
-    SpvDecorationCentroid = 15,
-    SpvDecorationSample = 16,
-    SpvDecorationInvariant = 17,
-    SpvDecorationRestrict = 18,
-    SpvDecorationAliased = 19,
-    SpvDecorationVolatile = 20,
-    SpvDecorationConstant = 21,
-    SpvDecorationCoherent = 22,
-    SpvDecorationNonwritable = 23,
-    SpvDecorationNonreadable = 24,
-    SpvDecorationUniform = 25,
-    SpvDecorationNoStaticUse = 26,
-    SpvDecorationCPacked = 27,
+    SpvDecorationRelaxedPrecision = 0,
+    SpvDecorationSpecId = 1,
+    SpvDecorationBlock = 2,
+    SpvDecorationBufferBlock = 3,
+    SpvDecorationRowMajor = 4,
+    SpvDecorationColMajor = 5,
+    SpvDecorationArrayStride = 6,
+    SpvDecorationMatrixStride = 7,
+    SpvDecorationGLSLShared = 8,
+    SpvDecorationGLSLPacked = 9,
+    SpvDecorationCPacked = 10,
+    SpvDecorationBuiltIn = 11,
+    SpvDecorationSmooth = 12,
+    SpvDecorationNoperspective = 13,
+    SpvDecorationFlat = 14,
+    SpvDecorationPatch = 15,
+    SpvDecorationCentroid = 16,
+    SpvDecorationSample = 17,
+    SpvDecorationInvariant = 18,
+    SpvDecorationRestrict = 19,
+    SpvDecorationAliased = 20,
+    SpvDecorationVolatile = 21,
+    SpvDecorationConstant = 22,
+    SpvDecorationCoherent = 23,
+    SpvDecorationNonwritable = 24,
+    SpvDecorationNonreadable = 25,
+    SpvDecorationUniform = 26,
+    SpvDecorationNoStaticUse = 27,
     SpvDecorationSaturatedConversion = 28,
     SpvDecorationStream = 29,
     SpvDecorationLocation = 30,
@@ -870,21 +345,17 @@ typedef enum SpvDecoration_ {
     SpvDecorationBinding = 33,
     SpvDecorationDescriptorSet = 34,
     SpvDecorationOffset = 35,
-    SpvDecorationAlignment = 36,
-    SpvDecorationXfbBuffer = 37,
-    SpvDecorationStride = 38,
-    SpvDecorationBuiltIn = 39,
-    SpvDecorationFuncParamAttr = 40,
-    SpvDecorationFPRoundingMode = 41,
-    SpvDecorationFPFastMathMode = 42,
-    SpvDecorationLinkageAttributes = 43,
-    SpvDecorationSpecId = 44,
+    SpvDecorationXfbBuffer = 36,
+    SpvDecorationXfbStride = 37,
+    SpvDecorationFuncParamAttr = 38,
+    SpvDecorationFPRoundingMode = 39,
+    SpvDecorationFPFastMathMode = 40,
+    SpvDecorationLinkageAttributes = 41,
 } SpvDecoration;
 
 typedef enum SpvBuiltIn_ {
     SpvBuiltInPosition = 0,
     SpvBuiltInPointSize = 1,
-    SpvBuiltInClipVertex = 2,
     SpvBuiltInClipDistance = 3,
     SpvBuiltInCullDistance = 4,
     SpvBuiltInVertexId = 5,
@@ -1001,12 +472,13 @@ typedef enum SpvMemoryAccessMask_ {
     SpvMemoryAccessAlignedMask = 0x00000002,
 } SpvMemoryAccessMask;
 
-typedef enum SpvExecutionScope_ {
-    SpvExecutionScopeCrossDevice = 0,
-    SpvExecutionScopeDevice = 1,
-    SpvExecutionScopeWorkgroup = 2,
-    SpvExecutionScopeSubgroup = 3,
-} SpvExecutionScope;
+typedef enum SpvScope_ {
+    SpvScopeCrossDevice = 0,
+    SpvScopeDevice = 1,
+    SpvScopeWorkgroup = 2,
+    SpvScopeSubgroup = 3,
+    SpvScopeInvocation = 4,
+} SpvScope;
 
 typedef enum SpvGroupOperation_ {
     SpvGroupOperationReduce = 0,
@@ -1029,276 +501,320 @@ typedef enum SpvKernelProfilingInfoMask_ {
     SpvKernelProfilingInfoCmdExecTimeMask = 0x00000001,
 } SpvKernelProfilingInfoMask;
 
+typedef enum SpvCapability_ {
+    SpvCapabilityMatrix = 0,
+    SpvCapabilityShader = 1,
+    SpvCapabilityGeometry = 2,
+    SpvCapabilityTessellation = 3,
+    SpvCapabilityAddresses = 4,
+    SpvCapabilityLinkage = 5,
+    SpvCapabilityKernel = 6,
+    SpvCapabilityVector16 = 7,
+    SpvCapabilityFloat16Buffer = 8,
+    SpvCapabilityFloat16 = 9,
+    SpvCapabilityFloat64 = 10,
+    SpvCapabilityInt64 = 11,
+    SpvCapabilityInt64Atomics = 12,
+    SpvCapabilityImageBasic = 13,
+    SpvCapabilityImageReadWrite = 14,
+    SpvCapabilityImageMipmap = 15,
+    SpvCapabilityImageSRGBWrite = 16,
+    SpvCapabilityPipes = 17,
+    SpvCapabilityGroups = 18,
+    SpvCapabilityDeviceEnqueue = 19,
+    SpvCapabilityLiteralSampler = 20,
+    SpvCapabilityAtomicStorage = 21,
+    SpvCapabilityInt16 = 22,
+    SpvCapabilityTessellationPointSize = 23,
+    SpvCapabilityGeometryPointSize = 24,
+    SpvCapabilityImageGatherExtended = 25,
+    SpvCapabilityStorageImageExtendedFormats = 26,
+    SpvCapabilityStorageImageMultisample = 27,
+    SpvCapabilityUniformBufferArrayDynamicIndexing = 28,
+    SpvCapabilitySampledImageArrayDynamicIndexing = 29,
+    SpvCapabilityStorageBufferArrayDynamicIndexing = 30,
+    SpvCapabilityStorageImageArrayDynamicIndexing = 31,
+    SpvCapabilityClipDistance = 32,
+    SpvCapabilityCullDistance = 33,
+    SpvCapabilityImageCubeArray = 34,
+    SpvCapabilitySampleRateShading = 35,
+} SpvCapability;
+
 typedef enum SpvOp_ {
     SpvOpNop = 0,
-    SpvOpSource = 1,
-    SpvOpSourceExtension = 2,
-    SpvOpExtension = 3,
-    SpvOpExtInstImport = 4,
-    SpvOpMemoryModel = 5,
-    SpvOpEntryPoint = 6,
-    SpvOpExecutionMode = 7,
-    SpvOpTypeVoid = 8,
-    SpvOpTypeBool = 9,
-    SpvOpTypeInt = 10,
-    SpvOpTypeFloat = 11,
-    SpvOpTypeVector = 12,
-    SpvOpTypeMatrix = 13,
-    SpvOpTypeSampler = 14,
-    SpvOpTypeFilter = 15,
-    SpvOpTypeArray = 16,
-    SpvOpTypeRuntimeArray = 17,
-    SpvOpTypeStruct = 18,
-    SpvOpTypeOpaque = 19,
-    SpvOpTypePointer = 20,
-    SpvOpTypeFunction = 21,
-    SpvOpTypeEvent = 22,
-    SpvOpTypeDeviceEvent = 23,
-    SpvOpTypeReserveId = 24,
-    SpvOpTypeQueue = 25,
-    SpvOpTypePipe = 26,
-    SpvOpConstantTrue = 27,
-    SpvOpConstantFalse = 28,
-    SpvOpConstant = 29,
-    SpvOpConstantComposite = 30,
-    SpvOpConstantSampler = 31,
-    SpvOpConstantNullPointer = 32,
-    SpvOpConstantNullObject = 33,
-    SpvOpSpecConstantTrue = 34,
-    SpvOpSpecConstantFalse = 35,
-    SpvOpSpecConstant = 36,
-    SpvOpSpecConstantComposite = 37,
-    SpvOpVariable = 38,
-    SpvOpVariableArray = 39,
-    SpvOpFunction = 40,
-    SpvOpFunctionParameter = 41,
-    SpvOpFunctionEnd = 42,
-    SpvOpFunctionCall = 43,
-    SpvOpExtInst = 44,
-    SpvOpUndef = 45,
-    SpvOpLoad = 46,
-    SpvOpStore = 47,
-    SpvOpPhi = 48,
-    SpvOpDecorationGroup = 49,
-    SpvOpDecorate = 50,
-    SpvOpMemberDecorate = 51,
-    SpvOpGroupDecorate = 52,
-    SpvOpGroupMemberDecorate = 53,
-    SpvOpName = 54,
-    SpvOpMemberName = 55,
-    SpvOpString = 56,
-    SpvOpLine = 57,
-    SpvOpVectorExtractDynamic = 58,
-    SpvOpVectorInsertDynamic = 59,
-    SpvOpVectorShuffle = 60,
-    SpvOpCompositeConstruct = 61,
-    SpvOpCompositeExtract = 62,
-    SpvOpCompositeInsert = 63,
-    SpvOpCopyObject = 64,
-    SpvOpCopyMemory = 65,
-    SpvOpCopyMemorySized = 66,
-    SpvOpSampler = 67,
-    SpvOpTextureSample = 68,
-    SpvOpTextureSampleDref = 69,
-    SpvOpTextureSampleLod = 70,
-    SpvOpTextureSampleProj = 71,
-    SpvOpTextureSampleGrad = 72,
-    SpvOpTextureSampleOffset = 73,
-    SpvOpTextureSampleProjLod = 74,
-    SpvOpTextureSampleProjGrad = 75,
-    SpvOpTextureSampleLodOffset = 76,
-    SpvOpTextureSampleProjOffset = 77,
-    SpvOpTextureSampleGradOffset = 78,
-    SpvOpTextureSampleProjLodOffset = 79,
-    SpvOpTextureSampleProjGradOffset = 80,
-    SpvOpTextureFetchTexelLod = 81,
-    SpvOpTextureFetchTexelOffset = 82,
-    SpvOpTextureFetchSample = 83,
-    SpvOpTextureFetchTexel = 84,
-    SpvOpTextureGather = 85,
-    SpvOpTextureGatherOffset = 86,
-    SpvOpTextureGatherOffsets = 87,
-    SpvOpTextureQuerySizeLod = 88,
-    SpvOpTextureQuerySize = 89,
-    SpvOpTextureQueryLod = 90,
-    SpvOpTextureQueryLevels = 91,
-    SpvOpTextureQuerySamples = 92,
-    SpvOpAccessChain = 93,
-    SpvOpInBoundsAccessChain = 94,
-    SpvOpSNegate = 95,
-    SpvOpFNegate = 96,
-    SpvOpNot = 97,
-    SpvOpAny = 98,
-    SpvOpAll = 99,
-    SpvOpConvertFToU = 100,
-    SpvOpConvertFToS = 101,
-    SpvOpConvertSToF = 102,
-    SpvOpConvertUToF = 103,
-    SpvOpUConvert = 104,
-    SpvOpSConvert = 105,
-    SpvOpFConvert = 106,
-    SpvOpConvertPtrToU = 107,
-    SpvOpConvertUToPtr = 108,
-    SpvOpPtrCastToGeneric = 109,
-    SpvOpGenericCastToPtr = 110,
-    SpvOpBitcast = 111,
-    SpvOpTranspose = 112,
-    SpvOpIsNan = 113,
-    SpvOpIsInf = 114,
-    SpvOpIsFinite = 115,
-    SpvOpIsNormal = 116,
-    SpvOpSignBitSet = 117,
-    SpvOpLessOrGreater = 118,
-    SpvOpOrdered = 119,
-    SpvOpUnordered = 120,
-    SpvOpArrayLength = 121,
-    SpvOpIAdd = 122,
-    SpvOpFAdd = 123,
-    SpvOpISub = 124,
-    SpvOpFSub = 125,
-    SpvOpIMul = 126,
-    SpvOpFMul = 127,
-    SpvOpUDiv = 128,
-    SpvOpSDiv = 129,
-    SpvOpFDiv = 130,
-    SpvOpUMod = 131,
-    SpvOpSRem = 132,
-    SpvOpSMod = 133,
-    SpvOpFRem = 134,
-    SpvOpFMod = 135,
-    SpvOpVectorTimesScalar = 136,
-    SpvOpMatrixTimesScalar = 137,
-    SpvOpVectorTimesMatrix = 138,
-    SpvOpMatrixTimesVector = 139,
-    SpvOpMatrixTimesMatrix = 140,
-    SpvOpOuterProduct = 141,
-    SpvOpDot = 142,
-    SpvOpShiftRightLogical = 143,
-    SpvOpShiftRightArithmetic = 144,
-    SpvOpShiftLeftLogical = 145,
-    SpvOpLogicalOr = 146,
-    SpvOpLogicalXor = 147,
-    SpvOpLogicalAnd = 148,
-    SpvOpBitwiseOr = 149,
-    SpvOpBitwiseXor = 150,
-    SpvOpBitwiseAnd = 151,
-    SpvOpSelect = 152,
-    SpvOpIEqual = 153,
-    SpvOpFOrdEqual = 154,
-    SpvOpFUnordEqual = 155,
-    SpvOpINotEqual = 156,
-    SpvOpFOrdNotEqual = 157,
-    SpvOpFUnordNotEqual = 158,
-    SpvOpULessThan = 159,
-    SpvOpSLessThan = 160,
-    SpvOpFOrdLessThan = 161,
-    SpvOpFUnordLessThan = 162,
-    SpvOpUGreaterThan = 163,
-    SpvOpSGreaterThan = 164,
-    SpvOpFOrdGreaterThan = 165,
-    SpvOpFUnordGreaterThan = 166,
-    SpvOpULessThanEqual = 167,
-    SpvOpSLessThanEqual = 168,
-    SpvOpFOrdLessThanEqual = 169,
-    SpvOpFUnordLessThanEqual = 170,
-    SpvOpUGreaterThanEqual = 171,
-    SpvOpSGreaterThanEqual = 172,
-    SpvOpFOrdGreaterThanEqual = 173,
-    SpvOpFUnordGreaterThanEqual = 174,
-    SpvOpDPdx = 175,
-    SpvOpDPdy = 176,
-    SpvOpFwidth = 177,
-    SpvOpDPdxFine = 178,
-    SpvOpDPdyFine = 179,
-    SpvOpFwidthFine = 180,
-    SpvOpDPdxCoarse = 181,
-    SpvOpDPdyCoarse = 182,
-    SpvOpFwidthCoarse = 183,
-    SpvOpEmitVertex = 184,
-    SpvOpEndPrimitive = 185,
-    SpvOpEmitStreamVertex = 186,
-    SpvOpEndStreamPrimitive = 187,
-    SpvOpControlBarrier = 188,
-    SpvOpMemoryBarrier = 189,
-    SpvOpImagePointer = 190,
-    SpvOpAtomicInit = 191,
-    SpvOpAtomicLoad = 192,
-    SpvOpAtomicStore = 193,
-    SpvOpAtomicExchange = 194,
-    SpvOpAtomicCompareExchange = 195,
-    SpvOpAtomicCompareExchangeWeak = 196,
-    SpvOpAtomicIIncrement = 197,
-    SpvOpAtomicIDecrement = 198,
-    SpvOpAtomicIAdd = 199,
-    SpvOpAtomicISub = 200,
-    SpvOpAtomicUMin = 201,
-    SpvOpAtomicUMax = 202,
-    SpvOpAtomicAnd = 203,
-    SpvOpAtomicOr = 204,
-    SpvOpAtomicXor = 205,
-    SpvOpLoopMerge = 206,
-    SpvOpSelectionMerge = 207,
-    SpvOpLabel = 208,
-    SpvOpBranch = 209,
-    SpvOpBranchConditional = 210,
-    SpvOpSwitch = 211,
-    SpvOpKill = 212,
-    SpvOpReturn = 213,
-    SpvOpReturnValue = 214,
-    SpvOpUnreachable = 215,
-    SpvOpLifetimeStart = 216,
-    SpvOpLifetimeStop = 217,
-    SpvOpCompileFlag = 218,
-    SpvOpAsyncGroupCopy = 219,
-    SpvOpWaitGroupEvents = 220,
-    SpvOpGroupAll = 221,
-    SpvOpGroupAny = 222,
-    SpvOpGroupBroadcast = 223,
-    SpvOpGroupIAdd = 224,
-    SpvOpGroupFAdd = 225,
-    SpvOpGroupFMin = 226,
-    SpvOpGroupUMin = 227,
-    SpvOpGroupSMin = 228,
-    SpvOpGroupFMax = 229,
-    SpvOpGroupUMax = 230,
-    SpvOpGroupSMax = 231,
-    SpvOpGenericCastToPtrExplicit = 232,
-    SpvOpGenericPtrMemSemantics = 233,
-    SpvOpReadPipe = 234,
-    SpvOpWritePipe = 235,
-    SpvOpReservedReadPipe = 236,
-    SpvOpReservedWritePipe = 237,
-    SpvOpReserveReadPipePackets = 238,
-    SpvOpReserveWritePipePackets = 239,
-    SpvOpCommitReadPipe = 240,
-    SpvOpCommitWritePipe = 241,
-    SpvOpIsValidReserveId = 242,
-    SpvOpGetNumPipePackets = 243,
-    SpvOpGetMaxPipePackets = 244,
-    SpvOpGroupReserveReadPipePackets = 245,
-    SpvOpGroupReserveWritePipePackets = 246,
-    SpvOpGroupCommitReadPipe = 247,
-    SpvOpGroupCommitWritePipe = 248,
-    SpvOpEnqueueMarker = 249,
-    SpvOpEnqueueKernel = 250,
-    SpvOpGetKernelNDrangeSubGroupCount = 251,
-    SpvOpGetKernelNDrangeMaxSubGroupSize = 252,
-    SpvOpGetKernelWorkGroupSize = 253,
-    SpvOpGetKernelPreferredWorkGroupSizeMultiple = 254,
-    SpvOpRetainEvent = 255,
-    SpvOpReleaseEvent = 256,
-    SpvOpCreateUserEvent = 257,
-    SpvOpIsValidEvent = 258,
-    SpvOpSetUserEventStatus = 259,
-    SpvOpCaptureEventProfilingInfo = 260,
-    SpvOpGetDefaultQueue = 261,
-    SpvOpBuildNDRange = 262,
-    SpvOpSatConvertSToU = 263,
-    SpvOpSatConvertUToS = 264,
-    SpvOpAtomicIMin = 265,
-    SpvOpAtomicIMax = 266,
+    SpvOpUndef = 1,
+    SpvOpSource = 3,
+    SpvOpSourceExtension = 4,
+    SpvOpName = 5,
+    SpvOpMemberName = 6,
+    SpvOpString = 7,
+    SpvOpLine = 8,
+    SpvOpExtension = 10,
+    SpvOpExtInstImport = 11,
+    SpvOpExtInst = 12,
+    SpvOpMemoryModel = 14,
+    SpvOpEntryPoint = 15,
+    SpvOpExecutionMode = 16,
+    SpvOpCapability = 17,
+    SpvOpTypeVoid = 19,
+    SpvOpTypeBool = 20,
+    SpvOpTypeInt = 21,
+    SpvOpTypeFloat = 22,
+    SpvOpTypeVector = 23,
+    SpvOpTypeMatrix = 24,
+    SpvOpTypeImage = 25,
+    SpvOpTypeSampler = 26,
+    SpvOpTypeSampledImage = 27,
+    SpvOpTypeArray = 28,
+    SpvOpTypeRuntimeArray = 29,
+    SpvOpTypeStruct = 30,
+    SpvOpTypeOpaque = 31,
+    SpvOpTypePointer = 32,
+    SpvOpTypeFunction = 33,
+    SpvOpTypeEvent = 34,
+    SpvOpTypeDeviceEvent = 35,
+    SpvOpTypeReserveId = 36,
+    SpvOpTypeQueue = 37,
+    SpvOpTypePipe = 38,
+    SpvOpConstantTrue = 41,
+    SpvOpConstantFalse = 42,
+    SpvOpConstant = 43,
+    SpvOpConstantComposite = 44,
+    SpvOpConstantSampler = 45,
+    SpvOpConstantNull = 46,
+    SpvOpSpecConstantTrue = 48,
+    SpvOpSpecConstantFalse = 49,
+    SpvOpSpecConstant = 50,
+    SpvOpSpecConstantComposite = 51,
+    SpvOpSpecConstantOp = 52,
+    SpvOpFunction = 54,
+    SpvOpFunctionParameter = 55,
+    SpvOpFunctionEnd = 56,
+    SpvOpFunctionCall = 57,
+    SpvOpVariable = 59,
+    SpvOpImageTexelPointer = 60,
+    SpvOpLoad = 61,
+    SpvOpStore = 62,
+    SpvOpCopyMemory = 63,
+    SpvOpCopyMemorySized = 64,
+    SpvOpAccessChain = 65,
+    SpvOpInBoundsAccessChain = 66,
+    SpvOpPtrAccessChain = 67,
+    SpvOpArrayLength = 68,
+    SpvOpGenericPtrMemSemantics = 69,
+    SpvOpDecorate = 71,
+    SpvOpMemberDecorate = 72,
+    SpvOpDecorationGroup = 73,
+    SpvOpGroupDecorate = 74,
+    SpvOpGroupMemberDecorate = 75,
+    SpvOpVectorExtractDynamic = 77,
+    SpvOpVectorInsertDynamic = 78,
+    SpvOpVectorShuffle = 79,
+    SpvOpCompositeConstruct = 80,
+    SpvOpCompositeExtract = 81,
+    SpvOpCompositeInsert = 82,
+    SpvOpCopyObject = 83,
+    SpvOpTranspose = 84,
+    SpvOpSampledImage = 86,
+    SpvOpImageSampleImplicitLod = 87,
+    SpvOpImageSampleExplicitLod = 88,
+    SpvOpImageSampleDrefImplicitLod = 89,
+    SpvOpImageSampleDrefExplicitLod = 90,
+    SpvOpImageSampleProjImplicitLod = 91,
+    SpvOpImageSampleProjExplicitLod = 92,
+    SpvOpImageSampleProjDrefImplicitLod = 93,
+    SpvOpImageSampleProjDrefExplicitLod = 94,
+    SpvOpImageFetch = 95,
+    SpvOpImageGather = 96,
+    SpvOpImageDrefGather = 97,
+    SpvOpImageRead = 98,
+    SpvOpImageWrite = 99,
+    SpvOpImageQueryDim = 100,
+    SpvOpImageQueryFormat = 101,
+    SpvOpImageQueryOrder = 102,
+    SpvOpImageQuerySizeLod = 103,
+    SpvOpImageQuerySize = 104,
+    SpvOpImageQueryLod = 105,
+    SpvOpImageQueryLevels = 106,
+    SpvOpImageQuerySamples = 107,
+    SpvOpConvertFToU = 109,
+    SpvOpConvertFToS = 110,
+    SpvOpConvertSToF = 111,
+    SpvOpConvertUToF = 112,
+    SpvOpUConvert = 113,
+    SpvOpSConvert = 114,
+    SpvOpFConvert = 115,
+    SpvOpQuantizeToF16 = 116,
+    SpvOpConvertPtrToU = 117,
+    SpvOpSatConvertSToU = 118,
+    SpvOpSatConvertUToS = 119,
+    SpvOpConvertUToPtr = 120,
+    SpvOpPtrCastToGeneric = 121,
+    SpvOpGenericCastToPtr = 122,
+    SpvOpGenericCastToPtrExplicit = 123,
+    SpvOpBitcast = 124,
+    SpvOpSNegate = 126,
+    SpvOpFNegate = 127,
+    SpvOpIAdd = 128,
+    SpvOpFAdd = 129,
+    SpvOpISub = 130,
+    SpvOpFSub = 131,
+    SpvOpIMul = 132,
+    SpvOpFMul = 133,
+    SpvOpUDiv = 134,
+    SpvOpSDiv = 135,
+    SpvOpFDiv = 136,
+    SpvOpUMod = 137,
+    SpvOpSRem = 138,
+    SpvOpSMod = 139,
+    SpvOpFRem = 140,
+    SpvOpFMod = 141,
+    SpvOpVectorTimesScalar = 142,
+    SpvOpMatrixTimesScalar = 143,
+    SpvOpVectorTimesMatrix = 144,
+    SpvOpMatrixTimesVector = 145,
+    SpvOpMatrixTimesMatrix = 146,
+    SpvOpOuterProduct = 147,
+    SpvOpDot = 148,
+    SpvOpIAddCarry = 149,
+    SpvOpISubBorrow = 150,
+    SpvOpIMulExtended = 151,
+    SpvOpAny = 154,
+    SpvOpAll = 155,
+    SpvOpIsNan = 156,
+    SpvOpIsInf = 157,
+    SpvOpIsFinite = 158,
+    SpvOpIsNormal = 159,
+    SpvOpSignBitSet = 160,
+    SpvOpLessOrGreater = 161,
+    SpvOpOrdered = 162,
+    SpvOpUnordered = 163,
+    SpvOpLogicalEqual = 164,
+    SpvOpLogicalNotEqual = 165,
+    SpvOpLogicalOr = 166,
+    SpvOpLogicalAnd = 167,
+    SpvOpLogicalNot = 168,
+    SpvOpSelect = 169,
+    SpvOpIEqual = 170,
+    SpvOpINotEqual = 171,
+    SpvOpUGreaterThan = 172,
+    SpvOpSGreaterThan = 173,
+    SpvOpUGreaterThanEqual = 174,
+    SpvOpSGreaterThanEqual = 175,
+    SpvOpULessThan = 176,
+    SpvOpSLessThan = 177,
+    SpvOpULessThanEqual = 178,
+    SpvOpSLessThanEqual = 179,
+    SpvOpFOrdEqual = 180,
+    SpvOpFUnordEqual = 181,
+    SpvOpFOrdNotEqual = 182,
+    SpvOpFUnordNotEqual = 183,
+    SpvOpFOrdLessThan = 184,
+    SpvOpFUnordLessThan = 185,
+    SpvOpFOrdGreaterThan = 186,
+    SpvOpFUnordGreaterThan = 187,
+    SpvOpFOrdLessThanEqual = 188,
+    SpvOpFUnordLessThanEqual = 189,
+    SpvOpFOrdGreaterThanEqual = 190,
+    SpvOpFUnordGreaterThanEqual = 191,
+    SpvOpShiftRightLogical = 194,
+    SpvOpShiftRightArithmetic = 195,
+    SpvOpShiftLeftLogical = 196,
+    SpvOpBitwiseOr = 197,
+    SpvOpBitwiseXor = 198,
+    SpvOpBitwiseAnd = 199,
+    SpvOpNot = 200,
+    SpvOpBitFieldInsert = 201,
+    SpvOpBitFieldSExtract = 202,
+    SpvOpBitFieldUExtract = 203,
+    SpvOpBitReverse = 204,
+    SpvOpBitCount = 205,
+    SpvOpDPdx = 207,
+    SpvOpDPdy = 208,
+    SpvOpFwidth = 209,
+    SpvOpDPdxFine = 210,
+    SpvOpDPdyFine = 211,
+    SpvOpFwidthFine = 212,
+    SpvOpDPdxCoarse = 213,
+    SpvOpDPdyCoarse = 214,
+    SpvOpFwidthCoarse = 215,
+    SpvOpEmitVertex = 218,
+    SpvOpEndPrimitive = 219,
+    SpvOpEmitStreamVertex = 220,
+    SpvOpEndStreamPrimitive = 221,
+    SpvOpControlBarrier = 224,
+    SpvOpMemoryBarrier = 225,
+    SpvOpAtomicLoad = 227,
+    SpvOpAtomicStore = 228,
+    SpvOpAtomicExchange = 229,
+    SpvOpAtomicCompareExchange = 230,
+    SpvOpAtomicCompareExchangeWeak = 231,
+    SpvOpAtomicIIncrement = 232,
+    SpvOpAtomicIDecrement = 233,
+    SpvOpAtomicIAdd = 234,
+    SpvOpAtomicISub = 235,
+    SpvOpAtomicSMin = 236,
+    SpvOpAtomicUMin = 237,
+    SpvOpAtomicSMax = 238,
+    SpvOpAtomicUMax = 239,
+    SpvOpAtomicAnd = 240,
+    SpvOpAtomicOr = 241,
+    SpvOpAtomicXor = 242,
+    SpvOpPhi = 245,
+    SpvOpLoopMerge = 246,
+    SpvOpSelectionMerge = 247,
+    SpvOpLabel = 248,
+    SpvOpBranch = 249,
+    SpvOpBranchConditional = 250,
+    SpvOpSwitch = 251,
+    SpvOpKill = 252,
+    SpvOpReturn = 253,
+    SpvOpReturnValue = 254,
+    SpvOpUnreachable = 255,
+    SpvOpLifetimeStart = 256,
+    SpvOpLifetimeStop = 257,
+    SpvOpAsyncGroupCopy = 259,
+    SpvOpWaitGroupEvents = 260,
+    SpvOpGroupAll = 261,
+    SpvOpGroupAny = 262,
+    SpvOpGroupBroadcast = 263,
+    SpvOpGroupIAdd = 264,
+    SpvOpGroupFAdd = 265,
+    SpvOpGroupFMin = 266,
+    SpvOpGroupUMin = 267,
+    SpvOpGroupSMin = 268,
+    SpvOpGroupFMax = 269,
+    SpvOpGroupUMax = 270,
+    SpvOpGroupSMax = 271,
+    SpvOpReadPipe = 274,
+    SpvOpWritePipe = 275,
+    SpvOpReservedReadPipe = 276,
+    SpvOpReservedWritePipe = 277,
+    SpvOpReserveReadPipePackets = 278,
+    SpvOpReserveWritePipePackets = 279,
+    SpvOpCommitReadPipe = 280,
+    SpvOpCommitWritePipe = 281,
+    SpvOpIsValidReserveId = 282,
+    SpvOpGetNumPipePackets = 283,
+    SpvOpGetMaxPipePackets = 284,
+    SpvOpGroupReserveReadPipePackets = 285,
+    SpvOpGroupReserveWritePipePackets = 286,
+    SpvOpGroupCommitReadPipe = 287,
+    SpvOpGroupCommitWritePipe = 288,
+    SpvOpEnqueueMarker = 291,
+    SpvOpEnqueueKernel = 292,
+    SpvOpGetKernelNDrangeSubGroupCount = 293,
+    SpvOpGetKernelNDrangeMaxSubGroupSize = 294,
+    SpvOpGetKernelWorkGroupSize = 295,
+    SpvOpGetKernelPreferredWorkGroupSizeMultiple = 296,
+    SpvOpRetainEvent = 297,
+    SpvOpReleaseEvent = 298,
+    SpvOpCreateUserEvent = 299,
+    SpvOpIsValidEvent = 300,
+    SpvOpSetUserEventStatus = 301,
+    SpvOpCaptureEventProfilingInfo = 302,
+    SpvOpGetDefaultQueue = 303,
+    SpvOpBuildNDRange = 304,
 } SpvOp;
 
-#endif  // #ifndef __cplusplus
-
 #endif  // #ifndef spirv_H
index 3b9d0940aad0bbf35f2cebc6843c2e5772a0e2ec..52b048820f305f1f5b1dcdd28413af1ca469c1f0 100644 (file)
@@ -139,13 +139,14 @@ handle_glsl450_alu(struct vtn_builder *b, enum GLSL450Entrypoint entrypoint,
                    const uint32_t *w, unsigned count)
 {
    struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa);
-   val->type = vtn_value(b, w[1], vtn_value_type_type)->type;
+   val->ssa = rzalloc(b, struct vtn_ssa_value);
+   val->ssa->type = vtn_value(b, w[1], vtn_value_type_type)->type->type;
 
    /* Collect the various SSA sources */
    unsigned num_inputs = count - 5;
    nir_ssa_def *src[3];
    for (unsigned i = 0; i < num_inputs; i++)
-      src[i] = vtn_ssa_value(b, w[i + 5]);
+      src[i] = vtn_ssa_value(b, w[i + 5])->def;
 
    nir_op op;
    switch (entrypoint) {
@@ -158,16 +159,16 @@ handle_glsl450_alu(struct vtn_builder *b, enum GLSL450Entrypoint entrypoint,
    case Ceil:        op = nir_op_fceil;         break;
    case Fract:       op = nir_op_ffract;        break;
    case Radians:
-      val->ssa = nir_fmul(&b->nb, src[0], nir_imm_float(&b->nb, 0.01745329251));
+      val->ssa->def = nir_fmul(&b->nb, src[0], nir_imm_float(&b->nb, 0.01745329251));
       return;
    case Degrees:
-      val->ssa = nir_fmul(&b->nb, src[0], nir_imm_float(&b->nb, 57.2957795131));
+      val->ssa->def = nir_fmul(&b->nb, src[0], nir_imm_float(&b->nb, 57.2957795131));
       return;
    case Sin:         op = nir_op_fsin;       break;
    case Cos:         op = nir_op_fcos;       break;
    case Tan:
-      val->ssa = nir_fdiv(&b->nb, nir_fsin(&b->nb, src[0]),
-                                  nir_fcos(&b->nb, src[0]));
+      val->ssa->def = nir_fdiv(&b->nb, nir_fsin(&b->nb, src[0]),
+                               nir_fcos(&b->nb, src[0]));
       return;
    case Pow:         op = nir_op_fpow;       break;
    case Exp2:        op = nir_op_fexp2;      break;
@@ -180,7 +181,7 @@ handle_glsl450_alu(struct vtn_builder *b, enum GLSL450Entrypoint entrypoint,
    case Max:         op = nir_op_fmax;       break;
    case Mix:         op = nir_op_flrp;       break;
    case Step:
-      val->ssa = nir_sge(&b->nb, src[1], src[0]);
+      val->ssa->def = nir_sge(&b->nb, src[1], src[0]);
       return;
 
    case FloatBitsToInt:
@@ -188,7 +189,7 @@ handle_glsl450_alu(struct vtn_builder *b, enum GLSL450Entrypoint entrypoint,
    case IntBitsToFloat:
    case UintBitsToFloat:
       /* Probably going to be removed from the final version of the spec. */
-      val->ssa = src[0];
+      val->ssa->def = src[0];
       return;
 
    case Fma:         op = nir_op_ffma;       break;
@@ -207,13 +208,13 @@ handle_glsl450_alu(struct vtn_builder *b, enum GLSL450Entrypoint entrypoint,
    case UnpackHalf2x16:    op = nir_op_unpack_half_2x16;    break;
 
    case Length:
-      val->ssa = build_length(&b->nb, src[0]);
+      val->ssa->def = build_length(&b->nb, src[0]);
       return;
    case Distance:
-      val->ssa = build_length(&b->nb, nir_fsub(&b->nb, src[0], src[1]));
+      val->ssa->def = build_length(&b->nb, nir_fsub(&b->nb, src[0], src[1]));
       return;
    case Normalize:
-      val->ssa = nir_fdiv(&b->nb, src[0], build_length(&b->nb, src[0]));
+      val->ssa->def = nir_fdiv(&b->nb, src[0], build_length(&b->nb, src[0]));
       return;
 
    case UaddCarry:         op = nir_op_uadd_carry;          break;
@@ -255,8 +256,8 @@ handle_glsl450_alu(struct vtn_builder *b, enum GLSL450Entrypoint entrypoint,
 
    nir_alu_instr *instr = nir_alu_instr_create(b->shader, op);
    nir_ssa_dest_init(&instr->instr, &instr->dest.dest,
-                     glsl_get_vector_elements(val->type), val->name);
-   val->ssa = &instr->dest.dest.ssa;
+                     glsl_get_vector_elements(val->ssa->type), val->name);
+   val->ssa->def = &instr->dest.dest.ssa;
 
    for (unsigned i = 0; i < nir_op_infos[op].num_inputs; i++)
       instr->src[i].src = nir_src_for_ssa(src[i]);
index 3f2ef15c74f876cc883ee3f4909c6befb7d2b3cc..c3a16986fc1b55faf5f058580292784e9aeba765 100644 (file)
 
 #include "spirv_to_nir_private.h"
 #include "nir_vla.h"
+#include "nir_control_flow.h"
 
-nir_ssa_def *
-vtn_ssa_value(struct vtn_builder *b, uint32_t value_id)
+static struct vtn_ssa_value *
+vtn_const_ssa_value(struct vtn_builder *b, nir_constant *constant,
+                    const struct glsl_type *type)
 {
-   struct vtn_value *val = vtn_untyped_value(b, value_id);
-   switch (val->value_type) {
-   case vtn_value_type_constant: {
-      assert(glsl_type_is_vector_or_scalar(val->type));
-      unsigned num_components = glsl_get_vector_elements(val->type);
-      nir_load_const_instr *load =
-         nir_load_const_instr_create(b->shader, num_components);
+   struct hash_entry *entry = _mesa_hash_table_search(b->const_table, constant);
+
+   if (entry)
+      return entry->data;
+
+   struct vtn_ssa_value *val = rzalloc(b, struct vtn_ssa_value);
+   val->type = type;
+
+   switch (glsl_get_base_type(type)) {
+   case GLSL_TYPE_INT:
+   case GLSL_TYPE_UINT:
+   case GLSL_TYPE_BOOL:
+   case GLSL_TYPE_FLOAT:
+   case GLSL_TYPE_DOUBLE:
+      if (glsl_type_is_vector_or_scalar(type)) {
+         unsigned num_components = glsl_get_vector_elements(val->type);
+         nir_load_const_instr *load =
+            nir_load_const_instr_create(b->shader, num_components);
+
+         for (unsigned i = 0; i < num_components; i++)
+            load->value.u[i] = constant->value.u[i];
+
+         nir_instr_insert_before_cf_list(&b->impl->body, &load->instr);
+         val->def = &load->def;
+      } else {
+         assert(glsl_type_is_matrix(type));
+         unsigned rows = glsl_get_vector_elements(val->type);
+         unsigned columns = glsl_get_matrix_columns(val->type);
+         val->elems = ralloc_array(b, struct vtn_ssa_value *, columns);
 
-      for (unsigned i = 0; i < num_components; i++)
-         load->value.u[0] = val->constant->value.u[0];
+         for (unsigned i = 0; i < columns; i++) {
+            struct vtn_ssa_value *col_val = rzalloc(b, struct vtn_ssa_value);
+            col_val->type = glsl_get_column_type(val->type);
+            nir_load_const_instr *load =
+               nir_load_const_instr_create(b->shader, rows);
 
-      nir_builder_instr_insert(&b->nb, &load->instr);
-      return &load->def;
+            for (unsigned j = 0; j < rows; j++)
+               load->value.u[j] = constant->value.u[rows * i + j];
+
+            nir_instr_insert_before_cf_list(&b->impl->body, &load->instr);
+            col_val->def = &load->def;
+
+            val->elems[i] = col_val;
+         }
+      }
+      break;
+
+   case GLSL_TYPE_ARRAY: {
+      unsigned elems = glsl_get_length(val->type);
+      val->elems = ralloc_array(b, struct vtn_ssa_value *, elems);
+      const struct glsl_type *elem_type = glsl_get_array_element(val->type);
+      for (unsigned i = 0; i < elems; i++)
+         val->elems[i] = vtn_const_ssa_value(b, constant->elements[i],
+                                             elem_type);
+      break;
+   }
+
+   case GLSL_TYPE_STRUCT: {
+      unsigned elems = glsl_get_length(val->type);
+      val->elems = ralloc_array(b, struct vtn_ssa_value *, elems);
+      for (unsigned i = 0; i < elems; i++) {
+         const struct glsl_type *elem_type =
+            glsl_get_struct_field(val->type, i);
+         val->elems[i] = vtn_const_ssa_value(b, constant->elements[i],
+                                             elem_type);
+      }
+      break;
    }
 
+   default:
+      unreachable("bad constant type");
+   }
+
+   return val;
+}
+
+struct vtn_ssa_value *
+vtn_ssa_value(struct vtn_builder *b, uint32_t value_id)
+{
+   struct vtn_value *val = vtn_untyped_value(b, value_id);
+   switch (val->value_type) {
+   case vtn_value_type_constant:
+      return vtn_const_ssa_value(b, val->constant, val->const_type);
+
    case vtn_value_type_ssa:
       return val->ssa;
    default:
@@ -110,15 +181,24 @@ vtn_handle_extension(struct vtn_builder *b, SpvOp opcode,
 static void
 _foreach_decoration_helper(struct vtn_builder *b,
                            struct vtn_value *base_value,
+                           int member,
                            struct vtn_value *value,
                            vtn_decoration_foreach_cb cb, void *data)
 {
+   int new_member = member;
+
    for (struct vtn_decoration *dec = value->decoration; dec; dec = dec->next) {
+      if (dec->member >= 0) {
+         assert(member == -1);
+         new_member = dec->member;
+      }
+
       if (dec->group) {
          assert(dec->group->value_type == vtn_value_type_decoration_group);
-         _foreach_decoration_helper(b, base_value, dec->group, cb, data);
+         _foreach_decoration_helper(b, base_value, new_member, dec->group,
+                                    cb, data);
       } else {
-         cb(b, base_value, dec, data);
+         cb(b, base_value, new_member, dec, data);
       }
    }
 }
@@ -133,24 +213,33 @@ void
 vtn_foreach_decoration(struct vtn_builder *b, struct vtn_value *value,
                        vtn_decoration_foreach_cb cb, void *data)
 {
-   _foreach_decoration_helper(b, value, value, cb, data);
+   _foreach_decoration_helper(b, value, -1, value, cb, data);
 }
 
 static void
 vtn_handle_decoration(struct vtn_builder *b, SpvOp opcode,
                       const uint32_t *w, unsigned count)
 {
+   const uint32_t *w_end = w + count;
+   const uint32_t target = w[1];
+   w += 2;
+
+   int member = -1;
    switch (opcode) {
    case SpvOpDecorationGroup:
-      vtn_push_value(b, w[1], vtn_value_type_undef);
+      vtn_push_value(b, target, vtn_value_type_undef);
       break;
 
+   case SpvOpMemberDecorate:
+      member = *(w++);
+      /* fallthrough */
    case SpvOpDecorate: {
-      struct vtn_value *val = &b->values[w[1]];
+      struct vtn_value *val = &b->values[target];
 
       struct vtn_decoration *dec = rzalloc(b, struct vtn_decoration);
-      dec->decoration = w[2];
-      dec->literals = &w[3];
+      dec->member = member;
+      dec->decoration = *(w++);
+      dec->literals = w;
 
       /* Link into the list */
       dec->next = val->decoration;
@@ -158,13 +247,17 @@ vtn_handle_decoration(struct vtn_builder *b, SpvOp opcode,
       break;
    }
 
+   case SpvOpGroupMemberDecorate:
+      member = *(w++);
+      /* fallthrough */
    case SpvOpGroupDecorate: {
-      struct vtn_value *group = &b->values[w[1]];
+      struct vtn_value *group = &b->values[target];
       assert(group->value_type == vtn_value_type_decoration_group);
 
-      for (unsigned i = 2; i < count; i++) {
-         struct vtn_value *val = &b->values[w[i]];
+      for (; w < w_end; w++) {
+         struct vtn_value *val = &b->values[*w];
          struct vtn_decoration *dec = rzalloc(b, struct vtn_decoration);
+         dec->member = member;
          dec->group = group;
 
          /* Link into the list */
@@ -174,57 +267,207 @@ vtn_handle_decoration(struct vtn_builder *b, SpvOp opcode,
       break;
    }
 
-   case SpvOpGroupMemberDecorate:
-      assert(!"Bad instruction.  Khronos Bug #13513");
+   default:
+      unreachable("Unhandled opcode");
+   }
+}
+
+struct member_decoration_ctx {
+   struct glsl_struct_field *fields;
+   struct vtn_type *type;
+};
+
+/* does a shallow copy of a vtn_type */
+
+static struct vtn_type *
+vtn_type_copy(struct vtn_builder *b, struct vtn_type *src)
+{
+   struct vtn_type *dest = ralloc(b, struct vtn_type);
+   dest->type = src->type;
+   dest->is_builtin = src->is_builtin;
+   if (src->is_builtin)
+      dest->builtin = src->builtin;
+
+   if (!glsl_type_is_vector_or_scalar(src->type)) {
+      switch (glsl_get_base_type(src->type)) {
+      case GLSL_TYPE_ARRAY:
+         dest->array_element = src->array_element;
+         dest->stride = src->stride;
+         break;
+
+      case GLSL_TYPE_INT:
+      case GLSL_TYPE_UINT:
+      case GLSL_TYPE_BOOL:
+      case GLSL_TYPE_FLOAT:
+      case GLSL_TYPE_DOUBLE:
+         /* matrices */
+         dest->row_major = src->row_major;
+         dest->stride = src->stride;
+         break;
+
+      case GLSL_TYPE_STRUCT: {
+         unsigned elems = glsl_get_length(src->type);
+
+         dest->members = ralloc_array(b, struct vtn_type *, elems);
+         memcpy(dest->members, src->members, elems * sizeof(struct vtn_type *));
+
+         dest->offsets = ralloc_array(b, unsigned, elems);
+         memcpy(dest->offsets, src->offsets, elems * sizeof(unsigned));
+         break;
+      }
+
+      default:
+         unreachable("unhandled type");
+      }
+   }
+
+   return dest;
+}
+
+static void
+struct_member_decoration_cb(struct vtn_builder *b,
+                            struct vtn_value *val, int member,
+                            const struct vtn_decoration *dec, void *void_ctx)
+{
+   struct member_decoration_ctx *ctx = void_ctx;
+
+   if (member < 0)
+      return;
+
+   switch (dec->decoration) {
+   case SpvDecorationRelaxedPrecision:
+      break; /* FIXME: Do nothing with this for now. */
+   case SpvDecorationSmooth:
+      ctx->fields[member].interpolation = INTERP_QUALIFIER_SMOOTH;
+      break;
+   case SpvDecorationNoperspective:
+      ctx->fields[member].interpolation = INTERP_QUALIFIER_NOPERSPECTIVE;
+      break;
+   case SpvDecorationFlat:
+      ctx->fields[member].interpolation = INTERP_QUALIFIER_FLAT;
+      break;
+   case SpvDecorationCentroid:
+      ctx->fields[member].centroid = true;
+      break;
+   case SpvDecorationSample:
+      ctx->fields[member].sample = true;
+      break;
+   case SpvDecorationLocation:
+      ctx->fields[member].location = dec->literals[0];
+      break;
+   case SpvDecorationBuiltIn:
+      ctx->type->members[member] = vtn_type_copy(b,
+                                                 ctx->type->members[member]);
+      ctx->type->members[member]->is_builtin = true;
+      ctx->type->members[member]->builtin = dec->literals[0];
+      ctx->type->builtin_block = true;
+      break;
+   case SpvDecorationOffset:
+      ctx->type->offsets[member] = dec->literals[0];
+      break;
+   default:
+      unreachable("Unhandled member decoration");
+   }
+}
+
+static void
+type_decoration_cb(struct vtn_builder *b,
+                   struct vtn_value *val, int member,
+                    const struct vtn_decoration *dec, void *ctx)
+{
+   struct vtn_type *type = val->type;
+
+   if (member != -1)
+      return;
+
+   switch (dec->decoration) {
+   case SpvDecorationArrayStride:
+      type->stride = dec->literals[0];
+      break;
+   case SpvDecorationBlock:
+      type->block = true;
+      break;
+   case SpvDecorationBufferBlock:
+      type->buffer_block = true;
+      break;
+   case SpvDecorationGLSLShared:
+   case SpvDecorationGLSLPacked:
+      /* Ignore these, since we get explicit offsets anyways */
       break;
 
    default:
-      unreachable("Unhandled opcode");
+      unreachable("Unhandled type decoration");
    }
 }
 
-static const struct glsl_type *
+static void
 vtn_handle_type(struct vtn_builder *b, SpvOp opcode,
-                const uint32_t *args, unsigned count)
+                const uint32_t *w, unsigned count)
 {
+   struct vtn_value *val = vtn_push_value(b, w[1], vtn_value_type_type);
+
+   val->type = rzalloc(b, struct vtn_type);
+   val->type->is_builtin = false;
+
    switch (opcode) {
    case SpvOpTypeVoid:
-      return glsl_void_type();
+      val->type->type = glsl_void_type();
+      break;
    case SpvOpTypeBool:
-      return glsl_bool_type();
+      val->type->type = glsl_bool_type();
+      break;
    case SpvOpTypeInt:
-      return glsl_int_type();
+      val->type->type = glsl_int_type();
+      break;
    case SpvOpTypeFloat:
-      return glsl_float_type();
+      val->type->type = glsl_float_type();
+      break;
 
    case SpvOpTypeVector: {
       const struct glsl_type *base =
-         vtn_value(b, args[0], vtn_value_type_type)->type;
-      unsigned elems = args[1];
+         vtn_value(b, w[2], vtn_value_type_type)->type->type;
+      unsigned elems = w[3];
 
       assert(glsl_type_is_scalar(base));
-      return glsl_vector_type(glsl_get_base_type(base), elems);
+      val->type->type = glsl_vector_type(glsl_get_base_type(base), elems);
+      break;
    }
 
    case SpvOpTypeMatrix: {
-      const struct glsl_type *base =
-         vtn_value(b, args[0], vtn_value_type_type)->type;
-      unsigned columns = args[1];
-
-      assert(glsl_type_is_vector(base));
-      return glsl_matrix_type(glsl_get_base_type(base),
-                              glsl_get_vector_elements(base),
-                              columns);
+      struct vtn_type *base =
+         vtn_value(b, w[2], vtn_value_type_type)->type;
+      unsigned columns = w[3];
+
+      assert(glsl_type_is_vector(base->type));
+      val->type->type = glsl_matrix_type(glsl_get_base_type(base->type),
+                                         glsl_get_vector_elements(base->type),
+                                         columns);
+      val->type->array_element = base;
+      val->type->row_major = false;
+      val->type->stride = 0;
+      break;
    }
 
-   case SpvOpTypeArray:
-      return glsl_array_type(b->values[args[0]].type, args[1]);
+   case SpvOpTypeArray: {
+      struct vtn_type *array_element =
+         vtn_value(b, w[2], vtn_value_type_type)->type;
+      val->type->type = glsl_array_type(array_element->type, w[3]);
+      val->type->array_element = array_element;
+      val->type->stride = 0;
+      break;
+   }
 
    case SpvOpTypeStruct: {
+      unsigned num_fields = count - 2;
+      val->type->members = ralloc_array(b, struct vtn_type *, num_fields);
+      val->type->offsets = ralloc_array(b, unsigned, num_fields);
+
       NIR_VLA(struct glsl_struct_field, fields, count);
-      for (unsigned i = 0; i < count; i++) {
+      for (unsigned i = 0; i < num_fields; i++) {
          /* TODO: Handle decorators */
-         fields[i].type = vtn_value(b, args[i], vtn_value_type_type)->type;
+         val->type->members[i] =
+            vtn_value(b, w[i + 2], vtn_value_type_type)->type;
+         fields[i].type = val->type->members[i]->type;
          fields[i].name = ralloc_asprintf(b, "field%d", i);
          fields[i].location = -1;
          fields[i].interpolation = 0;
@@ -233,20 +476,33 @@ vtn_handle_type(struct vtn_builder *b, SpvOp opcode,
          fields[i].matrix_layout = 2;
          fields[i].stream = -1;
       }
-      return glsl_struct_type(fields, count, "struct");
+
+      struct member_decoration_ctx ctx = {
+         .fields = fields,
+         .type = val->type
+      };
+
+      vtn_foreach_decoration(b, val, struct_member_decoration_cb, &ctx);
+
+      const char *name = val->name ? val->name : "struct";
+
+      val->type->type = glsl_struct_type(fields, num_fields, name);
+      break;
    }
 
    case SpvOpTypeFunction: {
-      const struct glsl_type *return_type = b->values[args[0]].type;
-      NIR_VLA(struct glsl_function_param, params, count - 1);
-      for (unsigned i = 1; i < count; i++) {
-         params[i - 1].type = vtn_value(b, args[i], vtn_value_type_type)->type;
+      const struct glsl_type *return_type =
+         vtn_value(b, w[2], vtn_value_type_type)->type->type;
+      NIR_VLA(struct glsl_function_param, params, count - 3);
+      for (unsigned i = 0; i < count - 3; i++) {
+         params[i].type = vtn_value(b, w[i + 3], vtn_value_type_type)->type->type;
 
          /* FIXME: */
-         params[i - 1].in = true;
-         params[i - 1].out = true;
+         params[i].in = true;
+         params[i].out = true;
       }
-      return glsl_function_type(return_type, params, count - 1);
+      val->type->type = glsl_function_type(return_type, params, count - 3);
+      break;
    }
 
    case SpvOpTypePointer:
@@ -254,16 +510,17 @@ vtn_handle_type(struct vtn_builder *b, SpvOp opcode,
        * the same type.  The validator should ensure that the proper number
        * of dereferences happen
        */
-      return vtn_value(b, args[1], vtn_value_type_type)->type;
+      val->type = vtn_value(b, w[3], vtn_value_type_type)->type;
+      break;
 
-   case SpvOpTypeSampler: {
+   case SpvOpTypeImage: {
       const struct glsl_type *sampled_type =
-         vtn_value(b, args[0], vtn_value_type_type)->type;
+         vtn_value(b, w[2], vtn_value_type_type)->type->type;
 
       assert(glsl_type_is_vector_or_scalar(sampled_type));
 
       enum glsl_sampler_dim dim;
-      switch ((SpvDim)args[1]) {
+      switch ((SpvDim)w[3]) {
       case SpvDim1D:       dim = GLSL_SAMPLER_DIM_1D;    break;
       case SpvDim2D:       dim = GLSL_SAMPLER_DIM_2D;    break;
       case SpvDim3D:       dim = GLSL_SAMPLER_DIM_3D;    break;
@@ -274,18 +531,21 @@ vtn_handle_type(struct vtn_builder *b, SpvOp opcode,
          unreachable("Invalid SPIR-V Sampler dimension");
       }
 
-      /* TODO: Handle the various texture image/filter options */
-      (void)args[2];
-
-      bool is_array = args[3];
-      bool is_shadow = args[4];
+      bool is_shadow = w[4];
+      bool is_array = w[5];
 
-      assert(args[5] == 0 && "FIXME: Handl multi-sampled textures");
+      assert(w[6] == 0 && "FIXME: Handl multi-sampled textures");
+      assert(w[7] == 1 && "FIXME: Add support for non-sampled images");
 
-      return glsl_sampler_type(dim, is_shadow, is_array,
-                               glsl_get_base_type(sampled_type));
+      val->type->type = glsl_sampler_type(dim, is_shadow, is_array,
+                                          glsl_get_base_type(sampled_type));
+      break;
    }
 
+   case SpvOpTypeSampledImage:
+      val->type = vtn_value(b, w[2], vtn_value_type_type)->type;
+      break;
+
    case SpvOpTypeRuntimeArray:
    case SpvOpTypeOpaque:
    case SpvOpTypeEvent:
@@ -296,6 +556,8 @@ vtn_handle_type(struct vtn_builder *b, SpvOp opcode,
    default:
       unreachable("Unhandled opcode");
    }
+
+   vtn_foreach_decoration(b, val, type_decoration_cb, NULL);
 }
 
 static void
@@ -303,19 +565,19 @@ vtn_handle_constant(struct vtn_builder *b, SpvOp opcode,
                     const uint32_t *w, unsigned count)
 {
    struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_constant);
-   val->type = vtn_value(b, w[1], vtn_value_type_type)->type;
+   val->const_type = vtn_value(b, w[1], vtn_value_type_type)->type->type;
    val->constant = ralloc(b, nir_constant);
    switch (opcode) {
    case SpvOpConstantTrue:
-      assert(val->type == glsl_bool_type());
+      assert(val->const_type == glsl_bool_type());
       val->constant->value.u[0] = NIR_TRUE;
       break;
    case SpvOpConstantFalse:
-      assert(val->type == glsl_bool_type());
+      assert(val->const_type == glsl_bool_type());
       val->constant->value.u[0] = NIR_FALSE;
       break;
    case SpvOpConstant:
-      assert(glsl_type_is_scalar(val->type));
+      assert(glsl_type_is_scalar(val->const_type));
       val->constant->value.u[0] = w[3];
       break;
    case SpvOpConstantComposite: {
@@ -324,20 +586,20 @@ vtn_handle_constant(struct vtn_builder *b, SpvOp opcode,
       for (unsigned i = 0; i < elem_count; i++)
          elems[i] = vtn_value(b, w[i + 3], vtn_value_type_constant)->constant;
 
-      switch (glsl_get_base_type(val->type)) {
+      switch (glsl_get_base_type(val->const_type)) {
       case GLSL_TYPE_UINT:
       case GLSL_TYPE_INT:
       case GLSL_TYPE_FLOAT:
       case GLSL_TYPE_BOOL:
-         if (glsl_type_is_matrix(val->type)) {
-            unsigned rows = glsl_get_vector_elements(val->type);
-            assert(glsl_get_matrix_columns(val->type) == elem_count);
+         if (glsl_type_is_matrix(val->const_type)) {
+            unsigned rows = glsl_get_vector_elements(val->const_type);
+            assert(glsl_get_matrix_columns(val->const_type) == elem_count);
             for (unsigned i = 0; i < elem_count; i++)
                for (unsigned j = 0; j < rows; j++)
                   val->constant->value.u[rows * i + j] = elems[i]->value.u[j];
          } else {
-            assert(glsl_type_is_vector(val->type));
-            assert(glsl_get_vector_elements(val->type) == elem_count);
+            assert(glsl_type_is_vector(val->const_type));
+            assert(glsl_get_vector_elements(val->const_type) == elem_count);
             for (unsigned i = 0; i < elem_count; i++)
                val->constant->value.u[i] = elems[i]->value.u[0];
          }
@@ -362,7 +624,101 @@ vtn_handle_constant(struct vtn_builder *b, SpvOp opcode,
 }
 
 static void
-var_decoration_cb(struct vtn_builder *b, struct vtn_value *val,
+vtn_get_builtin_location(SpvBuiltIn builtin, int *location,
+                         nir_variable_mode *mode)
+{
+   switch (builtin) {
+   case SpvBuiltInPosition:
+      *location = VARYING_SLOT_POS;
+      *mode = nir_var_shader_out;
+      break;
+   case SpvBuiltInPointSize:
+      *location = VARYING_SLOT_PSIZ;
+      *mode = nir_var_shader_out;
+      break;
+   case SpvBuiltInClipDistance:
+      *location = VARYING_SLOT_CLIP_DIST0; /* XXX CLIP_DIST1? */
+      *mode = nir_var_shader_in;
+      break;
+   case SpvBuiltInCullDistance:
+      /* XXX figure this out */
+      unreachable("unhandled builtin");
+   case SpvBuiltInVertexId:
+      *location = SYSTEM_VALUE_VERTEX_ID;
+      *mode = nir_var_system_value;
+      break;
+   case SpvBuiltInInstanceId:
+      *location = SYSTEM_VALUE_INSTANCE_ID;
+      *mode = nir_var_system_value;
+      break;
+   case SpvBuiltInPrimitiveId:
+      *location = VARYING_SLOT_PRIMITIVE_ID;
+      *mode = nir_var_shader_out;
+      break;
+   case SpvBuiltInInvocationId:
+      *location = SYSTEM_VALUE_INVOCATION_ID;
+      *mode = nir_var_system_value;
+      break;
+   case SpvBuiltInLayer:
+      *location = VARYING_SLOT_LAYER;
+      *mode = nir_var_shader_out;
+      break;
+   case SpvBuiltInTessLevelOuter:
+   case SpvBuiltInTessLevelInner:
+   case SpvBuiltInTessCoord:
+   case SpvBuiltInPatchVertices:
+      unreachable("no tessellation support");
+   case SpvBuiltInFragCoord:
+      *location = VARYING_SLOT_POS;
+      *mode = nir_var_shader_in;
+      break;
+   case SpvBuiltInPointCoord:
+      *location = VARYING_SLOT_PNTC;
+      *mode = nir_var_shader_out;
+      break;
+   case SpvBuiltInFrontFacing:
+      *location = VARYING_SLOT_FACE;
+      *mode = nir_var_shader_out;
+      break;
+   case SpvBuiltInSampleId:
+      *location = SYSTEM_VALUE_SAMPLE_ID;
+      *mode = nir_var_shader_in;
+      break;
+   case SpvBuiltInSamplePosition:
+      *location = SYSTEM_VALUE_SAMPLE_POS;
+      *mode = nir_var_shader_in;
+      break;
+   case SpvBuiltInSampleMask:
+      *location = SYSTEM_VALUE_SAMPLE_MASK_IN; /* XXX out? */
+      *mode = nir_var_shader_in;
+      break;
+   case SpvBuiltInFragColor:
+      *location = FRAG_RESULT_COLOR;
+      *mode = nir_var_shader_out;
+      break;
+   case SpvBuiltInFragDepth:
+      *location = FRAG_RESULT_DEPTH;
+      *mode = nir_var_shader_out;
+      break;
+   case SpvBuiltInHelperInvocation:
+      unreachable("unsupported builtin"); /* XXX */
+      break;
+   case SpvBuiltInNumWorkgroups:
+   case SpvBuiltInWorkgroupSize:
+      /* these are constants, need to be handled specially */
+      unreachable("unsupported builtin");
+   case SpvBuiltInWorkgroupId:
+   case SpvBuiltInLocalInvocationId:
+   case SpvBuiltInGlobalInvocationId:
+   case SpvBuiltInLocalInvocationIndex:
+      unreachable("no compute shader support");
+   default:
+      unreachable("unsupported builtin");
+   }
+}
+
+static void
+var_decoration_cb(struct vtn_builder *b, struct vtn_value *val, int member,
                   const struct vtn_decoration *dec, void *void_var)
 {
    assert(val->value_type == vtn_value_type_deref);
@@ -371,10 +727,8 @@ var_decoration_cb(struct vtn_builder *b, struct vtn_value *val,
 
    nir_variable *var = void_var;
    switch (dec->decoration) {
-   case SpvDecorationPrecisionLow:
-   case SpvDecorationPrecisionMedium:
-   case SpvDecorationPrecisionHigh:
-      break; /* FIXME: Do nothing with these for now. */
+   case SpvDecorationRelaxedPrecision:
+      break; /* FIXME: Do nothing with this for now. */
    case SpvDecorationSmooth:
       var->data.interpolation = INTERP_QUALIFIER_SMOOTH;
       break;
@@ -415,14 +769,25 @@ var_decoration_cb(struct vtn_builder *b, struct vtn_value *val,
       var->data.explicit_binding = true;
       var->data.binding = dec->literals[0];
       break;
-   case SpvDecorationBlock:
-   case SpvDecorationBufferBlock:
+   case SpvDecorationDescriptorSet:
+      var->data.descriptor_set = dec->literals[0];
+      break;
+   case SpvDecorationBuiltIn: {
+      nir_variable_mode mode;
+      vtn_get_builtin_location(dec->literals[0], &var->data.location,
+                               &mode);
+      var->data.mode = mode;
+      if (mode == nir_var_shader_in || mode == nir_var_system_value)
+         var->data.read_only = true;
+      b->builtins[dec->literals[0]] = var;
+      break;
+   }
+   case SpvDecorationNoStaticUse:
+      /* This can safely be ignored */
+      break;
    case SpvDecorationRowMajor:
    case SpvDecorationColMajor:
    case SpvDecorationGLSLShared:
-   case SpvDecorationGLSLStd140:
-   case SpvDecorationGLSLStd430:
-   case SpvDecorationGLSLPacked:
    case SpvDecorationPatch:
    case SpvDecorationRestrict:
    case SpvDecorationAliased:
@@ -431,42 +796,453 @@ var_decoration_cb(struct vtn_builder *b, struct vtn_value *val,
    case SpvDecorationNonreadable:
    case SpvDecorationUniform:
       /* This is really nice but we have no use for it right now. */
-   case SpvDecorationNoStaticUse:
    case SpvDecorationCPacked:
    case SpvDecorationSaturatedConversion:
    case SpvDecorationStream:
-   case SpvDecorationDescriptorSet:
    case SpvDecorationOffset:
-   case SpvDecorationAlignment:
    case SpvDecorationXfbBuffer:
-   case SpvDecorationStride:
-   case SpvDecorationBuiltIn:
    case SpvDecorationFuncParamAttr:
    case SpvDecorationFPRoundingMode:
    case SpvDecorationFPFastMathMode:
    case SpvDecorationLinkageAttributes:
    case SpvDecorationSpecId:
+      break;
    default:
       unreachable("Unhandled variable decoration");
    }
 }
 
+static nir_variable *
+get_builtin_variable(struct vtn_builder *b,
+                     const struct glsl_type *type,
+                     SpvBuiltIn builtin)
+{
+   nir_variable *var = b->builtins[builtin];
+
+   if (!var) {
+      var = ralloc(b->shader, nir_variable);
+      var->type = type;
+
+      nir_variable_mode mode;
+      vtn_get_builtin_location(builtin, &var->data.location, &mode);
+      var->data.mode = mode;
+      var->name = ralloc_strdup(var, "builtin");
+
+      switch (mode) {
+      case nir_var_shader_in:
+         exec_list_push_tail(&b->shader->inputs, &var->node);
+         break;
+      case nir_var_shader_out:
+         exec_list_push_tail(&b->shader->outputs, &var->node);
+         break;
+      case nir_var_system_value:
+         exec_list_push_tail(&b->shader->system_values, &var->node);
+         break;
+      default:
+         unreachable("bad builtin mode");
+      }
+
+      b->builtins[builtin] = var;
+   }
+
+   return var;
+}
+
+static void
+vtn_builtin_load(struct vtn_builder *b,
+                 struct vtn_ssa_value *val,
+                 SpvBuiltIn builtin)
+{
+   assert(glsl_type_is_vector_or_scalar(val->type));
+
+   nir_variable *var = get_builtin_variable(b, val->type, builtin);
+
+   nir_intrinsic_instr *load =
+      nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_var);
+   nir_ssa_dest_init(&load->instr, &load->dest,
+                     glsl_get_vector_elements(val->type), NULL);
+
+   load->variables[0] = nir_deref_var_create(load, var);
+   load->num_components = glsl_get_vector_elements(val->type);
+   nir_builder_instr_insert(&b->nb, &load->instr);
+   val->def = &load->dest.ssa;
+}
+
+static void
+vtn_builtin_store(struct vtn_builder *b,
+                  struct vtn_ssa_value *val,
+                  SpvBuiltIn builtin)
+{
+   assert(glsl_type_is_vector_or_scalar(val->type));
+
+   nir_variable *var = get_builtin_variable(b, val->type, builtin);
+
+   nir_intrinsic_instr *store =
+      nir_intrinsic_instr_create(b->shader, nir_intrinsic_store_var);
+
+   store->variables[0] = nir_deref_var_create(store, var);
+   store->num_components = glsl_get_vector_elements(val->type);
+   store->src[0] = nir_src_for_ssa(val->def);
+   nir_builder_instr_insert(&b->nb, &store->instr);
+}
+
+static struct vtn_ssa_value *
+_vtn_variable_load(struct vtn_builder *b,
+                   nir_deref_var *src_deref, struct vtn_type *src_type,
+                   nir_deref *src_deref_tail)
+{
+   struct vtn_ssa_value *val = rzalloc(b, struct vtn_ssa_value);
+   val->type = src_deref_tail->type;
+
+   if (src_type->is_builtin) {
+      vtn_builtin_load(b, val, src_type->builtin);
+      return val;
+   }
+
+   /* The deref tail may contain a deref to select a component of a vector (in
+    * other words, it might not be an actual tail) so we have to save it away
+    * here since we overwrite it later.
+    */
+   nir_deref *old_child = src_deref_tail->child;
+
+   if (glsl_type_is_vector_or_scalar(val->type)) {
+      nir_intrinsic_instr *load =
+         nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_var);
+      load->variables[0] =
+         nir_deref_as_var(nir_copy_deref(load, &src_deref->deref));
+      load->num_components = glsl_get_vector_elements(val->type);
+      nir_ssa_dest_init(&load->instr, &load->dest, load->num_components, NULL);
+
+      nir_builder_instr_insert(&b->nb, &load->instr);
+
+      if (src_deref->var->data.mode == nir_var_uniform &&
+          glsl_get_base_type(val->type) == GLSL_TYPE_BOOL) {
+         /* Uniform boolean loads need to be fixed up since they're defined
+          * to be zero/nonzero rather than NIR_FALSE/NIR_TRUE.
+          */
+         val->def = nir_ine(&b->nb, &load->dest.ssa, nir_imm_int(&b->nb, 0));
+      } else {
+         val->def = &load->dest.ssa;
+      }
+   } else if (glsl_get_base_type(val->type) == GLSL_TYPE_ARRAY ||
+              glsl_type_is_matrix(val->type)) {
+      unsigned elems = glsl_get_length(val->type);
+      val->elems = ralloc_array(b, struct vtn_ssa_value *, elems);
+
+      nir_deref_array *deref = nir_deref_array_create(b);
+      deref->deref_array_type = nir_deref_array_type_direct;
+      deref->deref.type = glsl_get_array_element(val->type);
+      src_deref_tail->child = &deref->deref;
+      for (unsigned i = 0; i < elems; i++) {
+         deref->base_offset = i;
+         val->elems[i] = _vtn_variable_load(b, src_deref,
+                                            src_type->array_element,
+                                            &deref->deref);
+      }
+   } else {
+      assert(glsl_get_base_type(val->type) == GLSL_TYPE_STRUCT);
+      unsigned elems = glsl_get_length(val->type);
+      val->elems = ralloc_array(b, struct vtn_ssa_value *, elems);
+
+      nir_deref_struct *deref = nir_deref_struct_create(b, 0);
+      src_deref_tail->child = &deref->deref;
+      for (unsigned i = 0; i < elems; i++) {
+         deref->index = i;
+         deref->deref.type = glsl_get_struct_field(val->type, i);
+         val->elems[i] = _vtn_variable_load(b, src_deref,
+                                            src_type->members[i],
+                                            &deref->deref);
+      }
+   }
+
+   src_deref_tail->child = old_child;
+
+   return val;
+}
+
+static void
+_vtn_variable_store(struct vtn_builder *b, struct vtn_type *dest_type,
+                    nir_deref_var *dest_deref, nir_deref *dest_deref_tail,
+                    struct vtn_ssa_value *src)
+{
+   if (dest_type->is_builtin) {
+      vtn_builtin_store(b, src, dest_type->builtin);
+      return;
+   }
+
+   nir_deref *old_child = dest_deref_tail->child;
+
+   if (glsl_type_is_vector_or_scalar(src->type)) {
+      nir_intrinsic_instr *store =
+         nir_intrinsic_instr_create(b->shader, nir_intrinsic_store_var);
+      store->variables[0] =
+         nir_deref_as_var(nir_copy_deref(store, &dest_deref->deref));
+      store->num_components = glsl_get_vector_elements(src->type);
+      store->src[0] = nir_src_for_ssa(src->def);
+
+      nir_builder_instr_insert(&b->nb, &store->instr);
+   } else if (glsl_get_base_type(src->type) == GLSL_TYPE_ARRAY ||
+              glsl_type_is_matrix(src->type)) {
+      unsigned elems = glsl_get_length(src->type);
+
+      nir_deref_array *deref = nir_deref_array_create(b);
+      deref->deref_array_type = nir_deref_array_type_direct;
+      deref->deref.type = glsl_get_array_element(src->type);
+      dest_deref_tail->child = &deref->deref;
+      for (unsigned i = 0; i < elems; i++) {
+         deref->base_offset = i;
+         _vtn_variable_store(b, dest_type->array_element, dest_deref,
+                             &deref->deref, src->elems[i]);
+      }
+   } else {
+      assert(glsl_get_base_type(src->type) == GLSL_TYPE_STRUCT);
+      unsigned elems = glsl_get_length(src->type);
+
+      nir_deref_struct *deref = nir_deref_struct_create(b, 0);
+      dest_deref_tail->child = &deref->deref;
+      for (unsigned i = 0; i < elems; i++) {
+         deref->index = i;
+         deref->deref.type = glsl_get_struct_field(src->type, i);
+         _vtn_variable_store(b, dest_type->members[i], dest_deref,
+                             &deref->deref, src->elems[i]);
+      }
+   }
+
+   dest_deref_tail->child = old_child;
+}
+
+static struct vtn_ssa_value *
+_vtn_block_load(struct vtn_builder *b, nir_intrinsic_op op,
+                unsigned set, nir_ssa_def *binding,
+                unsigned offset, nir_ssa_def *indirect,
+                struct vtn_type *type)
+{
+   struct vtn_ssa_value *val = ralloc(b, struct vtn_ssa_value);
+   val->type = type->type;
+   val->transposed = NULL;
+   if (glsl_type_is_vector_or_scalar(type->type)) {
+      nir_intrinsic_instr *load = nir_intrinsic_instr_create(b->shader, op);
+      load->num_components = glsl_get_vector_elements(type->type);
+      load->const_index[0] = set;
+      load->src[0] = nir_src_for_ssa(binding);
+      load->const_index[1] = offset;
+      if (indirect)
+         load->src[1] = nir_src_for_ssa(indirect);
+      nir_ssa_dest_init(&load->instr, &load->dest, load->num_components, NULL);
+      nir_builder_instr_insert(&b->nb, &load->instr);
+      val->def = &load->dest.ssa;
+   } else {
+      unsigned elems = glsl_get_length(type->type);
+      val->elems = ralloc_array(b, struct vtn_ssa_value *, elems);
+      if (glsl_type_is_struct(type->type)) {
+         for (unsigned i = 0; i < elems; i++) {
+            val->elems[i] = _vtn_block_load(b, op, set, binding,
+                                            offset + type->offsets[i],
+                                            indirect, type->members[i]);
+         }
+      } else {
+         for (unsigned i = 0; i < elems; i++) {
+            val->elems[i] = _vtn_block_load(b, op, set, binding,
+                                            offset + i * type->stride,
+                                            indirect, type->array_element);
+         }
+      }
+   }
+
+   return val;
+}
+
+static struct vtn_ssa_value *
+vtn_block_load(struct vtn_builder *b, nir_deref_var *src,
+               struct vtn_type *type, nir_deref *src_tail)
+{
+   unsigned set = src->var->data.descriptor_set;
+
+   nir_ssa_def *binding = nir_imm_int(&b->nb, src->var->data.binding);
+   nir_deref *deref = &src->deref;
+
+   /* The block variable may be an array, in which case the array index adds
+    * an offset to the binding. Figure out that index now.
+    */
+
+   if (deref->child->deref_type == nir_deref_type_array) {
+      deref = deref->child;
+      type = type->array_element;
+      nir_deref_array *deref_array = nir_deref_as_array(deref);
+      if (deref_array->deref_array_type == nir_deref_array_type_direct) {
+         binding = nir_imm_int(&b->nb, src->var->data.binding +
+                                       deref_array->base_offset);
+      } else {
+         binding = nir_iadd(&b->nb, binding, deref_array->indirect.ssa);
+      }
+   }
+
+   unsigned offset = 0;
+   nir_ssa_def *indirect = NULL;
+   while (deref != src_tail) {
+      deref = deref->child;
+      switch (deref->deref_type) {
+      case nir_deref_type_array: {
+         nir_deref_array *deref_array = nir_deref_as_array(deref);
+         if (deref_array->deref_array_type == nir_deref_array_type_direct) {
+            offset += type->stride * deref_array->base_offset;
+         } else {
+            nir_ssa_def *offset = nir_imul(&b->nb, deref_array->indirect.ssa,
+                                           nir_imm_int(&b->nb, type->stride));
+            indirect = indirect ? nir_iadd(&b->nb, indirect, offset) : offset;
+         }
+         type = type->array_element;
+         break;
+      }
+
+      case nir_deref_type_struct: {
+         nir_deref_struct *deref_struct = nir_deref_as_struct(deref);
+         offset += type->offsets[deref_struct->index];
+         type = type->members[deref_struct->index];
+         break;
+      }
+
+      default:
+         unreachable("unknown deref type");
+      }
+   }
+
+   /* TODO SSBO's */
+   nir_intrinsic_op op = indirect ? nir_intrinsic_load_ubo_indirect
+                                  : nir_intrinsic_load_ubo;
+
+   return _vtn_block_load(b, op, set, binding, offset, indirect, type);
+}
+
+/*
+ * Gets the NIR-level deref tail, which may have as a child an array deref
+ * selecting which component due to OpAccessChain supporting per-component
+ * indexing in SPIR-V.
+ */
+
+static nir_deref *
+get_deref_tail(nir_deref_var *deref)
+{
+   nir_deref *cur = &deref->deref;
+   while (!glsl_type_is_vector_or_scalar(cur->type) && cur->child)
+      cur = cur->child;
+
+   return cur;
+}
+
+static nir_ssa_def *vtn_vector_extract(struct vtn_builder *b,
+                                       nir_ssa_def *src, unsigned index);
+
+static nir_ssa_def *vtn_vector_extract_dynamic(struct vtn_builder *b,
+                                               nir_ssa_def *src,
+                                               nir_ssa_def *index);
+
+static struct vtn_ssa_value *
+vtn_variable_load(struct vtn_builder *b, nir_deref_var *src,
+                  struct vtn_type *src_type)
+{
+   nir_deref *src_tail = get_deref_tail(src);
+
+   struct vtn_ssa_value *val;
+   if (src->var->interface_type && src->var->data.mode == nir_var_uniform)
+      val = vtn_block_load(b, src, src_type, src_tail);
+   else
+      val = _vtn_variable_load(b, src, src_type, src_tail);
+
+   if (src_tail->child) {
+      nir_deref_array *vec_deref = nir_deref_as_array(src_tail->child);
+      assert(vec_deref->deref.child == NULL);
+      val->type = vec_deref->deref.type;
+      if (vec_deref->deref_array_type == nir_deref_array_type_direct)
+         val->def = vtn_vector_extract(b, val->def, vec_deref->base_offset);
+      else
+         val->def = vtn_vector_extract_dynamic(b, val->def,
+                                               vec_deref->indirect.ssa);
+   }
+
+   return val;
+}
+
+static nir_ssa_def * vtn_vector_insert(struct vtn_builder *b,
+                                       nir_ssa_def *src, nir_ssa_def *insert,
+                                       unsigned index);
+
+static nir_ssa_def * vtn_vector_insert_dynamic(struct vtn_builder *b,
+                                               nir_ssa_def *src,
+                                               nir_ssa_def *insert,
+                                               nir_ssa_def *index);
+static void
+vtn_variable_store(struct vtn_builder *b, struct vtn_ssa_value *src,
+                   nir_deref_var *dest, struct vtn_type *dest_type)
+{
+   nir_deref *dest_tail = get_deref_tail(dest);
+   if (dest_tail->child) {
+      struct vtn_ssa_value *val = _vtn_variable_load(b, dest, dest_type,
+                                                     dest_tail);
+      nir_deref_array *deref = nir_deref_as_array(dest_tail->child);
+      assert(deref->deref.child == NULL);
+      if (deref->deref_array_type == nir_deref_array_type_direct)
+         val->def = vtn_vector_insert(b, val->def, src->def,
+                                      deref->base_offset);
+      else
+         val->def = vtn_vector_insert_dynamic(b, val->def, src->def,
+                                              deref->indirect.ssa);
+      _vtn_variable_store(b, dest_type, dest, dest_tail, val);
+   } else {
+      _vtn_variable_store(b, dest_type, dest, dest_tail, src);
+   }
+}
+
+static void
+vtn_variable_copy(struct vtn_builder *b, nir_deref_var *src,
+                  nir_deref_var *dest, struct vtn_type *type)
+{
+   nir_deref *src_tail = get_deref_tail(src);
+
+   if (src_tail->child || src->var->interface_type) {
+      assert(get_deref_tail(dest)->child);
+      struct vtn_ssa_value *val = vtn_variable_load(b, src, type);
+      vtn_variable_store(b, val, dest, type);
+   } else {
+      nir_intrinsic_instr *copy =
+         nir_intrinsic_instr_create(b->shader, nir_intrinsic_copy_var);
+      copy->variables[0] = nir_deref_as_var(nir_copy_deref(copy, &dest->deref));
+      copy->variables[1] = nir_deref_as_var(nir_copy_deref(copy, &src->deref));
+
+      nir_builder_instr_insert(&b->nb, &copy->instr);
+   }
+}
+
 static void
 vtn_handle_variables(struct vtn_builder *b, SpvOp opcode,
                      const uint32_t *w, unsigned count)
 {
    switch (opcode) {
    case SpvOpVariable: {
-      const struct glsl_type *type =
+      struct vtn_type *type =
          vtn_value(b, w[1], vtn_value_type_type)->type;
       struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_deref);
 
       nir_variable *var = ralloc(b->shader, nir_variable);
 
-      var->type = type;
+      var->type = type->type;
       var->name = ralloc_strdup(var, val->name);
 
+      bool builtin_block = false;
+      if (type->block) {
+         var->interface_type = type->type;
+         builtin_block = type->builtin_block;
+      } else if (glsl_type_is_array(type->type) &&
+                 (type->array_element->block ||
+                  type->array_element->buffer_block)) {
+         var->interface_type = type->array_element->type;
+         builtin_block = type->array_element->builtin_block;
+      } else {
+         var->interface_type = NULL;
+      }
+
       switch ((SpvStorageClass)w[3]) {
+      case SpvStorageClassUniform:
       case SpvStorageClassUniformConstant:
          var->data.mode = nir_var_uniform;
          var->data.read_only = true;
@@ -484,11 +1260,9 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode,
       case SpvStorageClassFunction:
          var->data.mode = nir_var_local;
          break;
-      case SpvStorageClassUniform:
       case SpvStorageClassWorkgroupLocal:
       case SpvStorageClassWorkgroupGlobal:
       case SpvStorageClassGeneric:
-      case SpvStorageClassPrivate:
       case SpvStorageClassAtomicCounter:
       default:
          unreachable("Unhandled variable storage class");
@@ -500,15 +1274,55 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode,
             vtn_value(b, w[4], vtn_value_type_constant)->constant;
       }
 
-      if (var->data.mode == nir_var_local) {
-         exec_list_push_tail(&b->impl->locals, &var->node);
-      } else {
-         exec_list_push_tail(&b->shader->globals, &var->node);
+      val->deref = nir_deref_var_create(b, var);
+      val->deref_type = type;
+
+      vtn_foreach_decoration(b, val, var_decoration_cb, var);
+
+      if (b->execution_model == SpvExecutionModelFragment &&
+          var->data.mode == nir_var_shader_out) {
+         var->data.location += FRAG_RESULT_DATA0;
+      } else if (b->execution_model == SpvExecutionModelVertex &&
+                 var->data.mode == nir_var_shader_in) {
+         var->data.location += VERT_ATTRIB_GENERIC0;
+      } else if (var->data.mode == nir_var_shader_in ||
+                 var->data.mode == nir_var_shader_out) {
+         var->data.location += VARYING_SLOT_VAR0;
       }
 
-      val->deref = nir_deref_var_create(b->shader, var);
+      /* If this was a uniform block, then we're not going to actually use the
+       * variable (we're only going to use it to compute offsets), so don't
+       * declare it in the shader.
+       */
+      if (var->data.mode == nir_var_uniform && var->interface_type)
+         break;
 
-      vtn_foreach_decoration(b, val, var_decoration_cb, var);
+      /* Builtin blocks are lowered to individual variables during SPIR-V ->
+       * NIR, so don't declare them either.
+       */
+      if (builtin_block)
+         break;
+
+      switch (var->data.mode) {
+      case nir_var_shader_in:
+         exec_list_push_tail(&b->shader->inputs, &var->node);
+         break;
+      case nir_var_shader_out:
+         exec_list_push_tail(&b->shader->outputs, &var->node);
+         break;
+      case nir_var_global:
+         exec_list_push_tail(&b->shader->globals, &var->node);
+         break;
+      case nir_var_local:
+         exec_list_push_tail(&b->impl->locals, &var->node);
+         break;
+      case nir_var_uniform:
+         exec_list_push_tail(&b->shader->uniforms, &var->node);
+         break;
+      case nir_var_system_value:
+         exec_list_push_tail(&b->shader->system_values, &var->node);
+         break;
+      }
       break;
    }
 
@@ -517,6 +1331,7 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode,
       struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_deref);
       nir_deref_var *base = vtn_value(b, w[3], vtn_value_type_deref)->deref;
       val->deref = nir_deref_as_var(nir_copy_deref(b, &base->deref));
+      struct vtn_type *deref_type = vtn_value(b, w[3], vtn_value_type_deref)->deref_type;
 
       nir_deref *tail = &val->deref->deref;
       while (tail->child)
@@ -535,15 +1350,17 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode,
          case GLSL_TYPE_BOOL:
          case GLSL_TYPE_ARRAY: {
             nir_deref_array *deref_arr = nir_deref_array_create(b);
-            if (base_type == GLSL_TYPE_ARRAY) {
-               deref_arr->deref.type = glsl_get_array_element(tail->type);
-            } else if (glsl_type_is_matrix(tail->type)) {
-               deref_arr->deref.type = glsl_get_column_type(tail->type);
+            if (base_type == GLSL_TYPE_ARRAY ||
+                glsl_type_is_matrix(tail->type)) {
+               deref_type = deref_type->array_element;
             } else {
                assert(glsl_type_is_vector(tail->type));
-               deref_arr->deref.type = glsl_scalar_type(base_type);
+               deref_type = ralloc(b, struct vtn_type);
+               deref_type->type = glsl_scalar_type(base_type);
             }
 
+            deref_arr->deref.type = deref_type->type;
+
             if (idx_val->value_type == vtn_value_type_constant) {
                unsigned idx = idx_val->constant->value.u[0];
                deref_arr->deref_array_type = nir_deref_array_type_direct;
@@ -552,7 +1369,8 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode,
                assert(idx_val->value_type == vtn_value_type_ssa);
                deref_arr->deref_array_type = nir_deref_array_type_indirect;
                deref_arr->base_offset = 0;
-               deref_arr->indirect = nir_src_for_ssa(vtn_ssa_value(b, w[1]));
+               deref_arr->indirect =
+                  nir_src_for_ssa(vtn_ssa_value(b, w[1])->def);
             }
             tail->child = &deref_arr->deref;
             break;
@@ -561,8 +1379,9 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode,
          case GLSL_TYPE_STRUCT: {
             assert(idx_val->value_type == vtn_value_type_constant);
             unsigned idx = idx_val->constant->value.u[0];
+            deref_type = deref_type->members[idx];
             nir_deref_struct *deref_struct = nir_deref_struct_create(b, idx);
-            deref_struct->deref.type = glsl_get_struct_field(tail->type, idx);
+            deref_struct->deref.type = deref_type->type;
             tail->child = &deref_struct->deref;
             break;
          }
@@ -571,93 +1390,57 @@ vtn_handle_variables(struct vtn_builder *b, SpvOp opcode,
          }
          tail = tail->child;
       }
+
+      /* For uniform blocks, we don't resolve the access chain until we
+       * actually access the variable, so we need to keep around the original
+       * type of the variable.
+       */
+      if (base->var->interface_type && base->var->data.mode == nir_var_uniform)
+         val->deref_type = vtn_value(b, w[3], vtn_value_type_deref)->deref_type;
+      else
+         val->deref_type = deref_type;
+
+
       break;
    }
 
    case SpvOpCopyMemory: {
       nir_deref_var *dest = vtn_value(b, w[1], vtn_value_type_deref)->deref;
       nir_deref_var *src = vtn_value(b, w[2], vtn_value_type_deref)->deref;
+      struct vtn_type *type =
+         vtn_value(b, w[1], vtn_value_type_deref)->deref_type;
 
-      nir_intrinsic_instr *copy =
-         nir_intrinsic_instr_create(b->shader, nir_intrinsic_copy_var);
-      copy->variables[0] = nir_deref_as_var(nir_copy_deref(copy, &dest->deref));
-      copy->variables[1] = nir_deref_as_var(nir_copy_deref(copy, &src->deref));
-
-      nir_builder_instr_insert(&b->nb, &copy->instr);
+      vtn_variable_copy(b, src, dest, type);
       break;
    }
 
    case SpvOpLoad: {
       nir_deref_var *src = vtn_value(b, w[3], vtn_value_type_deref)->deref;
-      const struct glsl_type *src_type = nir_deref_tail(&src->deref)->type;
+      struct vtn_type *src_type =
+         vtn_value(b, w[3], vtn_value_type_deref)->deref_type;
 
-      if (glsl_get_base_type(src_type) == GLSL_TYPE_SAMPLER) {
+      if (glsl_get_base_type(src_type->type) == GLSL_TYPE_SAMPLER) {
          vtn_push_value(b, w[2], vtn_value_type_deref)->deref = src;
          return;
       }
 
-      assert(glsl_type_is_vector_or_scalar(src_type));
       struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa);
-
-      nir_intrinsic_instr *load =
-         nir_intrinsic_instr_create(b->shader, nir_intrinsic_load_var);
-      load->variables[0] = nir_deref_as_var(nir_copy_deref(load, &src->deref));
-      load->num_components = glsl_get_vector_elements(src_type);
-      nir_ssa_dest_init(&load->instr, &load->dest, load->num_components,
-                        val->name);
-
-      nir_builder_instr_insert(&b->nb, &load->instr);
-      val->type = src_type;
-
-      if (src->var->data.mode == nir_var_uniform &&
-          glsl_get_base_type(src_type) == GLSL_TYPE_BOOL) {
-         /* Uniform boolean loads need to be fixed up since they're defined
-          * to be zero/nonzero rather than NIR_FALSE/NIR_TRUE.
-          */
-         val->ssa = nir_ine(&b->nb, &load->dest.ssa, nir_imm_int(&b->nb, 0));
-      } else {
-         val->ssa = &load->dest.ssa;
-      }
+      val->ssa = vtn_variable_load(b, src, src_type);
       break;
    }
 
-   case SpvOpStore: {
-      nir_deref_var *dest = vtn_value(b, w[1], vtn_value_type_deref)->deref;
-      const struct glsl_type *dest_type = nir_deref_tail(&dest->deref)->type;
-      struct vtn_value *src_val = vtn_untyped_value(b, w[2]);
-      if (src_val->value_type == vtn_value_type_ssa) {
-         assert(glsl_type_is_vector_or_scalar(dest_type));
-         nir_intrinsic_instr *store =
-            nir_intrinsic_instr_create(b->shader, nir_intrinsic_store_var);
-         store->src[0] = nir_src_for_ssa(src_val->ssa);
-         store->variables[0] = nir_deref_as_var(nir_copy_deref(store, &dest->deref));
-         store->num_components = glsl_get_vector_elements(dest_type);
-
-         nir_builder_instr_insert(&b->nb, &store->instr);
-      } else {
-         assert(src_val->value_type == vtn_value_type_constant);
-
-         nir_variable *const_tmp = rzalloc(b->shader, nir_variable);
-         const_tmp->type = dest_type;
-         const_tmp->name = "const_temp";
-         const_tmp->data.mode = nir_var_local;
-         const_tmp->data.read_only = true;
-         exec_list_push_tail(&b->impl->locals, &const_tmp->node);
-
-         nir_intrinsic_instr *copy =
-            nir_intrinsic_instr_create(b->shader, nir_intrinsic_copy_var);
-         copy->variables[0] = nir_deref_as_var(nir_copy_deref(copy, &dest->deref));
-         copy->variables[1] = nir_deref_var_create(copy, const_tmp);
-
-         nir_builder_instr_insert(&b->nb, &copy->instr);
-      }
+   case SpvOpStore: {
+      nir_deref_var *dest = vtn_value(b, w[1], vtn_value_type_deref)->deref;
+      struct vtn_type *dest_type =
+         vtn_value(b, w[1], vtn_value_type_deref)->deref_type;
+      struct vtn_ssa_value *src = vtn_ssa_value(b, w[2]);
+      vtn_variable_store(b, src, dest, dest_type);
       break;
    }
 
-   case SpvOpVariableArray:
    case SpvOpCopyMemorySized:
    case SpvOpArrayLength:
-   case SpvOpImagePointer:
+   case SpvOpImageTexelPointer:
    default:
       unreachable("Unhandled opcode");
    }
@@ -670,11 +1453,48 @@ vtn_handle_function_call(struct vtn_builder *b, SpvOp opcode,
    unreachable("Unhandled opcode");
 }
 
+static struct vtn_ssa_value *
+vtn_create_ssa_value(struct vtn_builder *b, const struct glsl_type *type)
+{
+   struct vtn_ssa_value *val = rzalloc(b, struct vtn_ssa_value);
+   val->type = type;
+
+   if (!glsl_type_is_vector_or_scalar(type)) {
+      unsigned elems = glsl_get_length(type);
+      val->elems = ralloc_array(b, struct vtn_ssa_value *, elems);
+      for (unsigned i = 0; i < elems; i++) {
+         const struct glsl_type *child_type;
+
+         switch (glsl_get_base_type(type)) {
+         case GLSL_TYPE_INT:
+         case GLSL_TYPE_UINT:
+         case GLSL_TYPE_BOOL:
+         case GLSL_TYPE_FLOAT:
+         case GLSL_TYPE_DOUBLE:
+            child_type = glsl_get_column_type(type);
+            break;
+         case GLSL_TYPE_ARRAY:
+            child_type = glsl_get_array_element(type);
+            break;
+         case GLSL_TYPE_STRUCT:
+            child_type = glsl_get_struct_field(type, i);
+            break;
+         default:
+            unreachable("unkown base type");
+         }
+
+         val->elems[i] = vtn_create_ssa_value(b, child_type);
+      }
+   }
+
+   return val;
+}
+
 static nir_tex_src
 vtn_tex_src(struct vtn_builder *b, unsigned index, nir_tex_src_type type)
 {
    nir_tex_src src;
-   src.src = nir_src_for_ssa(vtn_value(b, index, vtn_value_type_ssa)->ssa);
+   src.src = nir_src_for_ssa(vtn_value(b, index, vtn_value_type_ssa)->ssa->def);
    src.src_type = type;
    return src;
 }
@@ -689,80 +1509,67 @@ vtn_handle_texture(struct vtn_builder *b, SpvOp opcode,
    nir_tex_src srcs[8]; /* 8 should be enough */
    nir_tex_src *p = srcs;
 
+   unsigned idx = 4;
+
    unsigned coord_components = 0;
    switch (opcode) {
-   case SpvOpTextureSample:
-   case SpvOpTextureSampleDref:
-   case SpvOpTextureSampleLod:
-   case SpvOpTextureSampleProj:
-   case SpvOpTextureSampleGrad:
-   case SpvOpTextureSampleOffset:
-   case SpvOpTextureSampleProjLod:
-   case SpvOpTextureSampleProjGrad:
-   case SpvOpTextureSampleLodOffset:
-   case SpvOpTextureSampleProjOffset:
-   case SpvOpTextureSampleGradOffset:
-   case SpvOpTextureSampleProjLodOffset:
-   case SpvOpTextureSampleProjGradOffset:
-   case SpvOpTextureFetchTexelLod:
-   case SpvOpTextureFetchTexelOffset:
-   case SpvOpTextureFetchSample:
-   case SpvOpTextureFetchTexel:
-   case SpvOpTextureGather:
-   case SpvOpTextureGatherOffset:
-   case SpvOpTextureGatherOffsets:
-   case SpvOpTextureQueryLod: {
+   case SpvOpImageSampleImplicitLod:
+   case SpvOpImageSampleExplicitLod:
+   case SpvOpImageSampleDrefImplicitLod:
+   case SpvOpImageSampleDrefExplicitLod:
+   case SpvOpImageSampleProjImplicitLod:
+   case SpvOpImageSampleProjExplicitLod:
+   case SpvOpImageSampleProjDrefImplicitLod:
+   case SpvOpImageSampleProjDrefExplicitLod:
+   case SpvOpImageFetch:
+   case SpvOpImageGather:
+   case SpvOpImageDrefGather:
+   case SpvOpImageQueryLod: {
       /* All these types have the coordinate as their first real argument */
-      struct vtn_value *coord = vtn_value(b, w[4], vtn_value_type_ssa);
+      struct vtn_ssa_value *coord = vtn_ssa_value(b, w[idx++]);
       coord_components = glsl_get_vector_elements(coord->type);
-      p->src = nir_src_for_ssa(coord->ssa);
+      p->src = nir_src_for_ssa(coord->def);
       p->src_type = nir_tex_src_coord;
       p++;
       break;
    }
+
    default:
       break;
    }
 
    nir_texop texop;
    switch (opcode) {
-   case SpvOpTextureSample:
+   case SpvOpImageSampleImplicitLod:
       texop = nir_texop_tex;
-
-      if (count == 6) {
-         texop = nir_texop_txb;
-         *p++ = vtn_tex_src(b, w[5], nir_tex_src_bias);
-      }
       break;
 
-   case SpvOpTextureSampleDref:
-   case SpvOpTextureSampleLod:
-   case SpvOpTextureSampleProj:
-   case SpvOpTextureSampleGrad:
-   case SpvOpTextureSampleOffset:
-   case SpvOpTextureSampleProjLod:
-   case SpvOpTextureSampleProjGrad:
-   case SpvOpTextureSampleLodOffset:
-   case SpvOpTextureSampleProjOffset:
-   case SpvOpTextureSampleGradOffset:
-   case SpvOpTextureSampleProjLodOffset:
-   case SpvOpTextureSampleProjGradOffset:
-   case SpvOpTextureFetchTexelLod:
-   case SpvOpTextureFetchTexelOffset:
-   case SpvOpTextureFetchSample:
-   case SpvOpTextureFetchTexel:
-   case SpvOpTextureGather:
-   case SpvOpTextureGatherOffset:
-   case SpvOpTextureGatherOffsets:
-   case SpvOpTextureQuerySizeLod:
-   case SpvOpTextureQuerySize:
-   case SpvOpTextureQueryLod:
-   case SpvOpTextureQueryLevels:
-   case SpvOpTextureQuerySamples:
+   case SpvOpImageSampleExplicitLod:
+   case SpvOpImageSampleDrefImplicitLod:
+   case SpvOpImageSampleDrefExplicitLod:
+   case SpvOpImageSampleProjImplicitLod:
+   case SpvOpImageSampleProjExplicitLod:
+   case SpvOpImageSampleProjDrefImplicitLod:
+   case SpvOpImageSampleProjDrefExplicitLod:
+   case SpvOpImageFetch:
+   case SpvOpImageGather:
+   case SpvOpImageDrefGather:
+   case SpvOpImageQuerySizeLod:
+   case SpvOpImageQuerySize:
+   case SpvOpImageQueryLod:
+   case SpvOpImageQueryLevels:
+   case SpvOpImageQuerySamples:
    default:
       unreachable("Unhandled opcode");
    }
 
+   /* From now on, the remaining sources are "Optional Image Operands." */
+   if (idx < count) {
+      /* XXX handle these (bias, lod, etc.) */
+      assert(0);
+   }
+
+
    nir_tex_instr *instr = nir_tex_instr_create(b->shader, p - srcs);
 
    const struct glsl_type *sampler_type = nir_deref_tail(&sampler->deref)->type;
@@ -783,19 +1590,237 @@ vtn_handle_texture(struct vtn_builder *b, SpvOp opcode,
    instr->is_array = glsl_sampler_type_is_array(sampler_type);
    instr->is_shadow = glsl_sampler_type_is_shadow(sampler_type);
 
-   instr->sampler = sampler;
+   instr->sampler = nir_deref_as_var(nir_copy_deref(instr, &sampler->deref));
 
    nir_ssa_dest_init(&instr->instr, &instr->dest, 4, NULL);
-   val->ssa = &instr->dest.ssa;
+   val->ssa = vtn_create_ssa_value(b, glsl_vector_type(GLSL_TYPE_FLOAT, 4));
+   val->ssa->def = &instr->dest.ssa;
 
    nir_builder_instr_insert(&b->nb, &instr->instr);
 }
 
+
+static nir_alu_instr *
+create_vec(void *mem_ctx, unsigned num_components)
+{
+   nir_op op;
+   switch (num_components) {
+   case 1: op = nir_op_fmov; break;
+   case 2: op = nir_op_vec2; break;
+   case 3: op = nir_op_vec3; break;
+   case 4: op = nir_op_vec4; break;
+   default: unreachable("bad vector size");
+   }
+
+   nir_alu_instr *vec = nir_alu_instr_create(mem_ctx, op);
+   nir_ssa_dest_init(&vec->instr, &vec->dest.dest, num_components, NULL);
+   vec->dest.write_mask = (1 << num_components) - 1;
+
+   return vec;
+}
+
+static struct vtn_ssa_value *
+vtn_transpose(struct vtn_builder *b, struct vtn_ssa_value *src)
+{
+   if (src->transposed)
+      return src->transposed;
+
+   struct vtn_ssa_value *dest =
+      vtn_create_ssa_value(b, glsl_transposed_type(src->type));
+
+   for (unsigned i = 0; i < glsl_get_matrix_columns(dest->type); i++) {
+      nir_alu_instr *vec = create_vec(b, glsl_get_matrix_columns(src->type));
+      if (glsl_type_is_vector_or_scalar(src->type)) {
+          vec->src[0].src = nir_src_for_ssa(src->def);
+          vec->src[0].swizzle[0] = i;
+      } else {
+         for (unsigned j = 0; j < glsl_get_matrix_columns(src->type); j++) {
+            vec->src[j].src = nir_src_for_ssa(src->elems[j]->def);
+            vec->src[j].swizzle[0] = i;
+         }
+      }
+      nir_builder_instr_insert(&b->nb, &vec->instr);
+      dest->elems[i]->def = &vec->dest.dest.ssa;
+   }
+
+   dest->transposed = src;
+
+   return dest;
+}
+
+/*
+ * Normally, column vectors in SPIR-V correspond to a single NIR SSA
+ * definition. But for matrix multiplies, we want to do one routine for
+ * multiplying a matrix by a matrix and then pretend that vectors are matrices
+ * with one column. So we "wrap" these things, and unwrap the result before we
+ * send it off.
+ */
+
+static struct vtn_ssa_value *
+vtn_wrap_matrix(struct vtn_builder *b, struct vtn_ssa_value *val)
+{
+   if (val == NULL)
+      return NULL;
+
+   if (glsl_type_is_matrix(val->type))
+      return val;
+
+   struct vtn_ssa_value *dest = rzalloc(b, struct vtn_ssa_value);
+   dest->type = val->type;
+   dest->elems = ralloc_array(b, struct vtn_ssa_value *, 1);
+   dest->elems[0] = val;
+
+   return dest;
+}
+
+static struct vtn_ssa_value *
+vtn_unwrap_matrix(struct vtn_ssa_value *val)
+{
+   if (glsl_type_is_matrix(val->type))
+         return val;
+
+   return val->elems[0];
+}
+
+static struct vtn_ssa_value *
+vtn_matrix_multiply(struct vtn_builder *b,
+                    struct vtn_ssa_value *_src0, struct vtn_ssa_value *_src1)
+{
+
+   struct vtn_ssa_value *src0 = vtn_wrap_matrix(b, _src0);
+   struct vtn_ssa_value *src1 = vtn_wrap_matrix(b, _src1);
+   struct vtn_ssa_value *src0_transpose = vtn_wrap_matrix(b, _src0->transposed);
+   struct vtn_ssa_value *src1_transpose = vtn_wrap_matrix(b, _src1->transposed);
+
+   unsigned src0_rows = glsl_get_vector_elements(src0->type);
+   unsigned src0_columns = glsl_get_matrix_columns(src0->type);
+   unsigned src1_columns = glsl_get_matrix_columns(src1->type);
+
+   struct vtn_ssa_value *dest =
+      vtn_create_ssa_value(b, glsl_matrix_type(glsl_get_base_type(src0->type),
+                                               src0_rows, src1_columns));
+
+   dest = vtn_wrap_matrix(b, dest);
+
+   bool transpose_result = false;
+   if (src0_transpose && src1_transpose) {
+      /* transpose(A) * transpose(B) = transpose(B * A) */
+      src1 = src0_transpose;
+      src0 = src1_transpose;
+      src0_transpose = NULL;
+      src1_transpose = NULL;
+      transpose_result = true;
+   }
+
+   if (src0_transpose && !src1_transpose &&
+       glsl_get_base_type(src0->type) == GLSL_TYPE_FLOAT) {
+      /* We already have the rows of src0 and the columns of src1 available,
+       * so we can just take the dot product of each row with each column to
+       * get the result.
+       */
+
+      for (unsigned i = 0; i < src1_columns; i++) {
+         nir_alu_instr *vec = create_vec(b, src0_rows);
+         for (unsigned j = 0; j < src0_rows; j++) {
+            vec->src[j].src =
+               nir_src_for_ssa(nir_fdot(&b->nb, src0_transpose->elems[j]->def,
+                                        src1->elems[i]->def));
+         }
+
+         nir_builder_instr_insert(&b->nb, &vec->instr);
+         dest->elems[i]->def = &vec->dest.dest.ssa;
+      }
+   } else {
+      /* We don't handle the case where src1 is transposed but not src0, since
+       * the general case only uses individual components of src1 so the
+       * optimizer should chew through the transpose we emitted for src1.
+       */
+
+      for (unsigned i = 0; i < src1_columns; i++) {
+         /* dest[i] = sum(src0[j] * src1[i][j] for all j) */
+         dest->elems[i]->def =
+            nir_fmul(&b->nb, src0->elems[0]->def,
+                     vtn_vector_extract(b, src1->elems[i]->def, 0));
+         for (unsigned j = 1; j < src0_columns; j++) {
+            dest->elems[i]->def =
+               nir_fadd(&b->nb, dest->elems[i]->def,
+                        nir_fmul(&b->nb, src0->elems[j]->def,
+                                 vtn_vector_extract(b,
+                                                    src1->elems[i]->def, j)));
+         }
+      }
+   }
+
+   dest = vtn_unwrap_matrix(dest);
+
+   if (transpose_result)
+      dest = vtn_transpose(b, dest);
+
+   return dest;
+}
+
+static struct vtn_ssa_value *
+vtn_mat_times_scalar(struct vtn_builder *b,
+                     struct vtn_ssa_value *mat,
+                     nir_ssa_def *scalar)
+{
+   struct vtn_ssa_value *dest = vtn_create_ssa_value(b, mat->type);
+   for (unsigned i = 0; i < glsl_get_matrix_columns(mat->type); i++) {
+      if (glsl_get_base_type(mat->type) == GLSL_TYPE_FLOAT)
+         dest->elems[i]->def = nir_fmul(&b->nb, mat->elems[i]->def, scalar);
+      else
+         dest->elems[i]->def = nir_imul(&b->nb, mat->elems[i]->def, scalar);
+   }
+
+   return dest;
+}
+
 static void
 vtn_handle_matrix_alu(struct vtn_builder *b, SpvOp opcode,
                       const uint32_t *w, unsigned count)
 {
-   unreachable("Matrix math not handled");
+   struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa);
+
+   switch (opcode) {
+   case SpvOpTranspose: {
+      struct vtn_ssa_value *src = vtn_ssa_value(b, w[3]);
+      val->ssa = vtn_transpose(b, src);
+      break;
+   }
+
+   case SpvOpOuterProduct: {
+      struct vtn_ssa_value *src0 = vtn_ssa_value(b, w[3]);
+      struct vtn_ssa_value *src1 = vtn_ssa_value(b, w[4]);
+
+      val->ssa = vtn_matrix_multiply(b, src0, vtn_transpose(b, src1));
+      break;
+   }
+
+   case SpvOpMatrixTimesScalar: {
+      struct vtn_ssa_value *mat = vtn_ssa_value(b, w[3]);
+      struct vtn_ssa_value *scalar = vtn_ssa_value(b, w[4]);
+
+      if (mat->transposed) {
+         val->ssa = vtn_transpose(b, vtn_mat_times_scalar(b, mat->transposed,
+                                                          scalar->def));
+      } else {
+         val->ssa = vtn_mat_times_scalar(b, mat, scalar->def);
+      }
+      break;
+   }
+
+   case SpvOpVectorTimesMatrix:
+   case SpvOpMatrixTimesVector:
+   case SpvOpMatrixTimesMatrix: {
+      struct vtn_ssa_value *src0 = vtn_ssa_value(b, w[3]);
+      struct vtn_ssa_value *src1 = vtn_ssa_value(b, w[4]);
+
+      val->ssa = vtn_matrix_multiply(b, src0, src1);
+      break;
+   }
+
+   default: unreachable("unknown matrix opcode");
+   }
 }
 
 static void
@@ -803,13 +1828,15 @@ vtn_handle_alu(struct vtn_builder *b, SpvOp opcode,
                const uint32_t *w, unsigned count)
 {
    struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa);
-   val->type = vtn_value(b, w[1], vtn_value_type_type)->type;
+   const struct glsl_type *type =
+      vtn_value(b, w[1], vtn_value_type_type)->type->type;
+   val->ssa = vtn_create_ssa_value(b, type);
 
    /* Collect the various SSA sources */
    unsigned num_inputs = count - 3;
    nir_ssa_def *src[4];
    for (unsigned i = 0; i < num_inputs; i++)
-      src[i] = vtn_ssa_value(b, w[i + 3]);
+      src[i] = vtn_ssa_value(b, w[i + 3])->def;
 
    /* Indicates that the first two arguments should be swapped.  This is
     * used for implementing greater-than and less-than-or-equal.
@@ -868,7 +1895,8 @@ vtn_handle_alu(struct vtn_builder *b, SpvOp opcode,
    case SpvOpShiftRightArithmetic:  op = nir_op_ishr;    break;
    case SpvOpShiftLeftLogical:      op = nir_op_ishl;    break;
    case SpvOpLogicalOr:             op = nir_op_ior;     break;
-   case SpvOpLogicalXor:            op = nir_op_ixor;    break;
+   case SpvOpLogicalEqual:          op = nir_op_ieq;     break;
+   case SpvOpLogicalNotEqual:       op = nir_op_ine;     break;
    case SpvOpLogicalAnd:            op = nir_op_iand;    break;
    case SpvOpBitwiseOr:             op = nir_op_ior;     break;
    case SpvOpBitwiseXor:            op = nir_op_ixor;    break;
@@ -921,24 +1949,24 @@ vtn_handle_alu(struct vtn_builder *b, SpvOp opcode,
    case SpvOpDPdxCoarse:   op = nir_op_fddx_coarse;   break;
    case SpvOpDPdyCoarse:   op = nir_op_fddy_coarse;   break;
    case SpvOpFwidth:
-      val->ssa = nir_fadd(&b->nb,
-                          nir_fabs(&b->nb, nir_fddx(&b->nb, src[0])),
-                          nir_fabs(&b->nb, nir_fddx(&b->nb, src[1])));
+      val->ssa->def = nir_fadd(&b->nb,
+                               nir_fabs(&b->nb, nir_fddx(&b->nb, src[0])),
+                               nir_fabs(&b->nb, nir_fddx(&b->nb, src[1])));
       return;
    case SpvOpFwidthFine:
-      val->ssa = nir_fadd(&b->nb,
-                          nir_fabs(&b->nb, nir_fddx_fine(&b->nb, src[0])),
-                          nir_fabs(&b->nb, nir_fddx_fine(&b->nb, src[1])));
+      val->ssa->def = nir_fadd(&b->nb,
+                               nir_fabs(&b->nb, nir_fddx_fine(&b->nb, src[0])),
+                               nir_fabs(&b->nb, nir_fddx_fine(&b->nb, src[1])));
       return;
    case SpvOpFwidthCoarse:
-      val->ssa = nir_fadd(&b->nb,
-                          nir_fabs(&b->nb, nir_fddx_coarse(&b->nb, src[0])),
-                          nir_fabs(&b->nb, nir_fddx_coarse(&b->nb, src[1])));
+      val->ssa->def = nir_fadd(&b->nb,
+                               nir_fabs(&b->nb, nir_fddx_coarse(&b->nb, src[0])),
+                               nir_fabs(&b->nb, nir_fddx_coarse(&b->nb, src[1])));
       return;
 
    case SpvOpVectorTimesScalar:
       /* The builder will take care of splatting for us. */
-      val->ssa = nir_fmul(&b->nb, src[0], src[1]);
+      val->ssa->def = nir_fmul(&b->nb, src[0], src[1]);
       return;
 
    case SpvOpSRem:
@@ -965,8 +1993,9 @@ vtn_handle_alu(struct vtn_builder *b, SpvOp opcode,
 
    nir_alu_instr *instr = nir_alu_instr_create(b->shader, op);
    nir_ssa_dest_init(&instr->instr, &instr->dest.dest,
-                     glsl_get_vector_elements(val->type), val->name);
-   val->ssa = &instr->dest.dest.ssa;
+                     glsl_get_vector_elements(type), val->name);
+   instr->dest.write_mask = (1 << glsl_get_vector_elements(type)) - 1;
+   val->ssa->def = &instr->dest.dest.ssa;
 
    for (unsigned i = 0; i < nir_op_infos[op].num_inputs; i++)
       instr->src[i].src = nir_src_for_ssa(src[i]);
@@ -974,6 +2003,350 @@ vtn_handle_alu(struct vtn_builder *b, SpvOp opcode,
    nir_builder_instr_insert(&b->nb, &instr->instr);
 }
 
+static nir_ssa_def *
+vtn_vector_extract(struct vtn_builder *b, nir_ssa_def *src, unsigned index)
+{
+   unsigned swiz[4] = { index };
+   return nir_swizzle(&b->nb, src, swiz, 1, true);
+}
+
+
+static nir_ssa_def *
+vtn_vector_insert(struct vtn_builder *b, nir_ssa_def *src, nir_ssa_def *insert,
+                  unsigned index)
+{
+   nir_alu_instr *vec = create_vec(b->shader, src->num_components);
+
+   for (unsigned i = 0; i < src->num_components; i++) {
+      if (i == index) {
+         vec->src[i].src = nir_src_for_ssa(insert);
+      } else {
+         vec->src[i].src = nir_src_for_ssa(src);
+         vec->src[i].swizzle[0] = i;
+      }
+   }
+
+   nir_builder_instr_insert(&b->nb, &vec->instr);
+
+   return &vec->dest.dest.ssa;
+}
+
+static nir_ssa_def *
+vtn_vector_extract_dynamic(struct vtn_builder *b, nir_ssa_def *src,
+                           nir_ssa_def *index)
+{
+   nir_ssa_def *dest = vtn_vector_extract(b, src, 0);
+   for (unsigned i = 1; i < src->num_components; i++)
+      dest = nir_bcsel(&b->nb, nir_ieq(&b->nb, index, nir_imm_int(&b->nb, i)),
+                       vtn_vector_extract(b, src, i), dest);
+
+   return dest;
+}
+
+static nir_ssa_def *
+vtn_vector_insert_dynamic(struct vtn_builder *b, nir_ssa_def *src,
+                          nir_ssa_def *insert, nir_ssa_def *index)
+{
+   nir_ssa_def *dest = vtn_vector_insert(b, src, insert, 0);
+   for (unsigned i = 1; i < src->num_components; i++)
+      dest = nir_bcsel(&b->nb, nir_ieq(&b->nb, index, nir_imm_int(&b->nb, i)),
+                       vtn_vector_insert(b, src, insert, i), dest);
+
+   return dest;
+}
+
+static nir_ssa_def *
+vtn_vector_shuffle(struct vtn_builder *b, unsigned num_components,
+                   nir_ssa_def *src0, nir_ssa_def *src1,
+                   const uint32_t *indices)
+{
+   nir_alu_instr *vec = create_vec(b->shader, num_components);
+
+   nir_ssa_undef_instr *undef = nir_ssa_undef_instr_create(b->shader, 1);
+   nir_builder_instr_insert(&b->nb, &undef->instr);
+
+   for (unsigned i = 0; i < num_components; i++) {
+      uint32_t index = indices[i];
+      if (index == 0xffffffff) {
+         vec->src[i].src = nir_src_for_ssa(&undef->def);
+      } else if (index < src0->num_components) {
+         vec->src[i].src = nir_src_for_ssa(src0);
+         vec->src[i].swizzle[0] = index;
+      } else {
+         vec->src[i].src = nir_src_for_ssa(src1);
+         vec->src[i].swizzle[0] = index - src0->num_components;
+      }
+   }
+
+   nir_builder_instr_insert(&b->nb, &vec->instr);
+
+   return &vec->dest.dest.ssa;
+}
+
+/*
+ * Concatentates a number of vectors/scalars together to produce a vector
+ */
+static nir_ssa_def *
+vtn_vector_construct(struct vtn_builder *b, unsigned num_components,
+                     unsigned num_srcs, nir_ssa_def **srcs)
+{
+   nir_alu_instr *vec = create_vec(b->shader, num_components);
+
+   unsigned dest_idx = 0;
+   for (unsigned i = 0; i < num_srcs; i++) {
+      nir_ssa_def *src = srcs[i];
+      for (unsigned j = 0; j < src->num_components; j++) {
+         vec->src[dest_idx].src = nir_src_for_ssa(src);
+         vec->src[dest_idx].swizzle[0] = j;
+         dest_idx++;
+      }
+   }
+
+   nir_builder_instr_insert(&b->nb, &vec->instr);
+
+   return &vec->dest.dest.ssa;
+}
+
+static struct vtn_ssa_value *
+vtn_composite_copy(void *mem_ctx, struct vtn_ssa_value *src)
+{
+   struct vtn_ssa_value *dest = rzalloc(mem_ctx, struct vtn_ssa_value);
+   dest->type = src->type;
+
+   if (glsl_type_is_vector_or_scalar(src->type)) {
+      dest->def = src->def;
+   } else {
+      unsigned elems = glsl_get_length(src->type);
+
+      dest->elems = ralloc_array(mem_ctx, struct vtn_ssa_value *, elems);
+      for (unsigned i = 0; i < elems; i++)
+         dest->elems[i] = vtn_composite_copy(mem_ctx, src->elems[i]);
+   }
+
+   return dest;
+}
+
+static struct vtn_ssa_value *
+vtn_composite_insert(struct vtn_builder *b, struct vtn_ssa_value *src,
+                     struct vtn_ssa_value *insert, const uint32_t *indices,
+                     unsigned num_indices)
+{
+   struct vtn_ssa_value *dest = vtn_composite_copy(b, src);
+
+   struct vtn_ssa_value *cur = dest;
+   unsigned i;
+   for (i = 0; i < num_indices - 1; i++) {
+      cur = cur->elems[indices[i]];
+   }
+
+   if (glsl_type_is_vector_or_scalar(cur->type)) {
+      /* According to the SPIR-V spec, OpCompositeInsert may work down to
+       * the component granularity. In that case, the last index will be
+       * the index to insert the scalar into the vector.
+       */
+
+      cur->def = vtn_vector_insert(b, cur->def, insert->def, indices[i]);
+   } else {
+      cur->elems[indices[i]] = insert;
+   }
+
+   return dest;
+}
+
+static struct vtn_ssa_value *
+vtn_composite_extract(struct vtn_builder *b, struct vtn_ssa_value *src,
+                      const uint32_t *indices, unsigned num_indices)
+{
+   struct vtn_ssa_value *cur = src;
+   for (unsigned i = 0; i < num_indices; i++) {
+      if (glsl_type_is_vector_or_scalar(cur->type)) {
+         assert(i == num_indices - 1);
+         /* According to the SPIR-V spec, OpCompositeExtract may work down to
+          * the component granularity. The last index will be the index of the
+          * vector to extract.
+          */
+
+         struct vtn_ssa_value *ret = rzalloc(b, struct vtn_ssa_value);
+         ret->type = glsl_scalar_type(glsl_get_base_type(cur->type));
+         ret->def = vtn_vector_extract(b, cur->def, indices[i]);
+         return ret;
+      }
+   }
+
+   return cur;
+}
+
+static void
+vtn_handle_composite(struct vtn_builder *b, SpvOp opcode,
+                     const uint32_t *w, unsigned count)
+{
+   struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa);
+   const struct glsl_type *type =
+      vtn_value(b, w[1], vtn_value_type_type)->type->type;
+   val->ssa = vtn_create_ssa_value(b, type);
+
+   switch (opcode) {
+   case SpvOpVectorExtractDynamic:
+      val->ssa->def = vtn_vector_extract_dynamic(b, vtn_ssa_value(b, w[3])->def,
+                                                 vtn_ssa_value(b, w[4])->def);
+      break;
+
+   case SpvOpVectorInsertDynamic:
+      val->ssa->def = vtn_vector_insert_dynamic(b, vtn_ssa_value(b, w[3])->def,
+                                                vtn_ssa_value(b, w[4])->def,
+                                                vtn_ssa_value(b, w[5])->def);
+      break;
+
+   case SpvOpVectorShuffle:
+      val->ssa->def = vtn_vector_shuffle(b, glsl_get_vector_elements(type),
+                                         vtn_ssa_value(b, w[3])->def,
+                                         vtn_ssa_value(b, w[4])->def,
+                                         w + 5);
+      break;
+
+   case SpvOpCompositeConstruct: {
+      unsigned elems = count - 3;
+      if (glsl_type_is_vector_or_scalar(type)) {
+         nir_ssa_def *srcs[4];
+         for (unsigned i = 0; i < elems; i++)
+            srcs[i] = vtn_ssa_value(b, w[3 + i])->def;
+         val->ssa->def =
+            vtn_vector_construct(b, glsl_get_vector_elements(type),
+                                 elems, srcs);
+      } else {
+         val->ssa->elems = ralloc_array(b, struct vtn_ssa_value *, elems);
+         for (unsigned i = 0; i < elems; i++)
+            val->ssa->elems[i] = vtn_ssa_value(b, w[3 + i]);
+      }
+      break;
+   }
+   case SpvOpCompositeExtract:
+      val->ssa = vtn_composite_extract(b, vtn_ssa_value(b, w[3]),
+                                       w + 4, count - 4);
+      break;
+
+   case SpvOpCompositeInsert:
+      val->ssa = vtn_composite_insert(b, vtn_ssa_value(b, w[4]),
+                                      vtn_ssa_value(b, w[3]),
+                                      w + 5, count - 5);
+      break;
+
+   case SpvOpCopyObject:
+      val->ssa = vtn_composite_copy(b, vtn_ssa_value(b, w[3]));
+      break;
+
+   default:
+      unreachable("unknown composite operation");
+   }
+}
+
+static void
+vtn_phi_node_init(struct vtn_builder *b, struct vtn_ssa_value *val)
+{
+   if (glsl_type_is_vector_or_scalar(val->type)) {
+      nir_phi_instr *phi = nir_phi_instr_create(b->shader);
+      nir_ssa_dest_init(&phi->instr, &phi->dest,
+                        glsl_get_vector_elements(val->type), NULL);
+      exec_list_make_empty(&phi->srcs);
+      nir_builder_instr_insert(&b->nb, &phi->instr);
+      val->def = &phi->dest.ssa;
+   } else {
+      unsigned elems = glsl_get_length(val->type);
+      for (unsigned i = 0; i < elems; i++)
+         vtn_phi_node_init(b, val->elems[i]);
+   }
+}
+
+static struct vtn_ssa_value *
+vtn_phi_node_create(struct vtn_builder *b, const struct glsl_type *type)
+{
+   struct vtn_ssa_value *val = vtn_create_ssa_value(b, type);
+   vtn_phi_node_init(b, val);
+   return val;
+}
+
+static void
+vtn_handle_phi_first_pass(struct vtn_builder *b, const uint32_t *w)
+{
+   struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_ssa);
+   const struct glsl_type *type =
+      vtn_value(b, w[1], vtn_value_type_type)->type->type;
+   val->ssa = vtn_phi_node_create(b, type);
+}
+
+static void
+vtn_phi_node_add_src(struct vtn_ssa_value *phi, const nir_block *pred,
+                     struct vtn_ssa_value *val)
+{
+   assert(phi->type == val->type);
+   if (glsl_type_is_vector_or_scalar(phi->type)) {
+      nir_phi_instr *phi_instr = nir_instr_as_phi(phi->def->parent_instr);
+      nir_phi_src *src = ralloc(phi_instr, nir_phi_src);
+      src->pred = (nir_block *) pred;
+      src->src = nir_src_for_ssa(val->def);
+      exec_list_push_tail(&phi_instr->srcs, &src->node);
+   } else {
+      unsigned elems = glsl_get_length(phi->type);
+      for (unsigned i = 0; i < elems; i++)
+         vtn_phi_node_add_src(phi->elems[i], pred, val->elems[i]);
+   }
+}
+
+static struct vtn_ssa_value *
+vtn_get_phi_node_src(struct vtn_builder *b, nir_block *block,
+                     const struct glsl_type *type, const uint32_t *w,
+                     unsigned count)
+{
+   struct hash_entry *entry = _mesa_hash_table_search(b->block_table, block);
+   if (entry) {
+      struct vtn_block *spv_block = entry->data;
+      for (unsigned off = 4; off < count; off += 2) {
+         if (spv_block == vtn_value(b, w[off], vtn_value_type_block)->block) {
+            return vtn_ssa_value(b, w[off - 1]);
+         }
+      }
+   }
+
+   b->nb.cursor = nir_before_block(block);
+   struct vtn_ssa_value *phi = vtn_phi_node_create(b, type);
+
+   struct set_entry *entry2;
+   set_foreach(block->predecessors, entry2) {
+      nir_block *pred = (nir_block *) entry2->key;
+      struct vtn_ssa_value *val = vtn_get_phi_node_src(b, pred, type, w,
+                                                       count);
+      vtn_phi_node_add_src(phi, pred, val);
+   }
+
+   return phi;
+}
+
+static bool
+vtn_handle_phi_second_pass(struct vtn_builder *b, SpvOp opcode,
+                           const uint32_t *w, unsigned count)
+{
+   if (opcode == SpvOpLabel) {
+      b->block = vtn_value(b, w[1], vtn_value_type_block)->block;
+      return true;
+   }
+
+   if (opcode != SpvOpPhi)
+      return true;
+
+   struct vtn_ssa_value *phi = vtn_value(b, w[2], vtn_value_type_ssa)->ssa;
+
+   struct set_entry *entry;
+   set_foreach(b->block->block->predecessors, entry) {
+      nir_block *pred = (nir_block *) entry->key;
+
+      struct vtn_ssa_value *val = vtn_get_phi_node_src(b, pred, phi->type, w,
+                                                       count);
+      vtn_phi_node_add_src(phi, pred, val);
+   }
+
+   return true;
+}
+
 static bool
 vtn_handle_preamble_instruction(struct vtn_builder *b, SpvOp opcode,
                                 const uint32_t *w, unsigned count)
@@ -981,11 +2354,19 @@ vtn_handle_preamble_instruction(struct vtn_builder *b, SpvOp opcode,
    switch (opcode) {
    case SpvOpSource:
    case SpvOpSourceExtension:
-   case SpvOpCompileFlag:
    case SpvOpExtension:
       /* Unhandled, but these are for debug so that's ok. */
       break;
 
+   case SpvOpCapability:
+      /*
+       * TODO properly handle these and give a real error if asking for too
+       * much.
+       */
+      assert(w[1] == SpvCapabilityMatrix ||
+             w[1] == SpvCapabilityShader);
+      break;
+
    case SpvOpExtInstImport:
       vtn_handle_extension(b, opcode, w, count);
       break;
@@ -1002,7 +2383,7 @@ vtn_handle_preamble_instruction(struct vtn_builder *b, SpvOp opcode,
       break;
 
    case SpvOpExecutionMode:
-      unreachable("Execution modes not yet implemented");
+      /* TODO */
       break;
 
    case SpvOpString:
@@ -1035,7 +2416,9 @@ vtn_handle_preamble_instruction(struct vtn_builder *b, SpvOp opcode,
    case SpvOpTypeFloat:
    case SpvOpTypeVector:
    case SpvOpTypeMatrix:
+   case SpvOpTypeImage:
    case SpvOpTypeSampler:
+   case SpvOpTypeSampledImage:
    case SpvOpTypeArray:
    case SpvOpTypeRuntimeArray:
    case SpvOpTypeStruct:
@@ -1047,8 +2430,7 @@ vtn_handle_preamble_instruction(struct vtn_builder *b, SpvOp opcode,
    case SpvOpTypeReserveId:
    case SpvOpTypeQueue:
    case SpvOpTypePipe:
-      vtn_push_value(b, w[1], vtn_value_type_type)->type =
-         vtn_handle_type(b, opcode, &w[2], count - 2);
+      vtn_handle_type(b, opcode, w, count);
       break;
 
    case SpvOpConstantTrue:
@@ -1056,8 +2438,6 @@ vtn_handle_preamble_instruction(struct vtn_builder *b, SpvOp opcode,
    case SpvOpConstant:
    case SpvOpConstantComposite:
    case SpvOpConstantSampler:
-   case SpvOpConstantNullPointer:
-   case SpvOpConstantNullObject:
    case SpvOpSpecConstantTrue:
    case SpvOpSpecConstantFalse:
    case SpvOpSpecConstant:
@@ -1086,10 +2466,10 @@ vtn_handle_first_cfg_pass_instruction(struct vtn_builder *b, SpvOp opcode,
       b->func = rzalloc(b, struct vtn_function);
 
       const struct glsl_type *result_type =
-         vtn_value(b, w[1], vtn_value_type_type)->type;
+         vtn_value(b, w[1], vtn_value_type_type)->type->type;
       struct vtn_value *val = vtn_push_value(b, w[2], vtn_value_type_function);
       const struct glsl_type *func_type =
-         vtn_value(b, w[4], vtn_value_type_type)->type;
+         vtn_value(b, w[4], vtn_value_type_type)->type->type;
 
       assert(glsl_get_function_return_type(func_type) == result_type);
 
@@ -1123,6 +2503,7 @@ vtn_handle_first_cfg_pass_instruction(struct vtn_builder *b, SpvOp opcode,
    }
 
    case SpvOpFunctionEnd:
+      b->func->end = w;
       b->func = NULL;
       break;
 
@@ -1182,10 +2563,7 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode,
       struct vtn_block *block = vtn_value(b, w[1], vtn_value_type_block)->block;
       assert(block->block == NULL);
 
-      struct exec_node *list_tail = exec_list_get_tail(b->nb.cf_node_list);
-      nir_cf_node *tail_node = exec_node_data(nir_cf_node, list_tail, node);
-      assert(tail_node->type == nir_cf_node_block);
-      block->block = nir_cf_node_as_block(tail_node);
+      block->block = nir_cursor_current_block(b->nb.cursor);
       break;
    }
 
@@ -1203,7 +2581,6 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode,
       break;
 
    case SpvOpVariable:
-   case SpvOpVariableArray:
    case SpvOpLoad:
    case SpvOpStore:
    case SpvOpCopyMemory:
@@ -1211,7 +2588,7 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode,
    case SpvOpAccessChain:
    case SpvOpInBoundsAccessChain:
    case SpvOpArrayLength:
-   case SpvOpImagePointer:
+   case SpvOpImageTexelPointer:
       vtn_handle_variables(b, opcode, w, count);
       break;
 
@@ -1219,31 +2596,22 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode,
       vtn_handle_function_call(b, opcode, w, count);
       break;
 
-   case SpvOpTextureSample:
-   case SpvOpTextureSampleDref:
-   case SpvOpTextureSampleLod:
-   case SpvOpTextureSampleProj:
-   case SpvOpTextureSampleGrad:
-   case SpvOpTextureSampleOffset:
-   case SpvOpTextureSampleProjLod:
-   case SpvOpTextureSampleProjGrad:
-   case SpvOpTextureSampleLodOffset:
-   case SpvOpTextureSampleProjOffset:
-   case SpvOpTextureSampleGradOffset:
-   case SpvOpTextureSampleProjLodOffset:
-   case SpvOpTextureSampleProjGradOffset:
-   case SpvOpTextureFetchTexelLod:
-   case SpvOpTextureFetchTexelOffset:
-   case SpvOpTextureFetchSample:
-   case SpvOpTextureFetchTexel:
-   case SpvOpTextureGather:
-   case SpvOpTextureGatherOffset:
-   case SpvOpTextureGatherOffsets:
-   case SpvOpTextureQuerySizeLod:
-   case SpvOpTextureQuerySize:
-   case SpvOpTextureQueryLod:
-   case SpvOpTextureQueryLevels:
-   case SpvOpTextureQuerySamples:
+   case SpvOpImageSampleImplicitLod:
+   case SpvOpImageSampleExplicitLod:
+   case SpvOpImageSampleDrefImplicitLod:
+   case SpvOpImageSampleDrefExplicitLod:
+   case SpvOpImageSampleProjImplicitLod:
+   case SpvOpImageSampleProjExplicitLod:
+   case SpvOpImageSampleProjDrefImplicitLod:
+   case SpvOpImageSampleProjDrefExplicitLod:
+   case SpvOpImageFetch:
+   case SpvOpImageGather:
+   case SpvOpImageDrefGather:
+   case SpvOpImageQuerySizeLod:
+   case SpvOpImageQuerySize:
+   case SpvOpImageQueryLod:
+   case SpvOpImageQueryLevels:
+   case SpvOpImageQuerySamples:
       vtn_handle_texture(b, opcode, w, count);
       break;
 
@@ -1292,7 +2660,8 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode,
    case SpvOpShiftRightArithmetic:
    case SpvOpShiftLeftLogical:
    case SpvOpLogicalOr:
-   case SpvOpLogicalXor:
+   case SpvOpLogicalEqual:
+   case SpvOpLogicalNotEqual:
    case SpvOpLogicalAnd:
    case SpvOpBitwiseOr:
    case SpvOpBitwiseXor:
@@ -1341,6 +2710,20 @@ vtn_handle_body_instruction(struct vtn_builder *b, SpvOp opcode,
       vtn_handle_matrix_alu(b, opcode, w, count);
       break;
 
+   case SpvOpVectorExtractDynamic:
+   case SpvOpVectorInsertDynamic:
+   case SpvOpVectorShuffle:
+   case SpvOpCompositeConstruct:
+   case SpvOpCompositeExtract:
+   case SpvOpCompositeInsert:
+   case SpvOpCopyObject:
+      vtn_handle_composite(b, opcode, w, count);
+      break;
+
+   case SpvOpPhi:
+      vtn_handle_phi_first_pass(b, w);
+      break;
+
    default:
       unreachable("Unhandled opcode");
    }
@@ -1355,34 +2738,23 @@ vtn_walk_blocks(struct vtn_builder *b, struct vtn_block *start,
 {
    struct vtn_block *block = start;
    while (block != end_block) {
-      if (block->block != NULL) {
-         /* We've already visited this block once before so this is a
-          * back-edge.  Back-edges are only allowed to point to a loop
-          * merge.
-          */
-         assert(block == cont_block);
-         return;
-      }
-
       if (block->merge_op == SpvOpLoopMerge) {
          /* This is the jump into a loop. */
-         cont_block = block;
-         break_block = vtn_value(b, block->merge_block_id,
-                                 vtn_value_type_block)->block;
+         struct vtn_block *new_cont_block = block;
+         struct vtn_block *new_break_block =
+            vtn_value(b, block->merge_block_id, vtn_value_type_block)->block;
 
          nir_loop *loop = nir_loop_create(b->shader);
-         nir_cf_node_insert_end(b->nb.cf_node_list, &loop->cf_node);
-
-         struct exec_list *old_list = b->nb.cf_node_list;
+         nir_cf_node_insert(b->nb.cursor, &loop->cf_node);
 
          /* Reset the merge_op to prerevent infinite recursion */
          block->merge_op = SpvOpNop;
 
-         nir_builder_insert_after_cf_list(&b->nb, &loop->body);
-         vtn_walk_blocks(b, block, break_block, cont_block, NULL);
+         b->nb.cursor = nir_after_cf_list(&loop->body);
+         vtn_walk_blocks(b, block, new_break_block, new_cont_block, NULL);
 
-         nir_builder_insert_after_cf_list(&b->nb, old_list);
-         block = break_block;
+         b->nb.cursor = nir_after_cf_node(&loop->cf_node);
+         block = new_break_block;
          continue;
       }
 
@@ -1393,6 +2765,10 @@ vtn_walk_blocks(struct vtn_builder *b, struct vtn_block *start,
       vtn_foreach_instruction(b, block->label, block->branch,
                               vtn_handle_body_instruction);
 
+      nir_block *cur_block = nir_cursor_current_block(b->nb.cursor);
+      assert(cur_block == block->block);
+      _mesa_hash_table_insert(b->block_table, cur_block, block);
+
       switch (branch_op) {
       case SpvOpBranch: {
          struct vtn_block *branch_block =
@@ -1411,8 +2787,16 @@ vtn_walk_blocks(struct vtn_builder *b, struct vtn_block *start,
 
             return;
          } else if (branch_block == end_block) {
+            /* We're branching to the merge block of an if, since for loops
+             * and functions end_block == NULL, so we're done here.
+             */
             return;
          } else {
+            /* We're branching to another block, and according to the rules,
+             * we can only branch to another block with one predecessor (so
+             * we're the only one jumping to it) so we can just process it
+             * next.
+             */
             block = branch_block;
             continue;
          }
@@ -1426,8 +2810,8 @@ vtn_walk_blocks(struct vtn_builder *b, struct vtn_block *start,
             vtn_value(b, w[3], vtn_value_type_block)->block;
 
          nir_if *if_stmt = nir_if_create(b->shader);
-         if_stmt->condition = nir_src_for_ssa(vtn_ssa_value(b, w[1]));
-         nir_cf_node_insert_end(b->nb.cf_node_list, &if_stmt->cf_node);
+         if_stmt->condition = nir_src_for_ssa(vtn_ssa_value(b, w[1])->def);
+         nir_cf_node_insert(b->nb.cursor, &if_stmt->cf_node);
 
          if (then_block == break_block) {
             nir_jump_instr *jump = nir_jump_instr_create(b->shader,
@@ -1454,20 +2838,21 @@ vtn_walk_blocks(struct vtn_builder *b, struct vtn_block *start,
                                            &jump->instr);
             block = then_block;
          } else {
-            /* Conventional if statement */
+            /* According to the rules we're branching to two blocks that don't
+             * have any other predecessors, so we can handle this as a
+             * conventional if.
+             */
             assert(block->merge_op == SpvOpSelectionMerge);
             struct vtn_block *merge_block =
                vtn_value(b, block->merge_block_id, vtn_value_type_block)->block;
 
-            struct exec_list *old_list = b->nb.cf_node_list;
-
-            nir_builder_insert_after_cf_list(&b->nb, &if_stmt->then_list);
+            b->nb.cursor = nir_after_cf_list(&if_stmt->then_list);
             vtn_walk_blocks(b, then_block, break_block, cont_block, merge_block);
 
-            nir_builder_insert_after_cf_list(&b->nb, &if_stmt->else_list);
+            b->nb.cursor = nir_after_cf_list(&if_stmt->else_list);
             vtn_walk_blocks(b, else_block, break_block, cont_block, merge_block);
 
-            nir_builder_insert_after_cf_list(&b->nb, old_list);
+            b->nb.cursor = nir_after_cf_node(&if_stmt->cf_node);
             block = merge_block;
             continue;
          }
@@ -1549,7 +2934,7 @@ spirv_to_nir(const uint32_t *words, size_t word_count,
    struct vtn_builder *b = rzalloc(NULL, struct vtn_builder);
    b->shader = shader;
    b->value_id_bound = value_id_bound;
-   b->values = ralloc_array(b, struct vtn_value, value_id_bound);
+   b->values = rzalloc_array(b, struct vtn_value, value_id_bound);
    exec_list_make_empty(&b->functions);
 
    /* Handle all the preamble instructions */
@@ -1562,11 +2947,22 @@ spirv_to_nir(const uint32_t *words, size_t word_count,
 
    foreach_list_typed(struct vtn_function, func, node, &b->functions) {
       b->impl = nir_function_impl_create(func->overload);
+      b->const_table = _mesa_hash_table_create(b, _mesa_hash_pointer,
+                                               _mesa_key_pointer_equal);
+      b->block_table = _mesa_hash_table_create(b, _mesa_hash_pointer,
+                                               _mesa_key_pointer_equal);
       nir_builder_init(&b->nb, b->impl);
-      nir_builder_insert_after_cf_list(&b->nb, &b->impl->body);
+      b->nb.cursor = nir_after_cf_list(&b->impl->body);
       vtn_walk_blocks(b, func->start_block, NULL, NULL, NULL);
+      vtn_foreach_instruction(b, func->start_block->label, func->end,
+                              vtn_handle_phi_second_pass);
    }
 
+   /* Because we can still have output reads in NIR, we need to lower
+    * outputs to temporaries before we are truely finished.
+    */
+   nir_lower_outputs_to_temporaries(shader);
+
    ralloc_free(b);
 
    return shader;
index d2b364bdfeb3081f269cf6ddbc58f62045e2099f..decceff65a6f39982b3ba43579c4260df696ac3c 100644 (file)
@@ -25,6 +25,7 @@
  *
  */
 
+#include "nir.h"
 #include "nir_spirv.h"
 #include "nir_builder.h"
 #include "spirv.h"
@@ -60,30 +61,88 @@ struct vtn_function {
 
    nir_function_overload *overload;
    struct vtn_block *start_block;
+
+   const uint32_t *end;
 };
 
 typedef bool (*vtn_instruction_handler)(struct vtn_builder *, uint32_t,
                                         const uint32_t *, unsigned);
 
+struct vtn_ssa_value {
+   union {
+      nir_ssa_def *def;
+      struct vtn_ssa_value **elems;
+   };
+
+   /* For matrices, a transposed version of the value, or NULL if it hasn't
+    * been computed
+    */
+   struct vtn_ssa_value *transposed;
+
+   const struct glsl_type *type;
+};
+
+struct vtn_type {
+   const struct glsl_type *type;
+
+   /* for matrices, whether the matrix is stored row-major */
+   bool row_major;
+
+   /* for structs, the offset of each member */
+   unsigned *offsets;
+
+   /* for structs, whether it was decorated as a "non-SSBO-like" block */
+   bool block;
+
+   /* for structs, whether it was decorated as an "SSBO-like" block */
+   bool buffer_block;
+
+   /* for structs with block == true, whether this is a builtin block (i.e. a
+    * block that contains only builtins).
+    */
+   bool builtin_block;
+
+   /* for arrays and matrices, the array stride */
+   unsigned stride;
+
+   /* for arrays, the vtn_type for the elements of the array */
+   struct vtn_type *array_element;
+
+   /* for structures, the vtn_type for each member */
+   struct vtn_type **members;
+
+   /* Whether this type, or a parent type, has been decorated as a builtin */
+   bool is_builtin;
+
+   SpvBuiltIn builtin;
+};
+
 struct vtn_value {
    enum vtn_value_type value_type;
    const char *name;
    struct vtn_decoration *decoration;
-   const struct glsl_type *type;
    union {
       void *ptr;
       char *str;
-      nir_constant *constant;
-      nir_deref_var *deref;
+      struct vtn_type *type;
+      struct {
+         nir_constant *constant;
+         const struct glsl_type *const_type;
+      };
+      struct {
+         nir_deref_var *deref;
+         struct vtn_type *deref_type;
+      };
       struct vtn_function *func;
       struct vtn_block *block;
-      nir_ssa_def *ssa;
+      struct vtn_ssa_value *ssa;
       vtn_instruction_handler ext_handler;
    };
 };
 
 struct vtn_decoration {
    struct vtn_decoration *next;
+   int member; /* -1 if not a member decoration */
    const uint32_t *literals;
    struct vtn_value *group;
    SpvDecoration decoration;
@@ -96,6 +155,25 @@ struct vtn_builder {
    nir_function_impl *impl;
    struct vtn_block *block;
 
+   /*
+    * In SPIR-V, constants are global, whereas in NIR, the load_const
+    * instruction we use is per-function. So while we parse each function, we
+    * keep a hash table of constants we've resolved to nir_ssa_value's so
+    * far, and we lazily resolve them when we see them used in a function.
+    */
+   struct hash_table *const_table;
+
+   /*
+    * Map from nir_block to the vtn_block which ends with it -- used for
+    * handling phi nodes.
+    */
+   struct hash_table *block_table;
+
+   /*
+    * NIR variable for each SPIR-V builtin.
+    */
+   nir_variable *builtins[42]; /* XXX need symbolic constant from SPIR-V header */
+
    unsigned value_id_bound;
    struct vtn_value *values;
 
@@ -134,10 +212,11 @@ vtn_value(struct vtn_builder *b, uint32_t value_id,
    return val;
 }
 
-nir_ssa_def *vtn_ssa_value(struct vtn_builder *b, uint32_t value_id);
+struct vtn_ssa_value *vtn_ssa_value(struct vtn_builder *b, uint32_t value_id);
 
 typedef void (*vtn_decoration_foreach_cb)(struct vtn_builder *,
                                           struct vtn_value *,
+                                          int member,
                                           const struct vtn_decoration *,
                                           void *);