Lots of cleanup in SpvEmitter.
This commit is contained in:
parent
e4d012911a
commit
cf68d02142
|
@ -41,16 +41,16 @@ OpFunctionEnd
|
||||||
spv_disasm.Disassemble(asm_result->words(), asm_result->word_count());
|
spv_disasm.Disassemble(asm_result->words(), asm_result->word_count());
|
||||||
|
|
||||||
SpvEmitter e;
|
SpvEmitter e;
|
||||||
auto glsl_std_450 = e.import("GLSL.std.450");
|
auto glsl_std_450 = e.ImportExtendedInstructions("GLSL.std.450");
|
||||||
auto fn = e.makeMain();
|
auto fn = e.MakeMainEntry();
|
||||||
auto float_1_0 = e.makeFloatConstant(1.0f);
|
auto float_1_0 = e.MakeFloatConstant(1.0f);
|
||||||
auto acos = e.createBuiltinCall(
|
auto acos = e.CreateExtendedInstructionCall(
|
||||||
spv::Decoration::Invariant, e.makeFloatType(32), glsl_std_450,
|
spv::Decoration::Invariant, e.MakeFloatType(32), glsl_std_450,
|
||||||
static_cast<int>(spv::GLSLstd450::Acos), {{float_1_0}});
|
static_cast<int>(spv::GLSLstd450::Acos), {{float_1_0}});
|
||||||
e.makeReturn(false);
|
e.MakeReturn(true);
|
||||||
|
|
||||||
std::vector<uint32_t> words;
|
std::vector<uint32_t> words;
|
||||||
e.dump(words);
|
e.Serialize(words);
|
||||||
|
|
||||||
auto disasm_result2 = spv_disasm.Disassemble(words.data(), words.size());
|
auto disasm_result2 = spv_disasm.Disassemble(words.data(), words.size());
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -64,87 +64,86 @@ class SpvEmitter {
|
||||||
SpvEmitter();
|
SpvEmitter();
|
||||||
~SpvEmitter();
|
~SpvEmitter();
|
||||||
|
|
||||||
void setSource(spv::SourceLanguage language, int version) {
|
// Document what source language and text this module was translated from.
|
||||||
|
void SetSourceLanguage(spv::SourceLanguage language, int version) {
|
||||||
source_language_ = language;
|
source_language_ = language;
|
||||||
source_version_ = version;
|
source_version_ = version;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addSourceExtension(const char* ext) { extensions_.push_back(ext); }
|
// Document an extension to the source language. Informational only.
|
||||||
|
void AddSourceExtension(const char* ext) {
|
||||||
|
source_extensions_.push_back(ext);
|
||||||
|
}
|
||||||
|
|
||||||
Id import(const char* name);
|
// Set addressing model and memory model for the entire module.
|
||||||
|
void SetMemoryModel(spv::AddressingModel addressing_model,
|
||||||
void setMemoryModel(spv::AddressingModel addressing_model,
|
|
||||||
spv::MemoryModel memory_model) {
|
spv::MemoryModel memory_model) {
|
||||||
addressing_model_ = addressing_model;
|
addressing_model_ = addressing_model;
|
||||||
memory_model_ = memory_model;
|
memory_model_ = memory_model;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addCapability(spv::Capability cap) { capabilities_.push_back(cap); }
|
// Declare a capability used by this module.
|
||||||
|
void DeclareCapability(spv::Capability cap) { capabilities_.push_back(cap); }
|
||||||
|
|
||||||
// To get a new <id> for anything needing a new one.
|
// Import an extended set of instructions that can be later referenced by the
|
||||||
Id getUniqueId() { return ++unique_id_; }
|
// returned id.
|
||||||
|
Id ImportExtendedInstructions(const char* name);
|
||||||
// To get a set of new <id>s, e.g., for a set of function parameters
|
|
||||||
Id getUniqueIds(int numIds) {
|
|
||||||
Id id = unique_id_ + 1;
|
|
||||||
unique_id_ += numIds;
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
// For creating new types (will return old type if the requested one was
|
// For creating new types (will return old type if the requested one was
|
||||||
// already made).
|
// already made).
|
||||||
Id makeVoidType();
|
Id MakeVoidType();
|
||||||
Id makeBoolType();
|
Id MakeBoolType();
|
||||||
Id makePointer(spv::StorageClass, Id type);
|
Id MakePointer(spv::StorageClass storage_class, Id pointee);
|
||||||
Id makeIntegerType(int width, bool hasSign); // generic
|
Id MakeIntegerType(int bit_width, bool is_signed);
|
||||||
Id makeIntType(int width) { return makeIntegerType(width, true); }
|
Id MakeIntType(int bit_width) { return MakeIntegerType(bit_width, true); }
|
||||||
Id makeUintType(int width) { return makeIntegerType(width, false); }
|
Id MakeUintType(int bit_width) { return MakeIntegerType(bit_width, false); }
|
||||||
Id makeFloatType(int width);
|
Id MakeFloatType(int bit_width);
|
||||||
Id makeStructType(std::vector<Id>& members, const char*);
|
Id MakeStructType(std::initializer_list<Id> members, const char* name);
|
||||||
Id makeStructResultType(Id type0, Id type1);
|
Id MakePairStructType(Id type0, Id type1);
|
||||||
Id makeVectorType(Id component, int size);
|
Id MakeVectorType(Id component_type, int component_count);
|
||||||
Id makeMatrixType(Id component, int cols, int rows);
|
Id MakeMatrix2DType(Id component_type, int cols, int rows);
|
||||||
Id makeArrayType(Id element, unsigned size);
|
Id MakeArrayType(Id element_type, int length);
|
||||||
Id makeRuntimeArray(Id element);
|
Id MakeRuntimeArray(Id element_type);
|
||||||
Id makeFunctionType(Id return_type, std::vector<Id>& param_types);
|
Id MakeFunctionType(Id return_type, std::initializer_list<Id> param_types);
|
||||||
Id makeImageType(Id sampledType, spv::Dim, bool depth, bool arrayed, bool ms,
|
Id MakeImageType(Id sampled_type, spv::Dim dim, bool has_depth,
|
||||||
unsigned sampled, spv::ImageFormat format);
|
bool is_arrayed, bool is_multisampled, int sampled,
|
||||||
Id makeSamplerType();
|
spv::ImageFormat format);
|
||||||
Id makeSampledImageType(Id imageType);
|
Id MakeSamplerType();
|
||||||
|
Id MakeSampledImageType(Id image_type);
|
||||||
|
|
||||||
// For querying about types.
|
// For querying about types.
|
||||||
Id getTypeId(Id result_id) const { return module_.getTypeId(result_id); }
|
Id GetTypeId(Id result_id) const { return module_.type_id(result_id); }
|
||||||
Id getDerefTypeId(Id result_id) const;
|
Id GetDerefTypeId(Id result_id) const;
|
||||||
Op getOpCode(Id id) const { return module_.getInstruction(id)->opcode(); }
|
Op GetOpcode(Id id) const { return module_.instruction(id)->opcode(); }
|
||||||
Op getTypeClass(Id type_id) const { return getOpCode(type_id); }
|
Op GetTypeClass(Id type_id) const { return GetOpcode(type_id); }
|
||||||
Op getMostBasicTypeClass(Id type_id) const;
|
Op GetMostBasicTypeClass(Id type_id) const;
|
||||||
int getNumComponents(Id result_id) const {
|
int GetComponentCount(Id result_id) const {
|
||||||
return getNumTypeComponents(getTypeId(result_id));
|
return GetTypeComponentCount(GetTypeId(result_id));
|
||||||
}
|
}
|
||||||
int getNumTypeComponents(Id type_id) const;
|
int GetTypeComponentCount(Id type_id) const;
|
||||||
Id getScalarTypeId(Id type_id) const;
|
Id GetScalarTypeId(Id type_id) const;
|
||||||
Id getContainedTypeId(Id type_id) const;
|
Id GetContainedTypeId(Id type_id) const;
|
||||||
Id getContainedTypeId(Id type_id, int) const;
|
Id GetContainedTypeId(Id type_id, int member) const;
|
||||||
spv::StorageClass getTypeStorageClass(Id type_id) const {
|
spv::StorageClass GetTypeStorageClass(Id type_id) const {
|
||||||
return module_.getStorageClass(type_id);
|
return module_.storage_class(type_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isPointer(Id result_id) const {
|
bool IsPointer(Id result_id) const {
|
||||||
return isPointerType(getTypeId(result_id));
|
return IsPointerType(GetTypeId(result_id));
|
||||||
}
|
}
|
||||||
bool isScalar(Id result_id) const {
|
bool IsScalar(Id result_id) const {
|
||||||
return isScalarType(getTypeId(result_id));
|
return IsScalarType(GetTypeId(result_id));
|
||||||
}
|
}
|
||||||
bool isVector(Id result_id) const {
|
bool IsVector(Id result_id) const {
|
||||||
return isVectorType(getTypeId(result_id));
|
return IsVectorType(GetTypeId(result_id));
|
||||||
}
|
}
|
||||||
bool isMatrix(Id result_id) const {
|
bool IsMatrix(Id result_id) const {
|
||||||
return isMatrixType(getTypeId(result_id));
|
return IsMatrixType(GetTypeId(result_id));
|
||||||
}
|
}
|
||||||
bool isAggregate(Id result_id) const {
|
bool IsAggregate(Id result_id) const {
|
||||||
return isAggregateType(getTypeId(result_id));
|
return IsAggregateType(GetTypeId(result_id));
|
||||||
}
|
}
|
||||||
bool isBoolType(Id type_id) const {
|
bool IsBoolType(Id type_id) const {
|
||||||
return grouped_types_[static_cast<int>(spv::Op::OpTypeBool)].size() > 0 &&
|
return grouped_types_[static_cast<int>(spv::Op::OpTypeBool)].size() > 0 &&
|
||||||
type_id ==
|
type_id ==
|
||||||
grouped_types_[static_cast<int>(spv::Op::OpTypeBool)]
|
grouped_types_[static_cast<int>(spv::Op::OpTypeBool)]
|
||||||
|
@ -152,222 +151,228 @@ class SpvEmitter {
|
||||||
->result_id();
|
->result_id();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isPointerType(Id type_id) const {
|
bool IsPointerType(Id type_id) const {
|
||||||
return getTypeClass(type_id) == spv::Op::OpTypePointer;
|
return GetTypeClass(type_id) == spv::Op::OpTypePointer;
|
||||||
}
|
}
|
||||||
bool isScalarType(Id type_id) const {
|
bool IsScalarType(Id type_id) const {
|
||||||
return getTypeClass(type_id) == spv::Op::OpTypeFloat ||
|
return GetTypeClass(type_id) == spv::Op::OpTypeFloat ||
|
||||||
getTypeClass(type_id) == spv::Op::OpTypeInt ||
|
GetTypeClass(type_id) == spv::Op::OpTypeInt ||
|
||||||
getTypeClass(type_id) == spv::Op::OpTypeBool;
|
GetTypeClass(type_id) == spv::Op::OpTypeBool;
|
||||||
}
|
}
|
||||||
bool isVectorType(Id type_id) const {
|
bool IsVectorType(Id type_id) const {
|
||||||
return getTypeClass(type_id) == spv::Op::OpTypeVector;
|
return GetTypeClass(type_id) == spv::Op::OpTypeVector;
|
||||||
}
|
}
|
||||||
bool isMatrixType(Id type_id) const {
|
bool IsMatrixType(Id type_id) const {
|
||||||
return getTypeClass(type_id) == spv::Op::OpTypeMatrix;
|
return GetTypeClass(type_id) == spv::Op::OpTypeMatrix;
|
||||||
}
|
}
|
||||||
bool isStructType(Id type_id) const {
|
bool IsStructType(Id type_id) const {
|
||||||
return getTypeClass(type_id) == spv::Op::OpTypeStruct;
|
return GetTypeClass(type_id) == spv::Op::OpTypeStruct;
|
||||||
}
|
}
|
||||||
bool isArrayType(Id type_id) const {
|
bool IsArrayType(Id type_id) const {
|
||||||
return getTypeClass(type_id) == spv::Op::OpTypeArray;
|
return GetTypeClass(type_id) == spv::Op::OpTypeArray;
|
||||||
}
|
}
|
||||||
bool isAggregateType(Id type_id) const {
|
bool IsAggregateType(Id type_id) const {
|
||||||
return isArrayType(type_id) || isStructType(type_id);
|
return IsArrayType(type_id) || IsStructType(type_id);
|
||||||
}
|
}
|
||||||
bool isImageType(Id type_id) const {
|
bool IsImageType(Id type_id) const {
|
||||||
return getTypeClass(type_id) == spv::Op::OpTypeImage;
|
return GetTypeClass(type_id) == spv::Op::OpTypeImage;
|
||||||
}
|
}
|
||||||
bool isSamplerType(Id type_id) const {
|
bool IsSamplerType(Id type_id) const {
|
||||||
return getTypeClass(type_id) == spv::Op::OpTypeSampler;
|
return GetTypeClass(type_id) == spv::Op::OpTypeSampler;
|
||||||
}
|
}
|
||||||
bool isSampledImageType(Id type_id) const {
|
bool IsSampledImageType(Id type_id) const {
|
||||||
return getTypeClass(type_id) == spv::Op::OpTypeSampledImage;
|
return GetTypeClass(type_id) == spv::Op::OpTypeSampledImage;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isConstantOpCode(Op opcode) const;
|
bool IsConstantOpCode(Op opcode) const;
|
||||||
bool isConstant(Id result_id) const {
|
bool IsConstant(Id result_id) const {
|
||||||
return isConstantOpCode(getOpCode(result_id));
|
return IsConstantOpCode(GetOpcode(result_id));
|
||||||
}
|
}
|
||||||
bool isConstantScalar(Id result_id) const {
|
bool IsConstantScalar(Id result_id) const {
|
||||||
return getOpCode(result_id) == spv::Op::OpConstant;
|
return GetOpcode(result_id) == spv::Op::OpConstant;
|
||||||
}
|
}
|
||||||
unsigned int getConstantScalar(Id result_id) const {
|
uint32_t GetConstantScalar(Id result_id) const {
|
||||||
return module_.getInstruction(result_id)->immediate_operand(0);
|
return module_.instruction(result_id)->immediate_operand(0);
|
||||||
}
|
}
|
||||||
spv::StorageClass getStorageClass(Id result_id) const {
|
spv::StorageClass GetStorageClass(Id result_id) const {
|
||||||
return getTypeStorageClass(getTypeId(result_id));
|
return GetTypeStorageClass(GetTypeId(result_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
int getTypeNumColumns(Id type_id) const {
|
int GetTypeColumnCount(Id type_id) const {
|
||||||
assert(isMatrixType(type_id));
|
assert(IsMatrixType(type_id));
|
||||||
return getNumTypeComponents(type_id);
|
return GetTypeComponentCount(type_id);
|
||||||
}
|
}
|
||||||
int getNumColumns(Id result_id) const {
|
int GetColumnCount(Id result_id) const {
|
||||||
return getTypeNumColumns(getTypeId(result_id));
|
return GetTypeColumnCount(GetTypeId(result_id));
|
||||||
}
|
}
|
||||||
int getTypeNumRows(Id type_id) const {
|
int GetTypeRowCount(Id type_id) const {
|
||||||
assert(isMatrixType(type_id));
|
assert(IsMatrixType(type_id));
|
||||||
return getNumTypeComponents(getContainedTypeId(type_id));
|
return GetTypeComponentCount(GetContainedTypeId(type_id));
|
||||||
}
|
}
|
||||||
int getNumRows(Id result_id) const {
|
int GetRowCount(Id result_id) const {
|
||||||
return getTypeNumRows(getTypeId(result_id));
|
return GetTypeRowCount(GetTypeId(result_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
spv::Dim getTypeDimensionality(Id type_id) const {
|
spv::Dim GetTypeDimensionality(Id type_id) const {
|
||||||
assert(isImageType(type_id));
|
assert(IsImageType(type_id));
|
||||||
return static_cast<spv::Dim>(
|
return static_cast<spv::Dim>(
|
||||||
module_.getInstruction(type_id)->immediate_operand(1));
|
module_.instruction(type_id)->immediate_operand(1));
|
||||||
}
|
}
|
||||||
Id getImageType(Id result_id) const {
|
Id GetImageType(Id result_id) const {
|
||||||
Id type_id = getTypeId(result_id);
|
Id type_id = GetTypeId(result_id);
|
||||||
assert(isImageType(type_id) || isSampledImageType(type_id));
|
assert(IsImageType(type_id) || IsSampledImageType(type_id));
|
||||||
return isSampledImageType(type_id)
|
return IsSampledImageType(type_id)
|
||||||
? module_.getInstruction(type_id)->id_operand(0)
|
? module_.instruction(type_id)->id_operand(0)
|
||||||
: type_id;
|
: type_id;
|
||||||
}
|
}
|
||||||
bool isArrayedImageType(Id type_id) const {
|
bool IsArrayedImageType(Id type_id) const {
|
||||||
assert(isImageType(type_id));
|
assert(IsImageType(type_id));
|
||||||
return module_.getInstruction(type_id)->immediate_operand(3) != 0;
|
return module_.instruction(type_id)->immediate_operand(3) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For making new constants (will return old constant if the requested one was
|
// For making new constants (will return old constant if the requested one was
|
||||||
// already made).
|
// already made).
|
||||||
Id makeBoolConstant(bool b, bool is_spec_constant = false);
|
Id MakeBoolConstant(bool value, bool is_spec_constant = false);
|
||||||
Id makeIntConstant(int i, bool is_spec_constant = false) {
|
Id MakeIntConstant(int value, bool is_spec_constant = false) {
|
||||||
return makeIntConstant(makeIntType(32), (unsigned)i, is_spec_constant);
|
return MakeIntegerConstant(MakeIntType(32), static_cast<uint32_t>(value),
|
||||||
|
is_spec_constant);
|
||||||
}
|
}
|
||||||
Id makeUintConstant(uint32_t u, bool is_spec_constant = false) {
|
Id MakeUintConstant(uint32_t value, bool is_spec_constant = false) {
|
||||||
return makeIntConstant(makeUintType(32), u, is_spec_constant);
|
return MakeIntegerConstant(MakeUintType(32), value, is_spec_constant);
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
Id makeUintConstant(T u, bool is_spec_constant = false) {
|
Id MakeUintConstant(T value, bool is_spec_constant = false) {
|
||||||
static_assert(sizeof(T) == sizeof(uint32_t), "Invalid type");
|
static_assert(sizeof(T) == sizeof(uint32_t), "Invalid type");
|
||||||
return makeIntConstant(makeUintType(32), static_cast<uint32_t>(u),
|
return MakeIntegerConstant(MakeUintType(32), static_cast<uint32_t>(value),
|
||||||
is_spec_constant);
|
is_spec_constant);
|
||||||
}
|
}
|
||||||
Id makeFloatConstant(float f, bool is_spec_constant = false);
|
Id MakeFloatConstant(float value, bool is_spec_constant = false);
|
||||||
Id makeDoubleConstant(double d, bool is_spec_constant = false);
|
Id MakeDoubleConstant(double value, bool is_spec_constant = false);
|
||||||
|
|
||||||
// Turn the array of constants into a proper spv constant of the requested
|
// Turns the array of constants into a proper constant of the requested type.
|
||||||
// type.
|
Id MakeCompositeConstant(Id type, std::initializer_list<Id> components);
|
||||||
Id makeCompositeConstant(Id type, std::vector<Id>& comps);
|
|
||||||
|
|
||||||
// Methods for adding information outside the CFG.
|
// Declares an entry point and its execution model.
|
||||||
Instruction* addEntryPoint(spv::ExecutionModel, Function*, const char* name);
|
Instruction* AddEntryPoint(spv::ExecutionModel execution_model,
|
||||||
void addExecutionMode(Function*, spv::ExecutionMode mode, int value1 = -1,
|
Function* entry_point, const char* name);
|
||||||
|
void AddExecutionMode(Function* entry_point,
|
||||||
|
spv::ExecutionMode execution_mode, int value1 = -1,
|
||||||
int value2 = -1, int value3 = -1);
|
int value2 = -1, int value3 = -1);
|
||||||
void addName(Id, const char* name);
|
void AddName(Id target_id, const char* name);
|
||||||
void addMemberName(Id, int member, const char* name);
|
void AddMemberName(Id target_id, int member, const char* name);
|
||||||
void addLine(Id target, Id file_name, int line, int column);
|
void AddLine(Id target_id, Id file_name, int line_number, int column_number);
|
||||||
void addDecoration(Id, spv::Decoration, int num = -1);
|
void AddDecoration(Id target_id, spv::Decoration decoration, int num = -1);
|
||||||
void addMemberDecoration(Id, unsigned int member, spv::Decoration,
|
void AddMemberDecoration(Id target_id, int member, spv::Decoration,
|
||||||
int num = -1);
|
int num = -1);
|
||||||
|
|
||||||
// At the end of what block do the next create*() instructions go?
|
// At the end of what block do the next create*() instructions go?
|
||||||
Block* build_point() const { return build_point_; }
|
Block* build_point() const { return build_point_; }
|
||||||
void set_build_point(Block* build_point) { build_point_ = build_point; }
|
void set_build_point(Block* build_point) { build_point_ = build_point; }
|
||||||
|
|
||||||
// Make the main function.
|
// Makes the main function.
|
||||||
Function* makeMain();
|
Function* MakeMainEntry();
|
||||||
|
|
||||||
// Make a shader-style function, and create its entry block if entry is
|
// Makes a shader-style function, and create its entry block if entry is
|
||||||
// non-zero.
|
// non-zero.
|
||||||
// Return the function, pass back the entry.
|
// Return the function, pass back the entry.
|
||||||
Function* makeFunctionEntry(Id return_type, const char* name,
|
Function* MakeFunctionEntry(Id return_type, const char* name,
|
||||||
std::vector<Id>& param_types, Block** entry = 0);
|
std::initializer_list<Id> param_types,
|
||||||
|
Block** entry = 0);
|
||||||
|
|
||||||
// Create a return. An 'implicit' return is one not appearing in the source
|
// Creates a return statement.
|
||||||
// code. In the case of an implicit return, no post-return block is inserted.
|
// An 'implicit' return is one not appearing in the source code. In the case
|
||||||
void makeReturn(bool implicit, Id retVal = 0);
|
// of an implicit return, no post-return block is inserted.
|
||||||
|
void MakeReturn(bool implicit, Id return_value = 0);
|
||||||
|
|
||||||
// Generate all the code needed to finish up a function.
|
// Generates all the code needed to finish up a function.
|
||||||
void leaveFunction();
|
void LeaveFunction();
|
||||||
|
|
||||||
// Create a discard.
|
// Creates a fragment-shader discard (kill).
|
||||||
void makeDiscard();
|
void MakeDiscard();
|
||||||
|
|
||||||
// Create a global or function local or IO variable.
|
// Creates a global or function local or IO variable.
|
||||||
Id createVariable(spv::StorageClass storage_class, Id type,
|
Id CreateVariable(spv::StorageClass storage_class, Id type,
|
||||||
const char* name = 0);
|
const char* name = 0);
|
||||||
|
|
||||||
// Create an imtermediate with an undefined value.
|
// Creates an intermediate object whose value is undefined.
|
||||||
Id createUndefined(Id type);
|
Id CreateUndefined(Id type);
|
||||||
|
|
||||||
// Store into an Id and return the l-value
|
// Stores the given value into the specified pointer.
|
||||||
void createStore(Id rvalue, Id lvalue);
|
void CreateStore(Id pointer_id, Id value_id);
|
||||||
|
|
||||||
// Load from an Id and return it
|
// Loads the value from the given pointer.
|
||||||
Id createLoad(Id lvalue);
|
Id CreateLoad(Id pointer_id);
|
||||||
|
|
||||||
// Create an OpAccessChain instruction
|
// Creates a pointer into a composite object that can be used with OpLoad and
|
||||||
Id createAccessChain(spv::StorageClass storage_class, Id base,
|
// OpStore.
|
||||||
std::vector<Id>& offsets);
|
Id CreateAccessChain(spv::StorageClass storage_class, Id base_id,
|
||||||
|
std::vector<Id> index_ids);
|
||||||
|
|
||||||
// Create an OpArrayLength instruction
|
// Queries the length of a run-time array.
|
||||||
Id createArrayLength(Id base, unsigned int member);
|
Id CreateArrayLength(Id struct_id, int array_member);
|
||||||
|
|
||||||
// Create an OpCompositeExtract instruction
|
Id CreateCompositeExtract(Id composite, Id type_id, uint32_t index);
|
||||||
Id createCompositeExtract(Id composite, Id type_id, unsigned index);
|
Id CreateCompositeExtract(Id composite, Id type_id,
|
||||||
Id createCompositeExtract(Id composite, Id type_id,
|
std::vector<uint32_t> indexes);
|
||||||
std::vector<unsigned>& indexes);
|
Id CreateCompositeInsert(Id object, Id composite, Id type_id, uint32_t index);
|
||||||
Id createCompositeInsert(Id object, Id composite, Id type_id, unsigned index);
|
Id CreateCompositeInsert(Id object, Id composite, Id type_id,
|
||||||
Id createCompositeInsert(Id object, Id composite, Id type_id,
|
std::vector<uint32_t> indexes);
|
||||||
std::vector<unsigned>& indexes);
|
|
||||||
|
|
||||||
Id createVectorExtractDynamic(Id vector, Id type_id, Id component_index);
|
Id CreateVectorExtractDynamic(Id vector, Id type_id, Id component_index);
|
||||||
Id createVectorInsertDynamic(Id vector, Id type_id, Id component,
|
Id CreateVectorInsertDynamic(Id vector, Id type_id, Id component,
|
||||||
Id component_index);
|
Id component_index);
|
||||||
|
|
||||||
void createNoResultOp(Op);
|
// Does nothing.
|
||||||
void createNoResultOp(Op, Id operand);
|
void CreateNop();
|
||||||
void createNoResultOp(Op, const std::vector<Id>& operands);
|
|
||||||
void createControlBarrier(spv::Scope execution, spv::Scope memory,
|
|
||||||
spv::MemorySemanticsMask);
|
|
||||||
void createMemoryBarrier(unsigned execution_scope, unsigned memory_semantics);
|
|
||||||
Id createUnaryOp(Op, Id type_id, Id operand);
|
|
||||||
Id createBinOp(Op, Id type_id, Id operand1, Id operand2);
|
|
||||||
Id createTriOp(Op, Id type_id, Id operand1, Id operand2, Id operand3);
|
|
||||||
Id createOp(Op, Id type_id, const std::vector<Id>& operands);
|
|
||||||
Id createFunctionCall(Function*, std::vector<spv::Id>&);
|
|
||||||
|
|
||||||
// Take an rvalue (source) and a set of channels to extract from it to
|
// Waits for other invocations of this module to reach the current point of
|
||||||
// make a new rvalue, which is returned.
|
// execution.
|
||||||
Id createRvalueSwizzle(Id type_id, Id source,
|
void CreateControlBarrier(spv::Scope execution_scope, spv::Scope memory_scope,
|
||||||
std::vector<unsigned>& channels);
|
spv::MemorySemanticsMask memory_semantics);
|
||||||
|
// Controls the order that memory accesses are observed.
|
||||||
|
void CreateMemoryBarrier(spv::Scope execution_scope,
|
||||||
|
spv::MemorySemanticsMask memory_semantics);
|
||||||
|
|
||||||
// Take a copy of an lvalue (target) and a source of components, and set the
|
Id CreateUnaryOp(Op opcode, Id type_id, Id operand);
|
||||||
|
Id CreateBinOp(Op opcode, Id type_id, Id operand1, Id operand2);
|
||||||
|
Id CreateTriOp(Op opcode, Id type_id, Id operand1, Id operand2, Id operand3);
|
||||||
|
Id CreateOp(Op opcode, Id type_id, const std::vector<Id>& operands);
|
||||||
|
Id CreateFunctionCall(Function* function, std::vector<spv::Id> args);
|
||||||
|
|
||||||
|
// Takes an rvalue (source) and a set of channels to extract from it to
|
||||||
|
// make a new rvalue.
|
||||||
|
Id CreateSwizzle(Id type_id, Id source, std::vector<uint32_t> channels);
|
||||||
|
|
||||||
|
// Takes a copy of an lvalue (target) and a source of components, and sets the
|
||||||
// source components into the lvalue where the 'channels' say to put them.
|
// source components into the lvalue where the 'channels' say to put them.
|
||||||
// An updated version of the target is returned.
|
Id CreateLvalueSwizzle(Id type_id, Id target, Id source,
|
||||||
// (No true lvalue or stores are used.)
|
std::vector<uint32_t> channels);
|
||||||
Id createLvalueSwizzle(Id type_id, Id target, Id source,
|
|
||||||
std::vector<unsigned>& channels);
|
|
||||||
|
|
||||||
// If the value passed in is an instruction and the precision is not EMpNone,
|
// If the value passed in is an instruction and the precision is not EMpNone,
|
||||||
// it gets tagged with the requested precision.
|
// it gets tagged with the requested precision.
|
||||||
void setPrecision(Id value, spv::Decoration precision) {
|
void SetPrecision(Id value, spv::Decoration precision) {
|
||||||
CheckNotImplemented("setPrecision");
|
CheckNotImplemented("setPrecision");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Can smear a scalar to a vector for the following forms:
|
// Smears a scalar to a vector for the following forms:
|
||||||
// - promoteScalar(scalar, vector) // smear scalar to width of vector
|
// - PromoteScalar(scalar, vector) // smear scalar to width of vector
|
||||||
// - promoteScalar(vector, scalar) // smear scalar to width of vector
|
// - PromoteScalar(vector, scalar) // smear scalar to width of vector
|
||||||
// - promoteScalar(pointer, scalar) // smear scalar to width of what pointer
|
// - PromoteScalar(pointer, scalar) // smear scalar to width of what pointer
|
||||||
// points to
|
// points to
|
||||||
// - promoteScalar(scalar, scalar) // do nothing
|
// - PromoteScalar(scalar, scalar) // do nothing
|
||||||
// Other forms are not allowed.
|
// Other forms are not allowed.
|
||||||
//
|
//
|
||||||
// Note: One of the arguments will change, with the result coming back that
|
// Note: One of the arguments will change, with the result coming back that
|
||||||
// way rather than
|
// way rather than through the return value.
|
||||||
// through the return value.
|
void PromoteScalar(spv::Decoration precision, Id& left, Id& right);
|
||||||
void promoteScalar(spv::Decoration precision, Id& left, Id& right);
|
|
||||||
|
|
||||||
// make a value by smearing the scalar to fill the type
|
// Makes a value by smearing the scalar to fill the type.
|
||||||
Id smearScalar(spv::Decoration precision, Id scalarVal, Id);
|
Id SmearScalar(spv::Decoration precision, Id scalar_value, Id vector_type_id);
|
||||||
|
|
||||||
// Create a call to a built-in function.
|
// Executes an instruction in an imported set of extended instructions.
|
||||||
Id createBuiltinCall(spv::Decoration precision, Id result_type, Id builtins,
|
Id CreateExtendedInstructionCall(spv::Decoration precision, Id result_type,
|
||||||
int entry_point, std::initializer_list<Id> args);
|
Id instruction_set, int instruction_ordinal,
|
||||||
|
std::initializer_list<Id> args);
|
||||||
|
|
||||||
// List of parameters used to create a texture operation
|
// List of parameters used to create a texture operation
|
||||||
struct TextureParameters {
|
struct TextureParameters {
|
||||||
|
@ -375,45 +380,45 @@ class SpvEmitter {
|
||||||
Id coords;
|
Id coords;
|
||||||
Id bias;
|
Id bias;
|
||||||
Id lod;
|
Id lod;
|
||||||
Id Dref;
|
Id depth_ref;
|
||||||
Id offset;
|
Id offset;
|
||||||
Id offsets;
|
Id offsets;
|
||||||
Id gradX;
|
Id grad_x;
|
||||||
Id gradY;
|
Id grad_y;
|
||||||
Id sample;
|
Id sample;
|
||||||
Id comp;
|
Id comp;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Select the correct texture operation based on all inputs, and emit the
|
// Selects the correct texture operation based on all inputs, and emit the
|
||||||
// correct instruction
|
// correct instruction.
|
||||||
Id createTextureCall(spv::Decoration precision, Id result_type, bool fetch,
|
Id CreateTextureCall(spv::Decoration precision, Id result_type, bool fetch,
|
||||||
bool proj, bool gather, const TextureParameters&);
|
bool proj, bool gather,
|
||||||
|
const TextureParameters& parameters);
|
||||||
|
|
||||||
// Emit the OpTextureQuery* instruction that was passed in.
|
// Emits the OpTextureQuery* instruction that was passed in and figures out
|
||||||
// Figure out the right return value and type, and return it.
|
// the right return value and type.
|
||||||
Id createTextureQueryCall(Op, const TextureParameters&);
|
Id CreateTextureQueryCall(Op opcode, const TextureParameters& parameters);
|
||||||
|
|
||||||
Id createSamplePositionCall(spv::Decoration precision, Id, Id);
|
Id CreateSamplePositionCall(spv::Decoration precision, Id, Id);
|
||||||
|
Id CreateBitFieldExtractCall(spv::Decoration precision, Id, Id, Id,
|
||||||
Id createBitFieldExtractCall(spv::Decoration precision, Id, Id, Id,
|
|
||||||
bool isSigned);
|
bool isSigned);
|
||||||
Id createBitFieldInsertCall(spv::Decoration precision, Id, Id, Id, Id);
|
Id CreateBitFieldInsertCall(spv::Decoration precision, Id, Id, Id, Id);
|
||||||
|
|
||||||
// Reduction comparision for composites: For equal and not-equal resulting in
|
// Reduction comparision for composites: For equal and not-equal resulting in
|
||||||
// a scalar.
|
// a scalar.
|
||||||
Id createCompare(spv::Decoration precision, Id, Id,
|
Id CreateCompare(spv::Decoration precision, Id value1, Id value2,
|
||||||
bool /* true if for equal, fales if for not-equal */);
|
bool is_equal);
|
||||||
|
|
||||||
// OpCompositeConstruct
|
// OpCompositeConstruct
|
||||||
Id createCompositeConstruct(Id type_id, std::vector<Id>& constituents);
|
Id CreateCompositeConstruct(Id type_id, std::vector<Id> constituent_ids);
|
||||||
|
|
||||||
// vector or scalar constructor
|
// vector or scalar constructor
|
||||||
Id createConstructor(spv::Decoration precision,
|
Id CreateConstructor(spv::Decoration precision, std::vector<Id> source_ids,
|
||||||
const std::vector<Id>& sources, Id result_type_id);
|
Id result_type_id);
|
||||||
|
|
||||||
// matrix constructor
|
// matrix constructor
|
||||||
Id createMatrixConstructor(spv::Decoration precision,
|
Id CreateMatrixConstructor(spv::Decoration precision, std::vector<Id> sources,
|
||||||
const std::vector<Id>& sources, Id constructee);
|
Id constructee);
|
||||||
|
|
||||||
// Helper to use for building nested control flow with if-then-else.
|
// Helper to use for building nested control flow with if-then-else.
|
||||||
class If {
|
class If {
|
||||||
|
@ -421,8 +426,8 @@ class SpvEmitter {
|
||||||
If(SpvEmitter& emitter, Id condition);
|
If(SpvEmitter& emitter, Id condition);
|
||||||
~If() = default;
|
~If() = default;
|
||||||
|
|
||||||
void makeBeginElse();
|
void MakeBeginElse();
|
||||||
void makeEndIf();
|
void MakeEndIf();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
If(const If&) = delete;
|
If(const If&) = delete;
|
||||||
|
@ -437,7 +442,7 @@ class SpvEmitter {
|
||||||
Block* merge_block_ = nullptr;
|
Block* merge_block_ = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Make a switch statement.
|
// Makes a switch statement.
|
||||||
// A switch has 'numSegments' of pieces of code, not containing any
|
// A switch has 'numSegments' of pieces of code, not containing any
|
||||||
// case/default labels, all separated by one or more case/default labels.
|
// case/default labels, all separated by one or more case/default labels.
|
||||||
// Each possible case value v is a jump to the caseValues[v] segment. The
|
// Each possible case value v is a jump to the caseValues[v] segment. The
|
||||||
|
@ -452,46 +457,46 @@ class SpvEmitter {
|
||||||
//
|
//
|
||||||
// Returns the right set of basic blocks to start each code segment with, so
|
// Returns the right set of basic blocks to start each code segment with, so
|
||||||
// that the caller's recursion stack can hold the memory for it.
|
// that the caller's recursion stack can hold the memory for it.
|
||||||
void makeSwitch(Id condition, int numSegments, std::vector<int>& caseValues,
|
void MakeSwitch(Id condition, int segment_count, std::vector<int> case_values,
|
||||||
std::vector<int>& valueToSegment, int defaultSegment,
|
std::vector<int> value_index_to_segment, int default_segment,
|
||||||
std::vector<Block*>& segmentBB); // return argument
|
std::vector<Block*>& segment_blocks);
|
||||||
|
|
||||||
// Add a branch to the innermost switch's merge block.
|
// Adds a branch to the innermost switch's merge block.
|
||||||
void addSwitchBreak();
|
void AddSwitchBreak();
|
||||||
|
|
||||||
// Move to the next code segment, passing in the return argument in
|
// Move sto the next code segment, passing in the return argument in
|
||||||
// makeSwitch()
|
// MakeSwitch().
|
||||||
void nextSwitchSegment(std::vector<Block*>& segmentBB, int segment);
|
void NextSwitchSegment(std::vector<Block*>& segment_block, int next_segment);
|
||||||
|
|
||||||
// Finish off the innermost switch.
|
// Finishes off the innermost switch.
|
||||||
void endSwitch(std::vector<Block*>& segmentBB);
|
void EndSwitch(std::vector<Block*>& segment_block);
|
||||||
|
|
||||||
// Start the beginning of a new loop, and prepare the builder to
|
// Starts the beginning of a new loop, and prepare the builder to
|
||||||
// generate code for the loop test.
|
// generate code for the loop test.
|
||||||
// The loopTestFirst parameter is true when the loop test executes before
|
// The test_first parameter is true when the loop test executes before
|
||||||
// the body. (It is false for do-while loops.)
|
// the body (it is false for do-while loops).
|
||||||
void makeNewLoop(bool loopTestFirst);
|
void MakeNewLoop(bool test_first);
|
||||||
|
|
||||||
// Add the branch for the loop test, based on the given condition.
|
// Adds the branch for the loop test, based on the given condition.
|
||||||
// The true branch goes to the first block in the loop body, and
|
// The true branch goes to the first block in the loop body, and
|
||||||
// the false branch goes to the loop's merge block. The builder insertion
|
// the false branch goes to the loop's merge block. The builder insertion
|
||||||
// point will be placed at the start of the body.
|
// point will be placed at the start of the body.
|
||||||
void createLoopTestBranch(Id condition);
|
void CreateLoopTestBranch(Id condition);
|
||||||
|
|
||||||
// Generate an unconditional branch to the loop body. The builder insertion
|
// Generates an unconditional branch to the loop body.
|
||||||
// point will be placed at the start of the body. Use this when there is
|
// The builder insertion point will be placed at the start of the body.
|
||||||
// no loop test.
|
// Use this when there is no loop test.
|
||||||
void createBranchToBody();
|
void CreateBranchToBody();
|
||||||
|
|
||||||
// Add a branch to the test of the current (innermost) loop.
|
// Adds a branch to the test of the current (innermost) loop.
|
||||||
// The way we generate code, that's also the loop header.
|
// The way we generate code, that's also the loop header.
|
||||||
void createLoopContinue();
|
void CreateLoopContinue();
|
||||||
|
|
||||||
// Add an exit (e.g. "break") for the innermost loop that you're in
|
// Adds an exit (e.g. "break") for the innermost loop that you're in.
|
||||||
void createLoopExit();
|
void CreateLoopExit();
|
||||||
|
|
||||||
// Close the innermost loop that you're in
|
// Close the innermost loop that you're in.
|
||||||
void closeLoop();
|
void CloseLoop();
|
||||||
|
|
||||||
// Access chain design for an R-Value vs. L-Value:
|
// Access chain design for an R-Value vs. L-Value:
|
||||||
//
|
//
|
||||||
|
@ -528,7 +533,7 @@ class SpvEmitter {
|
||||||
// base object
|
// base object
|
||||||
std::vector<Id> index_chain;
|
std::vector<Id> index_chain;
|
||||||
Id instr; // cache the instruction that generates this access chain
|
Id instr; // cache the instruction that generates this access chain
|
||||||
std::vector<unsigned> swizzle; // each std::vector element selects the next
|
std::vector<uint32_t> swizzle; // each std::vector element selects the next
|
||||||
// GLSL component number
|
// GLSL component number
|
||||||
Id component; // a dynamic component index, can coexist with a swizzle,
|
Id component; // a dynamic component index, can coexist with a swizzle,
|
||||||
// done after the swizzle, NoResult if not present
|
// done after the swizzle, NoResult if not present
|
||||||
|
@ -549,83 +554,98 @@ class SpvEmitter {
|
||||||
AccessChain access_chain() { return access_chain_; }
|
AccessChain access_chain() { return access_chain_; }
|
||||||
void set_access_chain(AccessChain new_chain) { access_chain_ = new_chain; }
|
void set_access_chain(AccessChain new_chain) { access_chain_ = new_chain; }
|
||||||
|
|
||||||
// clear accessChain
|
void ClearAccessChain();
|
||||||
void clearAccessChain();
|
|
||||||
|
|
||||||
// set new base as an l-value base
|
// set new base as an l-value base
|
||||||
void setAccessChainLValue(Id lvalue) {
|
void set_access_chain_lvalue(Id lvalue) {
|
||||||
assert(isPointer(lvalue));
|
assert(IsPointer(lvalue));
|
||||||
access_chain_.base = lvalue;
|
access_chain_.base = lvalue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// set new base value as an r-value
|
// set new base value as an r-value
|
||||||
void setAccessChainRValue(Id rvalue) {
|
void set_access_chain_rvalue(Id rvalue) {
|
||||||
access_chain_.is_rvalue = true;
|
access_chain_.is_rvalue = true;
|
||||||
access_chain_.base = rvalue;
|
access_chain_.base = rvalue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// push offset onto the end of the chain
|
// push offset onto the end of the chain
|
||||||
void accessChainPush(Id offset) {
|
void PushAccessChainOffset(Id offset) {
|
||||||
access_chain_.index_chain.push_back(offset);
|
access_chain_.index_chain.push_back(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
// push new swizzle onto the end of any existing swizzle, merging into a
|
// push new swizzle onto the end of any existing swizzle, merging into a
|
||||||
// single swizzle
|
// single swizzle
|
||||||
void accessChainPushSwizzle(std::vector<unsigned>& swizzle,
|
void PushAccessChainSwizzle(std::vector<uint32_t> swizzle,
|
||||||
Id pre_swizzle_base_type);
|
Id pre_swizzle_base_type);
|
||||||
|
|
||||||
// push a variable component selection onto the access chain; supporting only
|
// push a variable component selection onto the access chain; supporting only
|
||||||
// one, so unsided
|
// one, so unsided
|
||||||
void accessChainPushComponent(Id component, Id pre_swizzle_base_type) {
|
void PushAccessChainComponent(Id component, Id pre_swizzle_base_type) {
|
||||||
access_chain_.component = component;
|
access_chain_.component = component;
|
||||||
if (access_chain_.pre_swizzle_base_type == NoType)
|
if (access_chain_.pre_swizzle_base_type == NoType) {
|
||||||
access_chain_.pre_swizzle_base_type = pre_swizzle_base_type;
|
access_chain_.pre_swizzle_base_type = pre_swizzle_base_type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// use accessChain and swizzle to store value
|
// use accessChain and swizzle to store value
|
||||||
void accessChainStore(Id rvalue);
|
void CreateAccessChainStore(Id rvalue);
|
||||||
|
|
||||||
// use accessChain and swizzle to load an r-value
|
// use accessChain and swizzle to load an r-value
|
||||||
Id accessChainLoad(Id result_type);
|
Id CreateAccessChainLoad(Id result_type_id);
|
||||||
|
|
||||||
// get the direct pointer for an l-value
|
// get the direct pointer for an l-value
|
||||||
Id accessChainGetLValue();
|
Id CreateAccessChainLValue();
|
||||||
|
|
||||||
void dump(std::vector<unsigned int>&) const;
|
void Serialize(std::vector<uint32_t>& out) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Maximum dimension for column/row in a matrix.
|
// Maximum dimension for column/row in a matrix.
|
||||||
static const int kMaxMatrixSize = 4;
|
static const int kMaxMatrixSize = 4;
|
||||||
|
|
||||||
// Asserts on unimplemnted functionality.
|
// Allocates a new <id>.
|
||||||
void CheckNotImplemented(const char* message);
|
Id AllocateUniqueId() { return ++unique_id_; }
|
||||||
|
|
||||||
Id makeIntConstant(Id type_id, unsigned value, bool is_spec_constant);
|
// Allocates a contiguous sequence of <id>s.
|
||||||
Id findScalarConstant(Op type_class, Op opcode, Id type_id,
|
Id AllocateUniqueIds(int count) {
|
||||||
unsigned value) const;
|
Id id = unique_id_ + 1;
|
||||||
Id findScalarConstant(Op type_class, Op opcode, Id type_id, unsigned v1,
|
unique_id_ += count;
|
||||||
unsigned v2) const;
|
return id;
|
||||||
Id findCompositeConstant(Op type_class, std::vector<Id>& comps) const;
|
}
|
||||||
Id collapseAccessChain();
|
|
||||||
void transferAccessChainSwizzle(bool dynamic);
|
Id MakeIntegerConstant(Id type_id, uint32_t value, bool is_spec_constant);
|
||||||
void simplifyAccessChainSwizzle();
|
Id FindScalarConstant(Op type_class, Op opcode, Id type_id,
|
||||||
void createAndSetNoPredecessorBlock(const char*);
|
uint32_t value) const;
|
||||||
void createBranch(Block* block);
|
Id FindScalarConstant(Op type_class, Op opcode, Id type_id, uint32_t v1,
|
||||||
void createSelectionMerge(Block* merge_block,
|
uint32_t v2) const;
|
||||||
|
Id FindCompositeConstant(Op type_class,
|
||||||
|
std::initializer_list<Id> components) const;
|
||||||
|
|
||||||
|
Id CollapseAccessChain();
|
||||||
|
void SimplifyAccessChainSwizzle();
|
||||||
|
void TransferAccessChainSwizzle(bool dynamic);
|
||||||
|
|
||||||
|
void SerializeInstructions(
|
||||||
|
std::vector<uint32_t>& out,
|
||||||
|
const std::vector<Instruction*>& instructions) const;
|
||||||
|
|
||||||
|
void CreateAndSetNoPredecessorBlock(const char* name);
|
||||||
|
void CreateBranch(Block* block);
|
||||||
|
void CreateSelectionMerge(Block* merge_block,
|
||||||
spv::SelectionControlMask control);
|
spv::SelectionControlMask control);
|
||||||
void createLoopMerge(Block* merge_block, Block* continueBlock,
|
void CreateLoopMerge(Block* merge_block, Block* continueBlock,
|
||||||
spv::LoopControlMask control);
|
spv::LoopControlMask control);
|
||||||
void createConditionalBranch(Id condition, Block* then_block,
|
void CreateConditionalBranch(Id condition, Block* then_block,
|
||||||
Block* else_block);
|
Block* else_block);
|
||||||
void dumpInstructions(std::vector<unsigned int>&,
|
|
||||||
const std::vector<Instruction*>&) const;
|
|
||||||
|
|
||||||
struct Loop; // Defined below.
|
struct Loop; // Defined below.
|
||||||
void createBranchToLoopHeaderFromInside(const Loop& loop);
|
void CreateBranchToLoopHeaderFromInside(const Loop& loop);
|
||||||
|
|
||||||
|
// Asserts on unimplemented functionality.
|
||||||
|
void CheckNotImplemented(const char* message);
|
||||||
|
|
||||||
spv::SourceLanguage source_language_ = spv::SourceLanguage::Unknown;
|
spv::SourceLanguage source_language_ = spv::SourceLanguage::Unknown;
|
||||||
int source_version_ = 0;
|
int source_version_ = 0;
|
||||||
std::vector<const char*> extensions_;
|
std::vector<const char*> source_extensions_;
|
||||||
spv::AddressingModel addressing_model_ = spv::AddressingModel::Logical;
|
spv::AddressingModel addressing_model_ = spv::AddressingModel::Logical;
|
||||||
spv::MemoryModel memory_model_ = spv::MemoryModel::GLSL450;
|
spv::MemoryModel memory_model_ = spv::MemoryModel::GLSL450;
|
||||||
std::vector<spv::Capability> capabilities_;
|
std::vector<spv::Capability> capabilities_;
|
||||||
|
@ -647,12 +667,13 @@ class SpvEmitter {
|
||||||
std::vector<Instruction*> externals_;
|
std::vector<Instruction*> externals_;
|
||||||
|
|
||||||
// not output, internally used for quick & dirty canonical (unique) creation
|
// not output, internally used for quick & dirty canonical (unique) creation
|
||||||
std::vector<Instruction*> grouped_constants_[static_cast<int>(
|
// All types appear before OpConstant.
|
||||||
spv::Op::OpConstant)]; // all types appear before OpConstant
|
std::vector<Instruction*>
|
||||||
|
grouped_constants_[static_cast<int>(spv::Op::OpConstant)];
|
||||||
std::vector<Instruction*>
|
std::vector<Instruction*>
|
||||||
grouped_types_[static_cast<int>(spv::Op::OpConstant)];
|
grouped_types_[static_cast<int>(spv::Op::OpConstant)];
|
||||||
|
|
||||||
// stack of switches
|
// Stack of switches.
|
||||||
std::stack<Block*> switch_merges_;
|
std::stack<Block*> switch_merges_;
|
||||||
|
|
||||||
// Data that needs to be kept in order to properly handle loops.
|
// Data that needs to be kept in order to properly handle loops.
|
||||||
|
|
|
@ -86,55 +86,66 @@ class Instruction {
|
||||||
explicit Instruction(Op opcode) : opcode_(opcode) {}
|
explicit Instruction(Op opcode) : opcode_(opcode) {}
|
||||||
~Instruction() = default;
|
~Instruction() = default;
|
||||||
|
|
||||||
void addIdOperand(Id id) { operands_.push_back(id); }
|
void AddIdOperand(Id id) { operands_.push_back(id); }
|
||||||
|
|
||||||
void addIdOperands(const std::vector<Id>& ids) {
|
void AddIdOperands(const std::vector<Id>& ids) {
|
||||||
|
for (auto id : ids) {
|
||||||
|
operands_.push_back(id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void AddIdOperands(std::initializer_list<Id> ids) {
|
||||||
for (auto id : ids) {
|
for (auto id : ids) {
|
||||||
operands_.push_back(id);
|
operands_.push_back(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addImmediateOperand(uint32_t immediate) {
|
void AddImmediateOperand(uint32_t immediate) {
|
||||||
operands_.push_back(immediate);
|
operands_.push_back(immediate);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void addImmediateOperand(T immediate) {
|
void AddImmediateOperand(T immediate) {
|
||||||
static_assert(sizeof(T) == sizeof(uint32_t), "Invalid operand size");
|
static_assert(sizeof(T) == sizeof(uint32_t), "Invalid operand size");
|
||||||
operands_.push_back(static_cast<uint32_t>(immediate));
|
operands_.push_back(static_cast<uint32_t>(immediate));
|
||||||
}
|
}
|
||||||
|
|
||||||
void addImmediateOperands(const std::vector<uint32_t>& immediates) {
|
void AddImmediateOperands(const std::vector<uint32_t>& immediates) {
|
||||||
for (auto immediate : immediates) {
|
for (auto immediate : immediates) {
|
||||||
operands_.push_back(immediate);
|
operands_.push_back(immediate);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void addStringOperand(const char* str) {
|
void AddImmediateOperands(std::initializer_list<uint32_t> immediates) {
|
||||||
|
for (auto immediate : immediates) {
|
||||||
|
operands_.push_back(immediate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AddStringOperand(const char* str) {
|
||||||
original_string_ = str;
|
original_string_ = str;
|
||||||
uint32_t word;
|
uint32_t word;
|
||||||
char* wordString = (char*)&word;
|
char* word_string = reinterpret_cast<char*>(&word);
|
||||||
char* wordPtr = wordString;
|
char* word_ptr = word_string;
|
||||||
int charCount = 0;
|
int char_count = 0;
|
||||||
char c;
|
char c;
|
||||||
do {
|
do {
|
||||||
c = *(str++);
|
c = *(str++);
|
||||||
*(wordPtr++) = c;
|
*(word_ptr++) = c;
|
||||||
++charCount;
|
++char_count;
|
||||||
if (charCount == 4) {
|
if (char_count == 4) {
|
||||||
addImmediateOperand(word);
|
AddImmediateOperand(word);
|
||||||
wordPtr = wordString;
|
word_ptr = word_string;
|
||||||
charCount = 0;
|
char_count = 0;
|
||||||
}
|
}
|
||||||
} while (c != 0);
|
} while (c != 0);
|
||||||
|
|
||||||
// deal with partial last word
|
// deal with partial last word
|
||||||
if (charCount > 0) {
|
if (char_count > 0) {
|
||||||
// pad with 0s
|
// pad with 0s
|
||||||
for (; charCount < 4; ++charCount) {
|
for (; char_count < 4; ++char_count) {
|
||||||
*(wordPtr++) = 0;
|
*(word_ptr++) = 0;
|
||||||
}
|
}
|
||||||
addImmediateOperand(word);
|
AddImmediateOperand(word);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,17 +158,17 @@ class Instruction {
|
||||||
const char* string_operand() const { return original_string_.c_str(); }
|
const char* string_operand() const { return original_string_.c_str(); }
|
||||||
|
|
||||||
// Write out the binary form.
|
// Write out the binary form.
|
||||||
void dump(std::vector<uint32_t>& out) const {
|
void Serialize(std::vector<uint32_t>& out) const {
|
||||||
uint32_t wordCount = 1;
|
uint32_t word_count = 1;
|
||||||
if (type_id_) {
|
if (type_id_) {
|
||||||
++wordCount;
|
++word_count;
|
||||||
}
|
}
|
||||||
if (result_id_) {
|
if (result_id_) {
|
||||||
++wordCount;
|
++word_count;
|
||||||
}
|
}
|
||||||
wordCount += static_cast<uint32_t>(operands_.size());
|
word_count += static_cast<uint32_t>(operands_.size());
|
||||||
|
|
||||||
out.push_back((wordCount << spv::WordCountShift) |
|
out.push_back((word_count << spv::WordCountShift) |
|
||||||
static_cast<uint32_t>(opcode_));
|
static_cast<uint32_t>(opcode_));
|
||||||
if (type_id_) {
|
if (type_id_) {
|
||||||
out.push_back(type_id_);
|
out.push_back(type_id_);
|
||||||
|
@ -185,19 +196,24 @@ class Block {
|
||||||
public:
|
public:
|
||||||
Block(Id id, Function& parent);
|
Block(Id id, Function& parent);
|
||||||
~Block() {
|
~Block() {
|
||||||
// TODO: free instructions
|
for (size_t i = 0; i < instructions_.size(); ++i) {
|
||||||
|
delete instructions_[i];
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < local_variables_.size(); ++i) {
|
||||||
|
delete local_variables_[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Id id() { return instructions_.front()->result_id(); }
|
Id id() { return instructions_.front()->result_id(); }
|
||||||
|
|
||||||
Function& parent() const { return parent_; }
|
Function& parent() const { return parent_; }
|
||||||
|
|
||||||
void push_instruction(Instruction* inst);
|
void AddInstruction(Instruction* instr);
|
||||||
void push_local_variable(Instruction* inst) {
|
void AddLocalVariable(Instruction* instr) {
|
||||||
local_variables_.push_back(inst);
|
local_variables_.push_back(instr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_predecessor(Block* predecessor) {
|
void AddPredecessor(Block* predecessor) {
|
||||||
predecessors_.push_back(predecessor);
|
predecessors_.push_back(predecessor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,7 +238,7 @@ class Block {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dump(std::vector<uint32_t>& out) const {
|
void Serialize(std::vector<uint32_t>& out) const {
|
||||||
// skip the degenerate unreachable blocks
|
// skip the degenerate unreachable blocks
|
||||||
// TODO: code gen: skip all unreachable blocks (transitive closure)
|
// TODO: code gen: skip all unreachable blocks (transitive closure)
|
||||||
// (but, until that's done safer to keep non-degenerate
|
// (but, until that's done safer to keep non-degenerate
|
||||||
|
@ -231,12 +247,12 @@ class Block {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
instructions_[0]->dump(out);
|
instructions_[0]->Serialize(out);
|
||||||
for (auto variable : local_variables_) {
|
for (auto variable : local_variables_) {
|
||||||
variable->dump(out);
|
variable->Serialize(out);
|
||||||
}
|
}
|
||||||
for (int i = 1; i < instructions_.size(); ++i) {
|
for (int i = 1; i < instructions_.size(); ++i) {
|
||||||
instructions_[i]->dump(out);
|
instructions_[i]->Serialize(out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,32 +291,32 @@ class Function {
|
||||||
Id param_id(int p) { return parameter_instructions_[p]->result_id(); }
|
Id param_id(int p) { return parameter_instructions_[p]->result_id(); }
|
||||||
|
|
||||||
void push_block(Block* block) { blocks_.push_back(block); }
|
void push_block(Block* block) { blocks_.push_back(block); }
|
||||||
void pop_block(Block*) { blocks_.pop_back(); }
|
void pop_block(Block* block) { blocks_.pop_back(); }
|
||||||
|
|
||||||
Module& parent() const { return parent_; }
|
Module& parent() const { return parent_; }
|
||||||
Block* entry_block() const { return blocks_.front(); }
|
Block* entry_block() const { return blocks_.front(); }
|
||||||
Block* last_block() const { return blocks_.back(); }
|
Block* last_block() const { return blocks_.back(); }
|
||||||
|
|
||||||
void push_local_variable(Instruction* inst);
|
void AddLocalVariable(Instruction* instr);
|
||||||
|
|
||||||
Id return_type() const { return function_instruction_.type_id(); }
|
Id return_type() const { return function_instruction_.type_id(); }
|
||||||
|
|
||||||
void dump(std::vector<uint32_t>& out) const {
|
void Serialize(std::vector<uint32_t>& out) const {
|
||||||
// OpFunction
|
// OpFunction
|
||||||
function_instruction_.dump(out);
|
function_instruction_.Serialize(out);
|
||||||
|
|
||||||
// OpFunctionParameter
|
// OpFunctionParameter
|
||||||
for (auto instruction : parameter_instructions_) {
|
for (auto instruction : parameter_instructions_) {
|
||||||
instruction->dump(out);
|
instruction->Serialize(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Blocks
|
// Blocks
|
||||||
for (auto block : blocks_) {
|
for (auto block : blocks_) {
|
||||||
block->dump(out);
|
block->Serialize(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction end(0, 0, spv::Op::OpFunctionEnd);
|
Instruction end(0, 0, spv::Op::OpFunctionEnd);
|
||||||
end.dump(out);
|
end.Serialize(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -317,32 +333,35 @@ class Module {
|
||||||
public:
|
public:
|
||||||
Module() = default;
|
Module() = default;
|
||||||
~Module() {
|
~Module() {
|
||||||
// TODO delete things
|
for (size_t i = 0; i < functions_.size(); ++i) {
|
||||||
|
delete functions_[i];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void push_function(Function* function) { functions_.push_back(function); }
|
void AddFunction(Function* function) { functions_.push_back(function); }
|
||||||
|
|
||||||
void mapInstruction(Instruction* instruction) {
|
void MapInstruction(Instruction* instr) {
|
||||||
spv::Id result_id = instruction->result_id();
|
spv::Id result_id = instr->result_id();
|
||||||
// map the instruction's result id
|
// Map the instruction's result id.
|
||||||
if (result_id >= id_to_instruction_.size())
|
if (result_id >= id_to_instruction_.size()) {
|
||||||
id_to_instruction_.resize(result_id + 16);
|
id_to_instruction_.resize(result_id + 16);
|
||||||
id_to_instruction_[result_id] = instruction;
|
}
|
||||||
|
id_to_instruction_[result_id] = instr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction* getInstruction(Id id) const { return id_to_instruction_[id]; }
|
Instruction* instruction(Id id) const { return id_to_instruction_[id]; }
|
||||||
|
|
||||||
spv::Id getTypeId(Id result_id) const {
|
spv::Id type_id(Id result_id) const {
|
||||||
return id_to_instruction_[result_id]->type_id();
|
return id_to_instruction_[result_id]->type_id();
|
||||||
}
|
}
|
||||||
|
|
||||||
spv::StorageClass getStorageClass(Id type_id) const {
|
spv::StorageClass storage_class(Id type_id) const {
|
||||||
return (spv::StorageClass)id_to_instruction_[type_id]->immediate_operand(0);
|
return (spv::StorageClass)id_to_instruction_[type_id]->immediate_operand(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void dump(std::vector<uint32_t>& out) const {
|
void Serialize(std::vector<uint32_t>& out) const {
|
||||||
for (auto function : functions_) {
|
for (auto function : functions_) {
|
||||||
function->dump(out);
|
function->Serialize(out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,37 +370,36 @@ class Module {
|
||||||
|
|
||||||
std::vector<Function*> functions_;
|
std::vector<Function*> functions_;
|
||||||
|
|
||||||
// map from result id to instruction having that result id
|
// Maps from result id to instruction having that result id.
|
||||||
std::vector<Instruction*> id_to_instruction_;
|
std::vector<Instruction*> id_to_instruction_;
|
||||||
|
|
||||||
// map from a result id to its type id
|
|
||||||
};
|
};
|
||||||
|
|
||||||
inline Function::Function(Id id, Id resultType, Id functionType,
|
inline Function::Function(Id id, Id result_type_id, Id function_type_id,
|
||||||
Id firstParamId, Module& parent)
|
Id first_param_id, Module& parent)
|
||||||
: parent_(parent),
|
: parent_(parent),
|
||||||
function_instruction_(id, resultType, spv::Op::OpFunction) {
|
function_instruction_(id, result_type_id, spv::Op::OpFunction) {
|
||||||
// OpFunction
|
// OpFunction
|
||||||
function_instruction_.addImmediateOperand(
|
function_instruction_.AddImmediateOperand(
|
||||||
static_cast<uint32_t>(spv::FunctionControlMask::MaskNone));
|
static_cast<uint32_t>(spv::FunctionControlMask::MaskNone));
|
||||||
function_instruction_.addIdOperand(functionType);
|
function_instruction_.AddIdOperand(function_type_id);
|
||||||
parent.mapInstruction(&function_instruction_);
|
parent.MapInstruction(&function_instruction_);
|
||||||
parent.push_function(this);
|
parent.AddFunction(this);
|
||||||
|
|
||||||
// OpFunctionParameter
|
// OpFunctionParameter
|
||||||
Instruction* typeInst = parent.getInstruction(functionType);
|
Instruction* type_instr = parent.instruction(function_type_id);
|
||||||
int numParams = typeInst->operand_count() - 1;
|
int param_count = type_instr->operand_count() - 1;
|
||||||
for (int p = 0; p < numParams; ++p) {
|
for (int p = 0; p < param_count; ++p) {
|
||||||
auto param = new Instruction(firstParamId + p, typeInst->id_operand(p + 1),
|
auto param =
|
||||||
spv::Op::OpFunctionParameter);
|
new Instruction(first_param_id + p, type_instr->id_operand(p + 1),
|
||||||
parent.mapInstruction(param);
|
spv::Op::OpFunctionParameter);
|
||||||
|
parent.MapInstruction(param);
|
||||||
parameter_instructions_.push_back(param);
|
parameter_instructions_.push_back(param);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Function::push_local_variable(Instruction* inst) {
|
inline void Function::AddLocalVariable(Instruction* instr) {
|
||||||
blocks_[0]->push_local_variable(inst);
|
blocks_[0]->AddLocalVariable(instr);
|
||||||
parent_.mapInstruction(inst);
|
parent_.MapInstruction(instr);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Block::Block(Id id, Function& parent)
|
inline Block::Block(Id id, Function& parent)
|
||||||
|
@ -389,10 +407,10 @@ inline Block::Block(Id id, Function& parent)
|
||||||
instructions_.push_back(new Instruction(id, NoType, spv::Op::OpLabel));
|
instructions_.push_back(new Instruction(id, NoType, spv::Op::OpLabel));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void Block::push_instruction(Instruction* inst) {
|
inline void Block::AddInstruction(Instruction* inst) {
|
||||||
instructions_.push_back(inst);
|
instructions_.push_back(inst);
|
||||||
if (inst->result_id()) {
|
if (inst->result_id()) {
|
||||||
parent_.parent().mapInstruction(inst);
|
parent_.parent().MapInstruction(inst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue