SpirvShaderDebugger: Implement Array types and move pointer typeinfo value construction from build time to runtime. While this may seem counter-intuitive for performance, it's actually a big win, as shader compilation can take a significant amount of time with the amount of debug logic generated. This is also a first step towards lazy/static `vk::dbg::Value` generation for array types. Bug: b/124388146 Change-Id: I3448ffdabd553db17a22090081ac4809e0555b1d Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/45488 Kokoro-Result: kokoro <noreply+kokoro@google.com> Tested-by: Ben Clayton <bclayton@google.com> Reviewed-by: Antonio Maiorano <amaiorano@google.com>
diff --git a/src/Pipeline/SpirvShaderDebugger.cpp b/src/Pipeline/SpirvShaderDebugger.cpp index 2933a81..a93a1a3 100644 --- a/src/Pipeline/SpirvShaderDebugger.cpp +++ b/src/Pipeline/SpirvShaderDebugger.cpp
@@ -18,6 +18,9 @@ #define PRINT_EACH_PROCESSED_INSTRUCTION 0 // If enabled, each instruction will be printed before executing. #define PRINT_EACH_EXECUTED_INSTRUCTION 0 +// If enabled, debugger variables will contain debug information (addresses, +// byte offset, etc). +#define DEBUG_ANNOTATE_VARIABLE_KEYS 0 #ifdef ENABLE_VK_DEBUGGER @@ -85,9 +88,16 @@ { return s; } +template<typename T> +std::string tostring(T *s) +{ + char buf[32]; + snprintf(buf, sizeof(buf), "%p", s); + return buf; +} std::string tostring(sw::SpirvShader::Object::ID id) { - return "%" + std::to_string(id.value()); + return "%" + tostring(id.value()); } //////////////////////////////////////////////////////////////////////////////// @@ -243,6 +253,13 @@ kind == Kind::CompositeType || kind == Kind::TemplateType; } + + // sizeInBytes() returns the number of bytes of the given debug type. + virtual uint32_t sizeInBytes() const = 0; + + // value() returns a shared pointer to a vk::dbg::Value that views the data + // at ptr of this type. + virtual std::shared_ptr<vk::dbg::Value> value(vk::dbg::Context::Lock &lock, void *ptr, bool interleaved) const = 0; }; struct CompilationUnit : ObjectImpl<CompilationUnit, Scope, Object::Kind::CompilationUnit> @@ -264,18 +281,170 @@ std::string name; uint32_t size = 0; // in bits. OpenCLDebugInfo100DebugBaseTypeAttributeEncoding encoding = OpenCLDebugInfo100Unspecified; + + uint32_t sizeInBytes() const override { return size / 8; } + + std::shared_ptr<vk::dbg::Value> value(vk::dbg::Context::Lock &lock, void *ptr, bool interleaved) const override + { + switch(encoding) + { + case OpenCLDebugInfo100Address: + // return vk::dbg::make_reference(*static_cast<void **>(ptr)); + UNIMPLEMENTED("b/148401179 OpenCLDebugInfo100 OpenCLDebugInfo100Address BasicType"); + return nullptr; + case OpenCLDebugInfo100Boolean: + return vk::dbg::make_reference(*static_cast<bool *>(ptr)); + case OpenCLDebugInfo100Float: + return vk::dbg::make_reference(*static_cast<float *>(ptr)); + case OpenCLDebugInfo100Signed: + return vk::dbg::make_reference(*static_cast<int32_t *>(ptr)); + case OpenCLDebugInfo100SignedChar: + return vk::dbg::make_reference(*static_cast<int8_t *>(ptr)); + case OpenCLDebugInfo100Unsigned: + return vk::dbg::make_reference(*static_cast<uint32_t *>(ptr)); + case OpenCLDebugInfo100UnsignedChar: + return vk::dbg::make_reference(*static_cast<uint8_t *>(ptr)); + default: + UNIMPLEMENTED("b/148401179 OpenCLDebugInfo100 encoding %d", int(encoding)); + return nullptr; + } + } }; struct ArrayType : ObjectImpl<ArrayType, Type, Object::Kind::ArrayType> { Type *base = nullptr; std::vector<uint32_t> dimensions; + + // build() loops over each element of the multi-dimensional array, calling + // enter() for building each new dimension group, and element() for each + // inner-most dimension element. + // + // enter must be a function of the signature: + // std::shared_ptr<vk::dbg::VariableContainer> + // (std::shared_ptr<vk::dbg::VariableContainer>& parent, uint32_t idx) + // where: + // parent is the outer dimension group + // idx is the index of the next deepest dimension. + // + // element must be a function of the signature: + // void(std::shared_ptr<vk::dbg::VariableContainer> &parent, + // uint32_t idx, uint32_t offset) + // where: + // parent is the penultimate deepest dimension group + // idx is the index of the element in parent group + // offset is the 'flattened array' index for the element. + template<typename GROUP, typename ENTER_FUNC, typename ELEMENT_FUNC> + void build(const GROUP &group, ENTER_FUNC &&enter, ELEMENT_FUNC &&element) const + { + if(dimensions.size() == 0) { return; } + + struct Dimension + { + uint32_t idx = 0; + GROUP group; + bool built = false; + }; + + std::vector<Dimension> dims; + dims.resize(dimensions.size()); + + uint32_t offset = 0; + + int dimIdx = 0; + const int n = static_cast<int>(dimensions.size()) - 1; + while(dimIdx >= 0) + { + // (Re)build groups to inner dimensions. + for(; dimIdx <= n; dimIdx++) + { + if(!dims[dimIdx].built) + { + dims[dimIdx].group = (dimIdx == 0) + ? group + : enter(dims[dimIdx - 1].group, dims[dimIdx - 1].idx); + dims[dimIdx].built = true; + } + } + + // Emit each of the inner-most dimension elements. + for(dims[n].idx = 0; dims[n].idx < dimensions[n]; dims[n].idx++) + { + ASSERT(dims[n].built); + element(dims[n].group, dims[n].idx, offset++); + } + + dimIdx = n; + while(dims[dimIdx].idx == dimensions[dimIdx]) + { + dims[dimIdx] = {}; // Clear the the current dimension + dimIdx--; // Step up a dimension + if(dimIdx < 0) { break; } + dims[dimIdx].idx++; // Increment the next dimension index + } + } + } + + uint32_t sizeInBytes() const override + { + auto numBytes = base->sizeInBytes(); + for(auto dim : dimensions) + { + numBytes *= dim; + } + return numBytes; + } + + std::shared_ptr<vk::dbg::Value> value(vk::dbg::Context::Lock &lock, void *ptr, bool interleaved) const override + { + auto vc = lock.createVariableContainer(); + build( + vc, + [&](std::shared_ptr<vk::dbg::VariableContainer> &parent, uint32_t idx) { + auto child = lock.createVariableContainer(); + parent->put(tostring(idx), child); + return child; + }, + [&](std::shared_ptr<vk::dbg::VariableContainer> &parent, uint32_t idx, uint32_t offset) { + offset = offset * base->sizeInBytes() * (interleaved ? sw::SIMD::Width : 1); + auto addr = static_cast<uint8_t *>(ptr) + offset; + auto child = base->value(lock, addr, interleaved); + auto key = tostring(idx); +# if DEBUG_ANNOTATE_VARIABLE_KEYS + key += " (" + tostring(addr) + " +" + tostring(offset) + ", idx: " + tostring(idx) + ")" + (interleaved ? "I" : "F"); +# endif + parent->put(key, child); + }); + return vc; + } }; struct VectorType : ObjectImpl<VectorType, Type, Object::Kind::VectorType> { Type *base = nullptr; uint32_t components = 0; + + uint32_t sizeInBytes() const override + { + return base->sizeInBytes() * components; + } + + std::shared_ptr<vk::dbg::Value> value(vk::dbg::Context::Lock &lock, void *ptr, bool interleaved) const override + { + const auto elSize = base->sizeInBytes(); + auto vc = lock.createVariableContainer(); + for(uint32_t i = 0; i < components; i++) + { + auto offset = elSize * i * (interleaved ? sw::SIMD::Width : 1); + auto elPtr = static_cast<uint8_t *>(ptr) + offset; + auto elKey = tostring(i); +# if DEBUG_ANNOTATE_VARIABLE_KEYS + elKey += " (" + tostring(elPtr) + " +" + tostring(offset) + ")" + (interleaved ? "I" : "F"); +# endif + vc->put(elKey, base->value(lock, elPtr, interleaved)); + } + return vc; + } }; struct FunctionType : ObjectImpl<FunctionType, Type, Object::Kind::FunctionType> @@ -283,6 +452,22 @@ uint32_t flags = 0; // OR'd from OpenCLDebugInfo100DebugInfoFlags Type *returnTy = nullptr; std::vector<Type *> paramTys; + + uint32_t sizeInBytes() const override { return 0; } + std::shared_ptr<vk::dbg::Value> value(vk::dbg::Context::Lock &lock, void *ptr, bool interleaved) const override { return nullptr; } +}; + +struct Member : ObjectImpl<Member, Object, Object::Kind::Member> +{ + std::string name; + Type *type = nullptr; + Source *source = nullptr; + uint32_t line = 0; + uint32_t column = 0; + struct CompositeType *parent = nullptr; + uint32_t offset = 0; // in bits + uint32_t size = 0; // in bits + uint32_t flags = 0; // OR'd from OpenCLDebugInfo100DebugInfoFlags }; struct CompositeType : ObjectImpl<CompositeType, Type, Object::Kind::CompositeType> @@ -297,6 +482,23 @@ uint32_t size = 0; // in bits. uint32_t flags = 0; // OR'd from OpenCLDebugInfo100DebugInfoFlags std::vector<Member *> members; + + uint32_t sizeInBytes() const override { return size / 8; } + std::shared_ptr<vk::dbg::Value> value(vk::dbg::Context::Lock &lock, void *ptr, bool interleaved) const override + { + auto vc = lock.createVariableContainer(); + for(auto &member : members) + { + auto offset = (member->offset / 8) * (interleaved ? sw::SIMD::Width : 1); + auto elPtr = static_cast<uint8_t *>(ptr) + offset; + auto elKey = member->name; +# if DEBUG_ANNOTATE_VARIABLE_KEYS + // elKey += " (" + tostring(elPtr) + " +" + tostring(offset) + ")" + (interleaved ? "I" : "F"); +# endif + vc->put(elKey, member->type->value(lock, elPtr, interleaved)); + } + return vc; + } }; struct TemplateParameter : ObjectImpl<TemplateParameter, Object, Object::Kind::TemplateParameter> @@ -313,19 +515,12 @@ { Type *target = nullptr; // Class, struct or function. std::vector<TemplateParameter *> parameters; -}; -struct Member : ObjectImpl<Member, Object, Object::Kind::Member> -{ - std::string name; - Type *type = nullptr; - Source *source = nullptr; - uint32_t line = 0; - uint32_t column = 0; - CompositeType *parent = nullptr; - uint32_t offset = 0; // in bits - uint32_t size = 0; // in bits - uint32_t flags = 0; // OR'd from OpenCLDebugInfo100DebugInfoFlags + uint32_t sizeInBytes() const override { return target->sizeInBytes(); } + std::shared_ptr<vk::dbg::Value> value(vk::dbg::Context::Lock &lock, void *ptr, bool interleaved) const override + { + return target->value(lock, ptr, interleaved); + } }; struct Function : ObjectImpl<Function, Scope, Object::Kind::Function> @@ -576,6 +771,9 @@ template<typename K, typename V> void putVal(vk::dbg::VariableContainer *vc, K key, V value); + template<typename K> + void putPtr(vk::dbg::VariableContainer *vc, K key, void *ptr, bool interleaved, const debug::Type *type); + template<typename K, typename V> void putRef(vk::dbg::VariableContainer *vc, K key, V *ptr); @@ -685,6 +883,13 @@ vc->put(tostring(key), vk::dbg::make_constant(value)); } +template<typename K> +void SpirvShader::Impl::Debugger::State::putPtr(vk::dbg::VariableContainer *vc, K key, void *ptr, bool interleaved, const debug::Type *type) +{ + auto lock = debugger->ctx->lock(); + vc->put(tostring(key), type->value(lock, ptr, interleaved)); +} + template<typename K, typename V> void SpirvShader::Impl::Debugger::State::putRef(vk::dbg::VariableContainer *vc, K key, V *ptr) { @@ -798,7 +1003,10 @@ static Group localsLane(Ptr state, const debug::Scope *scope, int lane); static Group globals(Ptr state, int lane); - Group(Ptr state, Ptr group); + inline Group(); + inline Group(Ptr state, Ptr group); + + inline bool isValid() const; template<typename K, typename RK> Group group(RK key) const; @@ -806,6 +1014,9 @@ template<typename K, typename V, typename RK, typename RV> void put(RK key, RV value) const; + template<typename K, typename RK> + void putPtr(RK key, RValue<Pointer<Byte>> ptr, bool interleaved, const debug::Type *type) const; + template<typename K, typename V, typename RK> void putRef(RK key, RValue<Pointer<Byte>> ref) const; @@ -824,6 +1035,7 @@ private: Ptr state; Ptr ptr; + bool valid = false; }; SpirvShader::Impl::Debugger::Group @@ -844,26 +1056,44 @@ return localsLane(state, &debug::Scope::Global, lane); } +SpirvShader::Impl::Debugger::Group::Group() {} + SpirvShader::Impl::Debugger::Group::Group(Ptr state, Ptr group) : state(state) , ptr(group) + , valid(true) {} +bool SpirvShader::Impl::Debugger::Group::isValid() const +{ + return valid; +} + template<typename K, typename RK> SpirvShader::Impl::Debugger::Group SpirvShader::Impl::Debugger::Group::group(RK key) const { + ASSERT(isValid()); return Group(state, rr::Call(&State::group<K>, state, ptr, key)); } template<typename K, typename V, typename RK, typename RV> void SpirvShader::Impl::Debugger::Group::put(RK key, RV value) const { + ASSERT(isValid()); rr::Call(&State::putVal<K, V>, state, ptr, key, value); } +template<typename K, typename RK> +void SpirvShader::Impl::Debugger::Group::putPtr(RK key, RValue<Pointer<Byte>> addr, bool interleaved, const debug::Type *type) const +{ + ASSERT(isValid()); + rr::Call(&State::putPtr<K>, state, ptr, key, addr, interleaved, type); +} + template<typename K, typename V, typename RK> void SpirvShader::Impl::Debugger::Group::putRef(RK key, RValue<Pointer<Byte>> ref) const { + ASSERT(isValid()); rr::Call(&State::putRef<K, V>, state, ptr, key, ref); } @@ -948,9 +1178,10 @@ case OpenCLDebugInfo100DebugTypeArray: defineOrEmit(insn, pass, [&](debug::ArrayType *type) { type->base = get(debug::Type::ID(insn.word(5))); - auto &components = shader->getObject(insn.word(6)); - ASSERT(components.kind == SpirvShader::Object::Kind::Constant); - type->dimensions = components.constantValue; + for(uint32_t i = 6; i < insn.wordCount(); i++) + { + type->dimensions.emplace_back(shader->GetConstScalarInt(insn.word(i))); + } }); break; case OpenCLDebugInfo100DebugTypeVector: @@ -1260,7 +1491,7 @@ void SpirvShader::Impl::Debugger::exposeVariable( const SpirvShader *shader, const Group &group, - int l, + int lane, const Key &key, const debug::Type *type, Object::ID id, @@ -1271,55 +1502,31 @@ if(type != nullptr) { - if(auto ty = debug::cast<debug::BasicType>(type)) + switch(obj.kind) { - SIMD::Int val; - switch(obj.kind) + case Object::Kind::InterfaceVariable: + case Object::Kind::Pointer: + case Object::Kind::DescriptorSet: { - case Object::Kind::InterfaceVariable: - case Object::Kind::Pointer: + ASSERT(wordOffset == 0); // TODO. + auto ptr = shader->GetPointerToData(id, 0, state); // + sizeof(uint32_t) * wordOffset; + auto &ptrTy = shader->getType(obj); + auto interleaved = IsStorageInterleavedByLane(ptrTy.storageClass); + if(interleaved) { - auto ptr = shader->GetPointerToData(id, 0, state) + sizeof(uint32_t) * wordOffset; - auto &ptrTy = shader->getType(obj); - if(IsStorageInterleavedByLane(ptrTy.storageClass)) - { - ptr = InterleaveByLane(ptr); - } - auto addr = &ptr.base[Extract(ptr.offsets(), l)]; - switch(ty->encoding) - { - case OpenCLDebugInfo100Address: - // TODO: This function takes a SIMD vector, and pointers cannot - // be held in them. - break; - case OpenCLDebugInfo100Boolean: - group.putRef<Key, bool>(key, addr); - break; - case OpenCLDebugInfo100Float: - group.putRef<Key, float>(key, addr); - break; - case OpenCLDebugInfo100Signed: - group.putRef<Key, int>(key, addr); - break; - case OpenCLDebugInfo100SignedChar: - group.putRef<Key, int8_t>(key, addr); - break; - case OpenCLDebugInfo100Unsigned: - group.putRef<Key, unsigned int>(key, addr); - break; - case OpenCLDebugInfo100UnsignedChar: - group.putRef<Key, uint8_t>(key, addr); - break; - default: - break; - } + ptr = InterleaveByLane(ptr); } - break; - case Object::Kind::Constant: - case Object::Kind::Intermediate: + auto addr = &ptr.base[Extract(ptr.offsets(), lane)]; + group.putPtr<Key>(key, addr, interleaved, type); + } + break; + + case Object::Kind::Constant: + case Object::Kind::Intermediate: + { + if(auto ty = debug::cast<debug::BasicType>(type)) { auto val = Operand(shader, state, id).Int(wordOffset); - switch(ty->encoding) { case OpenCLDebugInfo100Address: @@ -1327,87 +1534,92 @@ // be held in them. break; case OpenCLDebugInfo100Boolean: - group.put<Key, bool>(key, Extract(val, l) != 0); + group.put<Key, bool>(key, Extract(val, lane) != 0); break; case OpenCLDebugInfo100Float: - group.put<Key, float>(key, Extract(As<SIMD::Float>(val), l)); + group.put<Key, float>(key, Extract(As<SIMD::Float>(val), lane)); break; case OpenCLDebugInfo100Signed: - group.put<Key, int>(key, Extract(val, l)); + group.put<Key, int>(key, Extract(val, lane)); break; case OpenCLDebugInfo100SignedChar: - group.put<Key, int8_t>(key, SByte(Extract(val, l))); + group.put<Key, int8_t>(key, SByte(Extract(val, lane))); break; case OpenCLDebugInfo100Unsigned: - group.put<Key, unsigned int>(key, Extract(val, l)); + group.put<Key, unsigned int>(key, Extract(val, lane)); break; case OpenCLDebugInfo100UnsignedChar: - group.put<Key, uint8_t>(key, Byte(Extract(val, l))); + group.put<Key, uint8_t>(key, Byte(Extract(val, lane))); break; default: break; } } - break; - default: - break; - } - return; - } - else if(auto ty = debug::cast<debug::VectorType>(type)) - { - auto elWords = 1; // Currently vector elements must only be basic types, 32-bit wide - auto elTy = ty->base; - auto vecGroup = group.group<Key>(key); - switch(ty->components) - { - case 1: - exposeVariable(shader, vecGroup, l, "x", elTy, id, state, wordOffset + 0 * elWords); - break; - case 2: - exposeVariable(shader, vecGroup, l, "x", elTy, id, state, wordOffset + 0 * elWords); - exposeVariable(shader, vecGroup, l, "y", elTy, id, state, wordOffset + 1 * elWords); - break; - case 3: - exposeVariable(shader, vecGroup, l, "x", elTy, id, state, wordOffset + 0 * elWords); - exposeVariable(shader, vecGroup, l, "y", elTy, id, state, wordOffset + 1 * elWords); - exposeVariable(shader, vecGroup, l, "z", elTy, id, state, wordOffset + 2 * elWords); - break; - case 4: - exposeVariable(shader, vecGroup, l, "x", elTy, id, state, wordOffset + 0 * elWords); - exposeVariable(shader, vecGroup, l, "y", elTy, id, state, wordOffset + 1 * elWords); - exposeVariable(shader, vecGroup, l, "z", elTy, id, state, wordOffset + 2 * elWords); - exposeVariable(shader, vecGroup, l, "w", elTy, id, state, wordOffset + 3 * elWords); - break; - default: - for(uint32_t i = 0; i < ty->components; i++) + else if(auto ty = debug::cast<debug::VectorType>(type)) + { + auto elWords = 1; // Currently vector elements must only be basic types, 32-bit wide + auto elTy = ty->base; + auto vecGroup = group.group<Key>(key); + switch(ty->components) { - exposeVariable(shader, vecGroup, l, std::to_string(i).c_str(), elTy, id, state, wordOffset + i * elWords); + case 1: + exposeVariable(shader, vecGroup, lane, "x", elTy, id, state, wordOffset + 0 * elWords); + break; + case 2: + exposeVariable(shader, vecGroup, lane, "x", elTy, id, state, wordOffset + 0 * elWords); + exposeVariable(shader, vecGroup, lane, "y", elTy, id, state, wordOffset + 1 * elWords); + break; + case 3: + exposeVariable(shader, vecGroup, lane, "x", elTy, id, state, wordOffset + 0 * elWords); + exposeVariable(shader, vecGroup, lane, "y", elTy, id, state, wordOffset + 1 * elWords); + exposeVariable(shader, vecGroup, lane, "z", elTy, id, state, wordOffset + 2 * elWords); + break; + case 4: + exposeVariable(shader, vecGroup, lane, "x", elTy, id, state, wordOffset + 0 * elWords); + exposeVariable(shader, vecGroup, lane, "y", elTy, id, state, wordOffset + 1 * elWords); + exposeVariable(shader, vecGroup, lane, "z", elTy, id, state, wordOffset + 2 * elWords); + exposeVariable(shader, vecGroup, lane, "w", elTy, id, state, wordOffset + 3 * elWords); + break; + default: + for(uint32_t i = 0; i < ty->components; i++) + { + exposeVariable(shader, vecGroup, lane, tostring(i).c_str(), elTy, id, state, wordOffset + i * elWords); + } + break; } - break; - } - return; - } - else if(auto ty = debug::cast<debug::CompositeType>(type)) - { - auto objectGroup = group.group<Key>(key); + } + else if(auto ty = debug::cast<debug::CompositeType>(type)) + { + auto objectGroup = group.group<Key>(key); - for(auto member : ty->members) - { - exposeVariable(shader, objectGroup, l, member->name.c_str(), member->type, id, state, member->offset / 32); + for(auto member : ty->members) + { + exposeVariable(shader, objectGroup, lane, member->name.c_str(), member->type, id, state, member->offset / 32); + } + } + else if(auto ty = debug::cast<debug::ArrayType>(type)) + { + ty->build( + group.group<Key>(key), + [&](Debugger::Group &parent, uint32_t idx) { + return parent.template group<int>(idx); + }, + [&](Debugger::Group &parent, uint32_t idx, uint32_t offset) { + exposeVariable(shader, parent, lane, idx, ty->base, id, state, offset); + }); + } + else + { + UNIMPLEMENTED("b/145351270: Debug type: %s", cstr(type->kind)); + } + return; } + break; - return; + case Object::Kind::Unknown: + UNIMPLEMENTED("b/145351270: Object kind: %d", (int)obj.kind); } - else if(auto ty = debug::cast<debug::ArrayType>(type)) - { - // TODO(bclayton): Expose array types. - return; - } - else - { - UNIMPLEMENTED("b/145351270: Debug type: %s", cstr(type->kind)); - } + return; } // No debug type information. Derive from SPIR-V. @@ -1416,13 +1628,13 @@ case spv::OpTypeInt: { Operand val(shader, state, id); - group.put<Key, int>(key, Extract(val.Int(0), l)); + group.put<Key, int>(key, Extract(val.Int(0), lane)); } break; case spv::OpTypeFloat: { Operand val(shader, state, id); - group.put<Key, float>(key, Extract(val.Float(0), l)); + group.put<Key, float>(key, Extract(val.Float(0), lane)); } break; case spv::OpTypeVector: @@ -1432,23 +1644,23 @@ switch(count) { case 1: - group.put<Key, float>(key, Extract(val.Float(0), l)); + group.put<Key, float>(key, Extract(val.Float(0), lane)); break; case 2: - group.put<Key, float>(key, Extract(val.Float(0), l), Extract(val.Float(1), l)); + group.put<Key, float>(key, Extract(val.Float(0), lane), Extract(val.Float(1), lane)); break; case 3: - group.put<Key, float>(key, Extract(val.Float(0), l), Extract(val.Float(1), l), Extract(val.Float(2), l)); + group.put<Key, float>(key, Extract(val.Float(0), lane), Extract(val.Float(1), lane), Extract(val.Float(2), lane)); break; case 4: - group.put<Key, float>(key, Extract(val.Float(0), l), Extract(val.Float(1), l), Extract(val.Float(2), l), Extract(val.Float(3), l)); + group.put<Key, float>(key, Extract(val.Float(0), lane), Extract(val.Float(1), lane), Extract(val.Float(2), lane), Extract(val.Float(3), lane)); break; default: { auto vec = group.group<Key>(key); for(uint32_t i = 0; i < count; i++) { - vec.template put<int, float>(i, Extract(val.Float(i), l)); + vec.template put<int, float>(i, Extract(val.Float(i), lane)); } } break; @@ -1465,7 +1677,7 @@ auto p = ptr + el.offset; if(interleavedByLane) { p = InterleaveByLane(p); } // TODO: Interleave once, then add offset? auto simd = p.Load<SIMD::Float>(sw::OutOfBoundsBehavior::Nullify, state->activeLaneMask()); - ptrGroup.template put<int, float>(el.index, Extract(simd, l)); + ptrGroup.template put<int, float>(el.index, Extract(simd, lane)); }); } break; @@ -1521,7 +1733,7 @@ default: name = "SPIR-V Shader"; break; } static std::atomic<int> id = { 0 }; - name += std::to_string(id++) + ".spvasm"; + name += tostring(id++) + ".spvasm"; dbg->spirvFile = dbg->ctx->lock().createVirtualFile(name.c_str(), source.c_str()); }