534 lines
16 KiB
C++
534 lines
16 KiB
C++
/*
|
|
* Copyright 2017, The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#ifndef MODULE_H
|
|
#define MODULE_H
|
|
|
|
#include <iostream>
|
|
#include <map>
|
|
#include <vector>
|
|
|
|
#include "core_defs.h"
|
|
#include "entity.h"
|
|
#include "instructions.h"
|
|
#include "stl_util.h"
|
|
#include "types_generated.h"
|
|
#include "visitor.h"
|
|
|
|
namespace android {
|
|
namespace spirit {
|
|
|
|
class Builder;
|
|
class AnnotationSection;
|
|
class CapabilityInst;
|
|
class DebugInfoSection;
|
|
class ExtensionInst;
|
|
class ExtInstImportInst;
|
|
class EntryPointInst;
|
|
class ExecutionModeInst;
|
|
class EntryPointDefinition;
|
|
class FunctionDeclaration;
|
|
class FunctionDefinition;
|
|
class GlobalSection;
|
|
class InputWordStream;
|
|
class Instruction;
|
|
class MemoryModelInst;
|
|
|
|
union VersionNumber {
|
|
struct {
|
|
uint8_t mLowZero;
|
|
uint8_t mMinorNumber;
|
|
uint8_t mMajorNumber;
|
|
uint8_t mHighZero;
|
|
} mMajorMinor;
|
|
uint8_t mBytes[4];
|
|
uint32_t mWord;
|
|
};
|
|
|
|
class Module : public Entity {
|
|
public:
|
|
static Module *getCurrentModule();
|
|
uint32_t nextId() { return mNextId++; }
|
|
|
|
Module();
|
|
|
|
Module(Builder *b);
|
|
|
|
virtual ~Module() {}
|
|
|
|
bool DeserializeInternal(InputWordStream &IS) override;
|
|
|
|
void Serialize(OutputWordStream &OS) const override;
|
|
|
|
void SerializeHeader(OutputWordStream &OS) const;
|
|
|
|
void registerId(uint32_t id, Instruction *inst) {
|
|
mIdTable.insert(std::make_pair(id, inst));
|
|
}
|
|
|
|
void initialize();
|
|
|
|
bool resolveIds();
|
|
|
|
void accept(IVisitor *v) override {
|
|
for (auto cap : mCapabilities) {
|
|
v->visit(cap);
|
|
}
|
|
for (auto ext : mExtensions) {
|
|
v->visit(ext);
|
|
}
|
|
for (auto imp : mExtInstImports) {
|
|
v->visit(imp);
|
|
}
|
|
|
|
v->visit(mMemoryModel.get());
|
|
|
|
for (auto entry : mEntryPoints) {
|
|
v->visit(entry);
|
|
}
|
|
|
|
for (auto mode : mExecutionModes) {
|
|
v->visit(mode);
|
|
}
|
|
|
|
v->visit(mDebugInfo.get());
|
|
if (mAnnotations) {
|
|
v->visit(mAnnotations.get());
|
|
}
|
|
if (mGlobals) {
|
|
v->visit(mGlobals.get());
|
|
}
|
|
|
|
for (auto def : mFunctionDefinitions) {
|
|
v->visit(def);
|
|
}
|
|
}
|
|
|
|
static std::ostream &errs() { return std::cerr; }
|
|
|
|
Module *addCapability(Capability cap);
|
|
Module *setMemoryModel(AddressingModel am, MemoryModel mm);
|
|
Module *addExtInstImport(const char *extName);
|
|
Module *addSource(SourceLanguage lang, int version);
|
|
Module *addSourceExtension(const char *ext);
|
|
Module *addString(const char *ext);
|
|
Module *addEntryPoint(EntryPointDefinition *entry);
|
|
|
|
ExtInstImportInst *getGLExt() const { return mGLExt; }
|
|
|
|
const std::string findStringOfPrefix(const char *prefix) const;
|
|
|
|
GlobalSection *getGlobalSection();
|
|
|
|
Instruction *lookupByName(const char *) const;
|
|
FunctionDefinition *
|
|
getFunctionDefinitionFromInstruction(FunctionInst *) const;
|
|
FunctionDefinition *lookupFunctionDefinitionByName(const char *name) const;
|
|
|
|
// Find the name of the instruction, e.g., the name of a function (OpFunction
|
|
// instruction).
|
|
// The returned string is owned by the OpName instruction, whose first operand
|
|
// is the instruction being queried on.
|
|
const char *lookupNameByInstruction(const Instruction *) const;
|
|
|
|
VariableInst *getInvocationId();
|
|
VariableInst *getNumWorkgroups();
|
|
|
|
// Adds a struct type built somewhere else.
|
|
Module *addStructType(TypeStructInst *structType);
|
|
Module *addVariable(VariableInst *var);
|
|
|
|
// Methods to look up types. Create them if not found.
|
|
TypeVoidInst *getVoidType();
|
|
TypeIntInst *getIntType(int bits, bool isSigned = true);
|
|
TypeIntInst *getUnsignedIntType(int bits);
|
|
TypeFloatInst *getFloatType(int bits);
|
|
TypeVectorInst *getVectorType(Instruction *componentType, int width);
|
|
TypePointerInst *getPointerType(StorageClass storage,
|
|
Instruction *pointeeType);
|
|
TypeRuntimeArrayInst *getRuntimeArrayType(Instruction *elementType);
|
|
|
|
// This implies that struct types are strictly structural equivalent, i.e.,
|
|
// two structs are equivalent i.f.f. their fields are equivalent, recursively.
|
|
TypeStructInst *getStructType(Instruction *fieldType[], int numField);
|
|
TypeStructInst *getStructType(const std::vector<Instruction *> &fieldType);
|
|
TypeStructInst *getStructType(Instruction *field0Type);
|
|
TypeStructInst *getStructType(Instruction *field0Type,
|
|
Instruction *field1Type);
|
|
TypeStructInst *getStructType(Instruction *field0Type,
|
|
Instruction *field1Type,
|
|
Instruction *field2Type);
|
|
|
|
// TODO: Can function types of different decorations be considered the same?
|
|
TypeFunctionInst *getFunctionType(Instruction *retType,
|
|
Instruction *const argType[],
|
|
size_t numArg);
|
|
TypeFunctionInst *getFunctionType(Instruction *retType,
|
|
const std::vector<Instruction *> &argTypes);
|
|
|
|
size_t getSize(TypeVoidInst *voidTy);
|
|
size_t getSize(TypeIntInst *intTy);
|
|
size_t getSize(TypeFloatInst *fpTy);
|
|
size_t getSize(TypeVectorInst *vTy);
|
|
size_t getSize(TypePointerInst *ptrTy);
|
|
size_t getSize(TypeStructInst *structTy);
|
|
size_t getSize(TypeFunctionInst *funcTy);
|
|
size_t getSize(Instruction *inst);
|
|
|
|
ConstantInst *getConstant(TypeIntInst *type, int32_t value);
|
|
ConstantInst *getConstant(TypeIntInst *type, uint32_t value);
|
|
ConstantInst *getConstant(TypeFloatInst *type, float value);
|
|
|
|
ConstantCompositeInst *getConstantComposite(TypeVectorInst *type,
|
|
ConstantInst *components[],
|
|
size_t width);
|
|
ConstantCompositeInst *
|
|
getConstantComposite(Instruction *type,
|
|
const std::vector<ConstantInst *> &components);
|
|
ConstantCompositeInst *getConstantComposite(Instruction *type,
|
|
ConstantInst *comp0,
|
|
ConstantInst *comp1);
|
|
ConstantCompositeInst *getConstantComposite(TypeVectorInst *type,
|
|
ConstantInst *comp0,
|
|
ConstantInst *comp1,
|
|
ConstantInst *comp2);
|
|
ConstantCompositeInst *getConstantComposite(TypeVectorInst *type,
|
|
ConstantInst *comp0,
|
|
ConstantInst *comp1,
|
|
ConstantInst *comp2,
|
|
ConstantInst *comp3);
|
|
|
|
Module *addFunctionDefinition(FunctionDefinition *func);
|
|
|
|
void consolidateAnnotations();
|
|
|
|
private:
|
|
static Module *mInstance;
|
|
uint32_t mNextId;
|
|
std::map<uint32_t, Instruction *> mIdTable;
|
|
|
|
uint32_t mMagicNumber;
|
|
VersionNumber mVersion;
|
|
uint32_t mGeneratorMagicNumber;
|
|
uint32_t mBound;
|
|
uint32_t mReserved;
|
|
|
|
std::vector<CapabilityInst *> mCapabilities;
|
|
std::vector<ExtensionInst *> mExtensions;
|
|
std::vector<ExtInstImportInst *> mExtInstImports;
|
|
std::unique_ptr<MemoryModelInst> mMemoryModel;
|
|
std::vector<EntryPointInst *> mEntryPointInsts;
|
|
std::vector<ExecutionModeInst *> mExecutionModes;
|
|
std::vector<EntryPointDefinition *> mEntryPoints;
|
|
std::unique_ptr<DebugInfoSection> mDebugInfo;
|
|
std::unique_ptr<AnnotationSection> mAnnotations;
|
|
std::unique_ptr<GlobalSection> mGlobals;
|
|
std::vector<FunctionDefinition *> mFunctionDefinitions;
|
|
|
|
ExtInstImportInst *mGLExt;
|
|
|
|
ContainerDeleter<std::vector<CapabilityInst *>> mCapabilitiesDeleter;
|
|
ContainerDeleter<std::vector<ExtensionInst *>> mExtensionsDeleter;
|
|
ContainerDeleter<std::vector<ExtInstImportInst *>> mExtInstImportsDeleter;
|
|
ContainerDeleter<std::vector<EntryPointInst *>> mEntryPointInstsDeleter;
|
|
ContainerDeleter<std::vector<ExecutionModeInst *>> mExecutionModesDeleter;
|
|
ContainerDeleter<std::vector<EntryPointDefinition *>> mEntryPointsDeleter;
|
|
ContainerDeleter<std::vector<FunctionDefinition *>>
|
|
mFunctionDefinitionsDeleter;
|
|
};
|
|
|
|
struct Extent3D {
|
|
uint32_t mWidth;
|
|
uint32_t mHeight;
|
|
uint32_t mDepth;
|
|
};
|
|
|
|
class EntryPointDefinition : public Entity {
|
|
public:
|
|
EntryPointDefinition() {}
|
|
EntryPointDefinition(Builder *builder, ExecutionModel execModel,
|
|
FunctionDefinition *func, const char *name);
|
|
|
|
virtual ~EntryPointDefinition() {
|
|
// Nothing to do here since ~Module() will delete entities referenced here
|
|
}
|
|
|
|
void accept(IVisitor *visitor) override {
|
|
visitor->visit(mEntryPointInst);
|
|
// Do not visit the ExecutionMode instructions here. They are linked here
|
|
// for convinience, and for convinience only. They are all grouped, stored,
|
|
// and serialized directly in the module in a section right after all
|
|
// EntryPoint instructions. Visit them from there.
|
|
}
|
|
|
|
bool DeserializeInternal(InputWordStream &IS) override;
|
|
|
|
EntryPointDefinition *addToInterface(VariableInst *var);
|
|
EntryPointDefinition *addExecutionMode(ExecutionModeInst *mode) {
|
|
mExecutionModeInsts.push_back(mode);
|
|
return this;
|
|
}
|
|
const std::vector<ExecutionModeInst *> &getExecutionModes() const {
|
|
return mExecutionModeInsts;
|
|
}
|
|
|
|
EntryPointDefinition *setLocalSize(uint32_t width, uint32_t height,
|
|
uint32_t depth);
|
|
|
|
EntryPointDefinition *applyExecutionMode(ExecutionModeInst *mode);
|
|
|
|
EntryPointInst *getInstruction() const { return mEntryPointInst; }
|
|
|
|
private:
|
|
const char *mName;
|
|
FunctionInst *mFunction;
|
|
ExecutionModel mExecutionModel;
|
|
std::vector<VariableInst *> mInterface;
|
|
Extent3D mLocalSize;
|
|
|
|
EntryPointInst *mEntryPointInst;
|
|
std::vector<ExecutionModeInst *> mExecutionModeInsts;
|
|
};
|
|
|
|
class DebugInfoSection : public Entity {
|
|
public:
|
|
DebugInfoSection() : mSourcesDeleter(mSources), mNamesDeleter(mNames) {}
|
|
DebugInfoSection(Builder *b)
|
|
: Entity(b), mSourcesDeleter(mSources), mNamesDeleter(mNames) {}
|
|
|
|
virtual ~DebugInfoSection() {}
|
|
|
|
bool DeserializeInternal(InputWordStream &IS) override;
|
|
|
|
DebugInfoSection *addSource(SourceLanguage lang, int version);
|
|
DebugInfoSection *addSourceExtension(const char *ext);
|
|
DebugInfoSection *addString(const char *str);
|
|
|
|
std::string findStringOfPrefix(const char *prefix);
|
|
|
|
Instruction *lookupByName(const char *name) const;
|
|
const char *lookupNameByInstruction(const Instruction *) const;
|
|
|
|
void accept(IVisitor *v) override {
|
|
for (auto source : mSources) {
|
|
v->visit(source);
|
|
}
|
|
for (auto name : mNames) {
|
|
v->visit(name);
|
|
}
|
|
}
|
|
|
|
private:
|
|
// (OpString|OpSource|OpSourceExtension|OpSourceContinued)*
|
|
std::vector<Instruction *> mSources;
|
|
// (OpName|OpMemberName)*
|
|
std::vector<Instruction *> mNames;
|
|
|
|
ContainerDeleter<std::vector<Instruction *>> mSourcesDeleter;
|
|
ContainerDeleter<std::vector<Instruction *>> mNamesDeleter;
|
|
};
|
|
|
|
class AnnotationSection : public Entity {
|
|
public:
|
|
AnnotationSection();
|
|
AnnotationSection(Builder *b);
|
|
|
|
virtual ~AnnotationSection() {}
|
|
|
|
bool DeserializeInternal(InputWordStream &IS) override;
|
|
|
|
void accept(IVisitor *v) override {
|
|
for (auto inst : mAnnotations) {
|
|
v->visit(inst);
|
|
}
|
|
}
|
|
|
|
template <typename T> void addAnnotations(T begin, T end) {
|
|
mAnnotations.insert<T>(std::end(mAnnotations), begin, end);
|
|
}
|
|
|
|
std::vector<Instruction *>::const_iterator begin() const {
|
|
return mAnnotations.begin();
|
|
}
|
|
|
|
std::vector<Instruction *>::const_iterator end() const {
|
|
return mAnnotations.end();
|
|
}
|
|
|
|
void clear() { mAnnotations.clear(); }
|
|
|
|
private:
|
|
std::vector<Instruction *> mAnnotations; // OpDecorate, etc.
|
|
|
|
ContainerDeleter<std::vector<Instruction *>> mAnnotationsDeleter;
|
|
};
|
|
|
|
// Types, constants, and globals
|
|
class GlobalSection : public Entity {
|
|
public:
|
|
GlobalSection();
|
|
GlobalSection(Builder *builder);
|
|
|
|
virtual ~GlobalSection() {}
|
|
|
|
bool DeserializeInternal(InputWordStream &IS) override;
|
|
|
|
void accept(IVisitor *v) override {
|
|
for (auto inst : mGlobalDefs) {
|
|
v->visit(inst);
|
|
}
|
|
|
|
if (mInvocationId) {
|
|
v->visit(mInvocationId.get());
|
|
}
|
|
|
|
if (mNumWorkgroups) {
|
|
v->visit(mNumWorkgroups.get());
|
|
}
|
|
}
|
|
|
|
ConstantInst *getConstant(TypeIntInst *type, int32_t value);
|
|
ConstantInst *getConstant(TypeIntInst *type, uint32_t value);
|
|
ConstantInst *getConstant(TypeFloatInst *type, float value);
|
|
ConstantCompositeInst *getConstantComposite(TypeVectorInst *type,
|
|
ConstantInst *components[],
|
|
size_t width);
|
|
|
|
// Methods to look up types. Create them if not found.
|
|
TypeVoidInst *getVoidType();
|
|
TypeIntInst *getIntType(int bits, bool isSigned = true);
|
|
TypeFloatInst *getFloatType(int bits);
|
|
TypeVectorInst *getVectorType(Instruction *componentType, int width);
|
|
TypePointerInst *getPointerType(StorageClass storage,
|
|
Instruction *pointeeType);
|
|
TypeRuntimeArrayInst *getRuntimeArrayType(Instruction *elementType);
|
|
|
|
// This implies that struct types are strictly structural equivalent, i.e.,
|
|
// two structs are equivalent i.f.f. their fields are equivalent, recursively.
|
|
TypeStructInst *getStructType(Instruction *fieldType[], int numField);
|
|
// TypeStructInst *getStructType(const std::vector<Instruction *>
|
|
// &fieldTypes);
|
|
|
|
// TODO: Can function types of different decorations be considered the same?
|
|
TypeFunctionInst *getFunctionType(Instruction *retType,
|
|
Instruction *const argType[],
|
|
size_t numArg);
|
|
// TypeStructInst *addStructType(Instruction *fieldType[], int numField);
|
|
GlobalSection *addStructType(TypeStructInst *structType);
|
|
GlobalSection *addVariable(VariableInst *var);
|
|
|
|
VariableInst *getInvocationId();
|
|
VariableInst *getNumWorkgroups();
|
|
|
|
private:
|
|
// TODO: Add structure to this.
|
|
// Separate types, constants, variables, etc.
|
|
std::vector<Instruction *> mGlobalDefs;
|
|
std::unique_ptr<VariableInst> mInvocationId;
|
|
std::unique_ptr<VariableInst> mNumWorkgroups;
|
|
|
|
ContainerDeleter<std::vector<Instruction *>> mGlobalDefsDeleter;
|
|
};
|
|
|
|
class FunctionDeclaration : public Entity {
|
|
public:
|
|
virtual ~FunctionDeclaration() {}
|
|
|
|
bool DeserializeInternal(InputWordStream &IS) override;
|
|
|
|
void accept(IVisitor *v) override {
|
|
v->visit(mFunc);
|
|
for (auto param : mParams) {
|
|
v->visit(param);
|
|
}
|
|
v->visit(mFuncEnd);
|
|
}
|
|
|
|
private:
|
|
FunctionInst *mFunc;
|
|
std::vector<FunctionParameterInst *> mParams;
|
|
FunctionEndInst *mFuncEnd;
|
|
};
|
|
|
|
class Block : public Entity {
|
|
public:
|
|
Block() {}
|
|
Block(Builder *b) : Entity(b) {}
|
|
|
|
virtual ~Block() {}
|
|
|
|
bool DeserializeInternal(InputWordStream &IS) override;
|
|
|
|
void accept(IVisitor *v) override {
|
|
for (auto inst : mInsts) {
|
|
v->visit(inst);
|
|
}
|
|
}
|
|
|
|
Block *addInstruction(Instruction *inst) {
|
|
mInsts.push_back(inst);
|
|
return this;
|
|
}
|
|
|
|
private:
|
|
std::vector<Instruction *> mInsts;
|
|
};
|
|
|
|
class FunctionDefinition : public Entity {
|
|
public:
|
|
FunctionDefinition();
|
|
FunctionDefinition(Builder *builder, FunctionInst *func,
|
|
FunctionEndInst *end);
|
|
|
|
virtual ~FunctionDefinition() {}
|
|
|
|
bool DeserializeInternal(InputWordStream &IS) override;
|
|
|
|
void accept(IVisitor *v) override {
|
|
v->visit(mFunc.get());
|
|
for (auto param : mParams) {
|
|
v->visit(param);
|
|
}
|
|
for (auto block : mBlocks) {
|
|
v->visit(block);
|
|
}
|
|
v->visit(mFuncEnd.get());
|
|
}
|
|
|
|
FunctionDefinition *addBlock(Block *b) {
|
|
mBlocks.push_back(b);
|
|
return this;
|
|
}
|
|
|
|
FunctionInst *getInstruction() const { return mFunc.get(); }
|
|
FunctionParameterInst *getParameter(uint32_t i) const { return mParams[i]; }
|
|
|
|
Instruction *getReturnType() const;
|
|
|
|
private:
|
|
std::unique_ptr<FunctionInst> mFunc;
|
|
std::vector<FunctionParameterInst *> mParams;
|
|
std::vector<Block *> mBlocks;
|
|
std::unique_ptr<FunctionEndInst> mFuncEnd;
|
|
|
|
ContainerDeleter<std::vector<FunctionParameterInst *>> mParamsDeleter;
|
|
ContainerDeleter<std::vector<Block *>> mBlocksDeleter;
|
|
};
|
|
|
|
} // namespace spirit
|
|
} // namespace android
|
|
|
|
#endif // MODULE_H
|