988 lines
30 KiB
C++
988 lines
30 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.
|
|
*/
|
|
|
|
#include "module.h"
|
|
|
|
#include <set>
|
|
|
|
#include "builder.h"
|
|
#include "core_defs.h"
|
|
#include "instructions.h"
|
|
#include "types_generated.h"
|
|
#include "word_stream.h"
|
|
|
|
namespace android {
|
|
namespace spirit {
|
|
|
|
Module *Module::mInstance = nullptr;
|
|
|
|
Module *Module::getCurrentModule() {
|
|
if (mInstance == nullptr) {
|
|
return mInstance = new Module();
|
|
}
|
|
return mInstance;
|
|
}
|
|
|
|
Module::Module()
|
|
: mNextId(1), mCapabilitiesDeleter(mCapabilities),
|
|
mExtensionsDeleter(mExtensions), mExtInstImportsDeleter(mExtInstImports),
|
|
mEntryPointInstsDeleter(mEntryPointInsts),
|
|
mExecutionModesDeleter(mExecutionModes),
|
|
mEntryPointsDeleter(mEntryPoints),
|
|
mFunctionDefinitionsDeleter(mFunctionDefinitions) {
|
|
mInstance = this;
|
|
}
|
|
|
|
Module::Module(Builder *b)
|
|
: Entity(b), mNextId(1), mCapabilitiesDeleter(mCapabilities),
|
|
mExtensionsDeleter(mExtensions), mExtInstImportsDeleter(mExtInstImports),
|
|
mEntryPointInstsDeleter(mEntryPointInsts),
|
|
mExecutionModesDeleter(mExecutionModes),
|
|
mEntryPointsDeleter(mEntryPoints),
|
|
mFunctionDefinitionsDeleter(mFunctionDefinitions) {
|
|
mInstance = this;
|
|
}
|
|
|
|
bool Module::resolveIds() {
|
|
auto &table = mIdTable;
|
|
|
|
std::unique_ptr<IVisitor> v0(
|
|
CreateInstructionVisitor([&table](Instruction *inst) {
|
|
if (inst->hasResult()) {
|
|
table.insert(std::make_pair(inst->getId(), inst));
|
|
}
|
|
}));
|
|
v0->visit(this);
|
|
|
|
mNextId = mIdTable.rbegin()->first + 1;
|
|
|
|
int err = 0;
|
|
std::unique_ptr<IVisitor> v(
|
|
CreateInstructionVisitor([&table, &err](Instruction *inst) {
|
|
for (auto ref : inst->getAllIdRefs()) {
|
|
if (ref) {
|
|
auto it = table.find(ref->mId);
|
|
if (it != table.end()) {
|
|
ref->mInstruction = it->second;
|
|
} else {
|
|
std::cout << "Found no instruction for id " << ref->mId
|
|
<< std::endl;
|
|
err++;
|
|
}
|
|
}
|
|
}
|
|
}));
|
|
v->visit(this);
|
|
return err == 0;
|
|
}
|
|
|
|
bool Module::DeserializeInternal(InputWordStream &IS) {
|
|
if (IS.empty()) {
|
|
return false;
|
|
}
|
|
|
|
IS >> &mMagicNumber;
|
|
if (mMagicNumber != 0x07230203) {
|
|
errs() << "Wrong Magic Number: " << mMagicNumber;
|
|
return false;
|
|
}
|
|
|
|
if (IS.empty()) {
|
|
return false;
|
|
}
|
|
|
|
IS >> &mVersion.mWord;
|
|
if (mVersion.mBytes[0] != 0 || mVersion.mBytes[3] != 0) {
|
|
return false;
|
|
}
|
|
|
|
if (IS.empty()) {
|
|
return false;
|
|
}
|
|
|
|
IS >> &mGeneratorMagicNumber >> &mBound >> &mReserved;
|
|
|
|
DeserializeZeroOrMore<CapabilityInst>(IS, mCapabilities);
|
|
DeserializeZeroOrMore<ExtensionInst>(IS, mExtensions);
|
|
DeserializeZeroOrMore<ExtInstImportInst>(IS, mExtInstImports);
|
|
|
|
mMemoryModel.reset(Deserialize<MemoryModelInst>(IS));
|
|
if (!mMemoryModel) {
|
|
errs() << "Missing memory model specification.\n";
|
|
return false;
|
|
}
|
|
|
|
DeserializeZeroOrMore<EntryPointDefinition>(IS, mEntryPoints);
|
|
DeserializeZeroOrMore<ExecutionModeInst>(IS, mExecutionModes);
|
|
for (auto entry : mEntryPoints) {
|
|
mEntryPointInsts.push_back(entry->getInstruction());
|
|
for (auto mode : mExecutionModes) {
|
|
entry->applyExecutionMode(mode);
|
|
}
|
|
}
|
|
|
|
mDebugInfo.reset(Deserialize<DebugInfoSection>(IS));
|
|
mAnnotations.reset(Deserialize<AnnotationSection>(IS));
|
|
mGlobals.reset(Deserialize<GlobalSection>(IS));
|
|
|
|
DeserializeZeroOrMore<FunctionDefinition>(IS, mFunctionDefinitions);
|
|
|
|
if (mFunctionDefinitions.empty()) {
|
|
errs() << "Missing function definitions.\n";
|
|
for (int i = 0; i < 4; i++) {
|
|
uint32_t w;
|
|
IS >> &w;
|
|
std::cout << std::hex << w << " ";
|
|
}
|
|
std::cout << std::endl;
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void Module::initialize() {
|
|
mMagicNumber = 0x07230203;
|
|
mVersion.mMajorMinor = {.mMinorNumber = 1, .mMajorNumber = 1};
|
|
mGeneratorMagicNumber = 0x00070000;
|
|
mBound = 0;
|
|
mReserved = 0;
|
|
mAnnotations.reset(new AnnotationSection());
|
|
}
|
|
|
|
void Module::SerializeHeader(OutputWordStream &OS) const {
|
|
OS << mMagicNumber;
|
|
OS << mVersion.mWord << mGeneratorMagicNumber;
|
|
if (mBound == 0) {
|
|
OS << mIdTable.end()->first + 1;
|
|
} else {
|
|
OS << std::max(mBound, mNextId);
|
|
}
|
|
OS << mReserved;
|
|
}
|
|
|
|
void Module::Serialize(OutputWordStream &OS) const {
|
|
SerializeHeader(OS);
|
|
Entity::Serialize(OS);
|
|
}
|
|
|
|
Module *Module::addCapability(Capability cap) {
|
|
mCapabilities.push_back(mBuilder->MakeCapability(cap));
|
|
return this;
|
|
}
|
|
|
|
Module *Module::setMemoryModel(AddressingModel am, MemoryModel mm) {
|
|
mMemoryModel.reset(mBuilder->MakeMemoryModel(am, mm));
|
|
return this;
|
|
}
|
|
|
|
Module *Module::addExtInstImport(const char *extName) {
|
|
ExtInstImportInst *extInst = mBuilder->MakeExtInstImport(extName);
|
|
mExtInstImports.push_back(extInst);
|
|
if (strcmp(extName, "GLSL.std.450") == 0) {
|
|
mGLExt = extInst;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
Module *Module::addSource(SourceLanguage lang, int version) {
|
|
if (!mDebugInfo) {
|
|
mDebugInfo.reset(mBuilder->MakeDebugInfoSection());
|
|
}
|
|
mDebugInfo->addSource(lang, version);
|
|
return this;
|
|
}
|
|
|
|
Module *Module::addSourceExtension(const char *ext) {
|
|
if (!mDebugInfo) {
|
|
mDebugInfo.reset(mBuilder->MakeDebugInfoSection());
|
|
}
|
|
mDebugInfo->addSourceExtension(ext);
|
|
return this;
|
|
}
|
|
|
|
Module *Module::addString(const char *str) {
|
|
if (!mDebugInfo) {
|
|
mDebugInfo.reset(mBuilder->MakeDebugInfoSection());
|
|
}
|
|
mDebugInfo->addString(str);
|
|
return this;
|
|
}
|
|
|
|
Module *Module::addEntryPoint(EntryPointDefinition *entry) {
|
|
mEntryPoints.push_back(entry);
|
|
auto newModes = entry->getExecutionModes();
|
|
mExecutionModes.insert(mExecutionModes.end(), newModes.begin(),
|
|
newModes.end());
|
|
return this;
|
|
}
|
|
|
|
const std::string Module::findStringOfPrefix(const char *prefix) const {
|
|
if (!mDebugInfo) {
|
|
return std::string();
|
|
}
|
|
return mDebugInfo->findStringOfPrefix(prefix);
|
|
}
|
|
|
|
GlobalSection *Module::getGlobalSection() {
|
|
if (!mGlobals) {
|
|
mGlobals.reset(new GlobalSection());
|
|
}
|
|
return mGlobals.get();
|
|
}
|
|
|
|
ConstantInst *Module::getConstant(TypeIntInst *type, int32_t value) {
|
|
return getGlobalSection()->getConstant(type, value);
|
|
}
|
|
|
|
ConstantInst *Module::getConstant(TypeIntInst *type, uint32_t value) {
|
|
return getGlobalSection()->getConstant(type, value);
|
|
}
|
|
|
|
ConstantInst *Module::getConstant(TypeFloatInst *type, float value) {
|
|
return getGlobalSection()->getConstant(type, value);
|
|
}
|
|
|
|
ConstantCompositeInst *Module::getConstantComposite(TypeVectorInst *type,
|
|
ConstantInst *components[],
|
|
size_t width) {
|
|
return getGlobalSection()->getConstantComposite(type, components, width);
|
|
}
|
|
|
|
ConstantCompositeInst *Module::getConstantComposite(TypeVectorInst *type,
|
|
ConstantInst *comp0,
|
|
ConstantInst *comp1,
|
|
ConstantInst *comp2) {
|
|
// TODO: verify that component types are the same and consistent with the
|
|
// resulting vector type
|
|
ConstantInst *comps[] = {comp0, comp1, comp2};
|
|
return getConstantComposite(type, comps, 3);
|
|
}
|
|
|
|
ConstantCompositeInst *Module::getConstantComposite(TypeVectorInst *type,
|
|
ConstantInst *comp0,
|
|
ConstantInst *comp1,
|
|
ConstantInst *comp2,
|
|
ConstantInst *comp3) {
|
|
// TODO: verify that component types are the same and consistent with the
|
|
// resulting vector type
|
|
ConstantInst *comps[] = {comp0, comp1, comp2, comp3};
|
|
return getConstantComposite(type, comps, 4);
|
|
}
|
|
|
|
TypeVoidInst *Module::getVoidType() {
|
|
return getGlobalSection()->getVoidType();
|
|
}
|
|
|
|
TypeIntInst *Module::getIntType(int bits, bool isSigned) {
|
|
return getGlobalSection()->getIntType(bits, isSigned);
|
|
}
|
|
|
|
TypeIntInst *Module::getUnsignedIntType(int bits) {
|
|
return getIntType(bits, false);
|
|
}
|
|
|
|
TypeFloatInst *Module::getFloatType(int bits) {
|
|
return getGlobalSection()->getFloatType(bits);
|
|
}
|
|
|
|
TypeVectorInst *Module::getVectorType(Instruction *componentType, int width) {
|
|
return getGlobalSection()->getVectorType(componentType, width);
|
|
}
|
|
|
|
TypePointerInst *Module::getPointerType(StorageClass storage,
|
|
Instruction *pointeeType) {
|
|
return getGlobalSection()->getPointerType(storage, pointeeType);
|
|
}
|
|
|
|
TypeRuntimeArrayInst *Module::getRuntimeArrayType(Instruction *elementType) {
|
|
return getGlobalSection()->getRuntimeArrayType(elementType);
|
|
}
|
|
|
|
TypeStructInst *Module::getStructType(Instruction *fieldType[], int numField) {
|
|
return getGlobalSection()->getStructType(fieldType, numField);
|
|
}
|
|
|
|
TypeStructInst *Module::getStructType(Instruction *fieldType) {
|
|
return getStructType(&fieldType, 1);
|
|
}
|
|
|
|
TypeFunctionInst *Module::getFunctionType(Instruction *retType,
|
|
Instruction *const argType[],
|
|
size_t numArg) {
|
|
return getGlobalSection()->getFunctionType(retType, argType, numArg);
|
|
}
|
|
|
|
TypeFunctionInst *
|
|
Module::getFunctionType(Instruction *retType,
|
|
const std::vector<Instruction *> &argTypes) {
|
|
return getGlobalSection()->getFunctionType(retType, argTypes.data(),
|
|
argTypes.size());
|
|
}
|
|
|
|
size_t Module::getSize(TypeVoidInst *) { return 0; }
|
|
|
|
size_t Module::getSize(TypeIntInst *intTy) { return intTy->mOperand1 / 8; }
|
|
|
|
size_t Module::getSize(TypeFloatInst *fpTy) { return fpTy->mOperand1 / 8; }
|
|
|
|
size_t Module::getSize(TypeVectorInst *vTy) {
|
|
return getSize(vTy->mOperand1.mInstruction) * vTy->mOperand2;
|
|
}
|
|
|
|
size_t Module::getSize(TypePointerInst *) {
|
|
return 4; // TODO: or 8?
|
|
}
|
|
|
|
size_t Module::getSize(TypeStructInst *structTy) {
|
|
size_t sz = 0;
|
|
for (auto ty : structTy->mOperand1) {
|
|
sz += getSize(ty.mInstruction);
|
|
}
|
|
return sz;
|
|
}
|
|
|
|
size_t Module::getSize(TypeFunctionInst *) {
|
|
return 4; // TODO: or 8? Is this just the size of a pointer?
|
|
}
|
|
|
|
size_t Module::getSize(Instruction *inst) {
|
|
switch (inst->getOpCode()) {
|
|
case OpTypeVoid:
|
|
return getSize(static_cast<TypeVoidInst *>(inst));
|
|
case OpTypeInt:
|
|
return getSize(static_cast<TypeIntInst *>(inst));
|
|
case OpTypeFloat:
|
|
return getSize(static_cast<TypeFloatInst *>(inst));
|
|
case OpTypeVector:
|
|
return getSize(static_cast<TypeVectorInst *>(inst));
|
|
case OpTypeStruct:
|
|
return getSize(static_cast<TypeStructInst *>(inst));
|
|
case OpTypeFunction:
|
|
return getSize(static_cast<TypeFunctionInst *>(inst));
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
Module *Module::addFunctionDefinition(FunctionDefinition *func) {
|
|
mFunctionDefinitions.push_back(func);
|
|
return this;
|
|
}
|
|
|
|
Instruction *Module::lookupByName(const char *name) const {
|
|
return mDebugInfo->lookupByName(name);
|
|
}
|
|
|
|
FunctionDefinition *
|
|
Module::getFunctionDefinitionFromInstruction(FunctionInst *inst) const {
|
|
for (auto fdef : mFunctionDefinitions) {
|
|
if (fdef->getInstruction() == inst) {
|
|
return fdef;
|
|
}
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
FunctionDefinition *
|
|
Module::lookupFunctionDefinitionByName(const char *name) const {
|
|
FunctionInst *inst = static_cast<FunctionInst *>(lookupByName(name));
|
|
return getFunctionDefinitionFromInstruction(inst);
|
|
}
|
|
|
|
const char *Module::lookupNameByInstruction(const Instruction *inst) const {
|
|
return mDebugInfo->lookupNameByInstruction(inst);
|
|
}
|
|
|
|
VariableInst *Module::getInvocationId() {
|
|
return getGlobalSection()->getInvocationId();
|
|
}
|
|
|
|
VariableInst *Module::getNumWorkgroups() {
|
|
return getGlobalSection()->getNumWorkgroups();
|
|
}
|
|
|
|
Module *Module::addStructType(TypeStructInst *structType) {
|
|
getGlobalSection()->addStructType(structType);
|
|
return this;
|
|
}
|
|
|
|
Module *Module::addVariable(VariableInst *var) {
|
|
getGlobalSection()->addVariable(var);
|
|
return this;
|
|
}
|
|
|
|
void Module::consolidateAnnotations() {
|
|
std::vector<Instruction *> annotations(mAnnotations->begin(),
|
|
mAnnotations->end());
|
|
std::unique_ptr<IVisitor> v(
|
|
CreateInstructionVisitor([&annotations](Instruction *inst) -> void {
|
|
const auto &ann = inst->getAnnotations();
|
|
annotations.insert(annotations.end(), ann.begin(), ann.end());
|
|
}));
|
|
v->visit(this);
|
|
mAnnotations->clear();
|
|
mAnnotations->addAnnotations(annotations.begin(), annotations.end());
|
|
}
|
|
|
|
EntryPointDefinition::EntryPointDefinition(Builder *builder,
|
|
ExecutionModel execModel,
|
|
FunctionDefinition *func,
|
|
const char *name)
|
|
: Entity(builder), mFunction(func->getInstruction()),
|
|
mExecutionModel(execModel) {
|
|
mName = strndup(name, strlen(name));
|
|
mEntryPointInst = mBuilder->MakeEntryPoint(execModel, mFunction, mName);
|
|
}
|
|
|
|
bool EntryPointDefinition::DeserializeInternal(InputWordStream &IS) {
|
|
if (IS.empty()) {
|
|
return false;
|
|
}
|
|
|
|
if ((mEntryPointInst = Deserialize<EntryPointInst>(IS))) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
EntryPointDefinition *
|
|
EntryPointDefinition::applyExecutionMode(ExecutionModeInst *mode) {
|
|
if (mode->mOperand1.mInstruction == mFunction) {
|
|
addExecutionMode(mode);
|
|
}
|
|
return this;
|
|
}
|
|
|
|
EntryPointDefinition *EntryPointDefinition::addToInterface(VariableInst *var) {
|
|
mInterface.push_back(var);
|
|
mEntryPointInst->mOperand4.push_back(var);
|
|
return this;
|
|
}
|
|
|
|
EntryPointDefinition *EntryPointDefinition::setLocalSize(uint32_t width,
|
|
uint32_t height,
|
|
uint32_t depth) {
|
|
mLocalSize.mWidth = width;
|
|
mLocalSize.mHeight = height;
|
|
mLocalSize.mDepth = depth;
|
|
|
|
auto mode = mBuilder->MakeExecutionMode(mFunction, ExecutionMode::LocalSize);
|
|
mode->addExtraOperand(width)->addExtraOperand(height)->addExtraOperand(depth);
|
|
|
|
addExecutionMode(mode);
|
|
|
|
return this;
|
|
}
|
|
|
|
bool DebugInfoSection::DeserializeInternal(InputWordStream &IS) {
|
|
while (true) {
|
|
if (auto str = Deserialize<StringInst>(IS)) {
|
|
mSources.push_back(str);
|
|
} else if (auto src = Deserialize<SourceInst>(IS)) {
|
|
mSources.push_back(src);
|
|
} else if (auto srcExt = Deserialize<SourceExtensionInst>(IS)) {
|
|
mSources.push_back(srcExt);
|
|
} else if (auto srcCont = Deserialize<SourceContinuedInst>(IS)) {
|
|
mSources.push_back(srcCont);
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
while (true) {
|
|
if (auto name = Deserialize<NameInst>(IS)) {
|
|
mNames.push_back(name);
|
|
} else if (auto memName = Deserialize<MemberNameInst>(IS)) {
|
|
mNames.push_back(memName);
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
DebugInfoSection *DebugInfoSection::addSource(SourceLanguage lang,
|
|
int version) {
|
|
SourceInst *source = mBuilder->MakeSource(lang, version);
|
|
mSources.push_back(source);
|
|
return this;
|
|
}
|
|
|
|
DebugInfoSection *DebugInfoSection::addSourceExtension(const char *ext) {
|
|
SourceExtensionInst *inst = mBuilder->MakeSourceExtension(ext);
|
|
mSources.push_back(inst);
|
|
return this;
|
|
}
|
|
|
|
DebugInfoSection *DebugInfoSection::addString(const char *str) {
|
|
StringInst *source = mBuilder->MakeString(str);
|
|
mSources.push_back(source);
|
|
return this;
|
|
}
|
|
|
|
std::string DebugInfoSection::findStringOfPrefix(const char *prefix) {
|
|
auto it = std::find_if(
|
|
mSources.begin(), mSources.end(), [prefix](Instruction *inst) -> bool {
|
|
if (inst->getOpCode() != OpString) {
|
|
return false;
|
|
}
|
|
const StringInst *strInst = static_cast<const StringInst *>(inst);
|
|
const std::string &str = strInst->mOperand1;
|
|
return str.find(prefix) == 0;
|
|
});
|
|
if (it == mSources.end()) {
|
|
return "";
|
|
}
|
|
StringInst *strInst = static_cast<StringInst *>(*it);
|
|
return strInst->mOperand1;
|
|
}
|
|
|
|
Instruction *DebugInfoSection::lookupByName(const char *name) const {
|
|
for (auto inst : mNames) {
|
|
if (inst->getOpCode() == OpName) {
|
|
NameInst *nameInst = static_cast<NameInst *>(inst);
|
|
if (nameInst->mOperand2.compare(name) == 0) {
|
|
return nameInst->mOperand1.mInstruction;
|
|
}
|
|
}
|
|
// Ignore member names
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
const char *
|
|
DebugInfoSection::lookupNameByInstruction(const Instruction *target) const {
|
|
for (auto inst : mNames) {
|
|
if (inst->getOpCode() == OpName) {
|
|
NameInst *nameInst = static_cast<NameInst *>(inst);
|
|
if (nameInst->mOperand1.mInstruction == target) {
|
|
return nameInst->mOperand2.c_str();
|
|
}
|
|
}
|
|
// Ignore member names
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
AnnotationSection::AnnotationSection() : mAnnotationsDeleter(mAnnotations) {}
|
|
|
|
AnnotationSection::AnnotationSection(Builder *b)
|
|
: Entity(b), mAnnotationsDeleter(mAnnotations) {}
|
|
|
|
bool AnnotationSection::DeserializeInternal(InputWordStream &IS) {
|
|
while (true) {
|
|
if (auto decor = Deserialize<DecorateInst>(IS)) {
|
|
mAnnotations.push_back(decor);
|
|
} else if (auto decor = Deserialize<MemberDecorateInst>(IS)) {
|
|
mAnnotations.push_back(decor);
|
|
} else if (auto decor = Deserialize<GroupDecorateInst>(IS)) {
|
|
mAnnotations.push_back(decor);
|
|
} else if (auto decor = Deserialize<GroupMemberDecorateInst>(IS)) {
|
|
mAnnotations.push_back(decor);
|
|
} else if (auto decor = Deserialize<DecorationGroupInst>(IS)) {
|
|
mAnnotations.push_back(decor);
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
GlobalSection::GlobalSection() : mGlobalDefsDeleter(mGlobalDefs) {}
|
|
|
|
GlobalSection::GlobalSection(Builder *builder)
|
|
: Entity(builder), mGlobalDefsDeleter(mGlobalDefs) {}
|
|
|
|
namespace {
|
|
|
|
template <typename T>
|
|
T *findOrCreate(std::function<bool(T *)> criteria, std::function<T *()> factory,
|
|
std::vector<Instruction *> *globals) {
|
|
T *derived;
|
|
for (auto inst : *globals) {
|
|
if (inst->getOpCode() == T::mOpCode) {
|
|
T *derived = static_cast<T *>(inst);
|
|
if (criteria(derived)) {
|
|
return derived;
|
|
}
|
|
}
|
|
}
|
|
derived = factory();
|
|
globals->push_back(derived);
|
|
return derived;
|
|
}
|
|
|
|
} // anonymous namespace
|
|
|
|
bool GlobalSection::DeserializeInternal(InputWordStream &IS) {
|
|
while (true) {
|
|
#define HANDLE_INSTRUCTION(OPCODE, INST_CLASS) \
|
|
if (auto typeInst = Deserialize<INST_CLASS>(IS)) { \
|
|
mGlobalDefs.push_back(typeInst); \
|
|
continue; \
|
|
}
|
|
#include "const_inst_dispatches_generated.h"
|
|
#include "type_inst_dispatches_generated.h"
|
|
#undef HANDLE_INSTRUCTION
|
|
|
|
if (auto globalInst = Deserialize<VariableInst>(IS)) {
|
|
// Check if this is function scoped
|
|
if (globalInst->mOperand1 == StorageClass::Function) {
|
|
Module::errs() << "warning: Variable (id = " << globalInst->mResult;
|
|
Module::errs() << ") has function scope in global section.\n";
|
|
// Khronos LLVM-SPIRV convertor emits "Function" storage-class globals.
|
|
// As a workaround, accept such SPIR-V code here, and fix it up later
|
|
// in the rs2spirv compiler by correcting the storage class.
|
|
// In a stricter deserializer, such code should be rejected, and we
|
|
// should return false here.
|
|
}
|
|
mGlobalDefs.push_back(globalInst);
|
|
continue;
|
|
}
|
|
|
|
if (auto globalInst = Deserialize<UndefInst>(IS)) {
|
|
mGlobalDefs.push_back(globalInst);
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
ConstantInst *GlobalSection::getConstant(TypeIntInst *type, int32_t value) {
|
|
return findOrCreate<ConstantInst>(
|
|
[=](ConstantInst *c) { return c->mOperand1.intValue == value; },
|
|
[=]() -> ConstantInst * {
|
|
LiteralContextDependentNumber cdn = {.intValue = value};
|
|
return mBuilder->MakeConstant(type, cdn);
|
|
},
|
|
&mGlobalDefs);
|
|
}
|
|
|
|
ConstantInst *GlobalSection::getConstant(TypeIntInst *type, uint32_t value) {
|
|
return findOrCreate<ConstantInst>(
|
|
[=](ConstantInst *c) { return c->mOperand1.intValue == (int)value; },
|
|
[=]() -> ConstantInst * {
|
|
LiteralContextDependentNumber cdn = {.intValue = (int)value};
|
|
return mBuilder->MakeConstant(type, cdn);
|
|
},
|
|
&mGlobalDefs);
|
|
}
|
|
|
|
ConstantInst *GlobalSection::getConstant(TypeFloatInst *type, float value) {
|
|
return findOrCreate<ConstantInst>(
|
|
[=](ConstantInst *c) { return c->mOperand1.floatValue == value; },
|
|
[=]() -> ConstantInst * {
|
|
LiteralContextDependentNumber cdn = {.floatValue = value};
|
|
return mBuilder->MakeConstant(type, cdn);
|
|
},
|
|
&mGlobalDefs);
|
|
}
|
|
|
|
ConstantCompositeInst *
|
|
GlobalSection::getConstantComposite(TypeVectorInst *type,
|
|
ConstantInst *components[], size_t width) {
|
|
return findOrCreate<ConstantCompositeInst>(
|
|
[=](ConstantCompositeInst *c) {
|
|
if (c->mOperand1.size() != width) {
|
|
return false;
|
|
}
|
|
for (size_t i = 0; i < width; i++) {
|
|
if (c->mOperand1[i].mInstruction != components[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
},
|
|
[=]() -> ConstantCompositeInst * {
|
|
ConstantCompositeInst *c = mBuilder->MakeConstantComposite(type);
|
|
for (size_t i = 0; i < width; i++) {
|
|
c->mOperand1.push_back(components[i]);
|
|
}
|
|
return c;
|
|
},
|
|
&mGlobalDefs);
|
|
}
|
|
|
|
TypeVoidInst *GlobalSection::getVoidType() {
|
|
return findOrCreate<TypeVoidInst>(
|
|
[=](TypeVoidInst *) -> bool { return true; },
|
|
[=]() -> TypeVoidInst * { return mBuilder->MakeTypeVoid(); },
|
|
&mGlobalDefs);
|
|
}
|
|
|
|
TypeIntInst *GlobalSection::getIntType(int bits, bool isSigned) {
|
|
if (isSigned) {
|
|
switch (bits) {
|
|
#define HANDLE_INT_SIZE(INT_TYPE, BITS, SIGNED) \
|
|
case BITS: { \
|
|
return findOrCreate<TypeIntInst>( \
|
|
[=](TypeIntInst *intTy) -> bool { \
|
|
return intTy->mOperand1 == BITS && intTy->mOperand2 == SIGNED; \
|
|
}, \
|
|
[=]() -> TypeIntInst * { \
|
|
return mBuilder->MakeTypeInt(BITS, SIGNED); \
|
|
}, \
|
|
&mGlobalDefs); \
|
|
}
|
|
HANDLE_INT_SIZE(Int, 8, 1);
|
|
HANDLE_INT_SIZE(Int, 16, 1);
|
|
HANDLE_INT_SIZE(Int, 32, 1);
|
|
HANDLE_INT_SIZE(Int, 64, 1);
|
|
default:
|
|
Module::errs() << "unexpected int type";
|
|
}
|
|
} else {
|
|
switch (bits) {
|
|
HANDLE_INT_SIZE(UInt, 8, 0);
|
|
HANDLE_INT_SIZE(UInt, 16, 0);
|
|
HANDLE_INT_SIZE(UInt, 32, 0);
|
|
HANDLE_INT_SIZE(UInt, 64, 0);
|
|
default:
|
|
Module::errs() << "unexpected int type";
|
|
}
|
|
}
|
|
#undef HANDLE_INT_SIZE
|
|
return nullptr;
|
|
}
|
|
|
|
TypeFloatInst *GlobalSection::getFloatType(int bits) {
|
|
switch (bits) {
|
|
#define HANDLE_FLOAT_SIZE(BITS) \
|
|
case BITS: { \
|
|
return findOrCreate<TypeFloatInst>( \
|
|
[=](TypeFloatInst *floatTy) -> bool { \
|
|
return floatTy->mOperand1 == BITS; \
|
|
}, \
|
|
[=]() -> TypeFloatInst * { return mBuilder->MakeTypeFloat(BITS); }, \
|
|
&mGlobalDefs); \
|
|
}
|
|
HANDLE_FLOAT_SIZE(16);
|
|
HANDLE_FLOAT_SIZE(32);
|
|
HANDLE_FLOAT_SIZE(64);
|
|
default:
|
|
Module::errs() << "unexpeced floating point type";
|
|
}
|
|
#undef HANDLE_FLOAT_SIZE
|
|
return nullptr;
|
|
}
|
|
|
|
TypeVectorInst *GlobalSection::getVectorType(Instruction *componentType,
|
|
int width) {
|
|
// TODO: verify that componentType is basic numeric types
|
|
|
|
return findOrCreate<TypeVectorInst>(
|
|
[=](TypeVectorInst *vecTy) -> bool {
|
|
return vecTy->mOperand1.mInstruction == componentType &&
|
|
vecTy->mOperand2 == width;
|
|
},
|
|
[=]() -> TypeVectorInst * {
|
|
return mBuilder->MakeTypeVector(componentType, width);
|
|
},
|
|
&mGlobalDefs);
|
|
}
|
|
|
|
TypePointerInst *GlobalSection::getPointerType(StorageClass storage,
|
|
Instruction *pointeeType) {
|
|
return findOrCreate<TypePointerInst>(
|
|
[=](TypePointerInst *type) -> bool {
|
|
return type->mOperand1 == storage &&
|
|
type->mOperand2.mInstruction == pointeeType;
|
|
},
|
|
[=]() -> TypePointerInst * {
|
|
return mBuilder->MakeTypePointer(storage, pointeeType);
|
|
},
|
|
&mGlobalDefs);
|
|
}
|
|
|
|
TypeRuntimeArrayInst *
|
|
GlobalSection::getRuntimeArrayType(Instruction *elemType) {
|
|
return findOrCreate<TypeRuntimeArrayInst>(
|
|
[=](TypeRuntimeArrayInst * /*type*/) -> bool {
|
|
// return type->mOperand1.mInstruction == elemType;
|
|
return false;
|
|
},
|
|
[=]() -> TypeRuntimeArrayInst * {
|
|
return mBuilder->MakeTypeRuntimeArray(elemType);
|
|
},
|
|
&mGlobalDefs);
|
|
}
|
|
|
|
TypeStructInst *GlobalSection::getStructType(Instruction *fieldType[],
|
|
int numField) {
|
|
TypeStructInst *structTy = mBuilder->MakeTypeStruct();
|
|
for (int i = 0; i < numField; i++) {
|
|
structTy->mOperand1.push_back(fieldType[i]);
|
|
}
|
|
mGlobalDefs.push_back(structTy);
|
|
return structTy;
|
|
}
|
|
|
|
TypeFunctionInst *GlobalSection::getFunctionType(Instruction *retType,
|
|
Instruction *const argType[],
|
|
size_t numArg) {
|
|
return findOrCreate<TypeFunctionInst>(
|
|
[=](TypeFunctionInst *type) -> bool {
|
|
if (type->mOperand1.mInstruction != retType ||
|
|
type->mOperand2.size() != numArg) {
|
|
return false;
|
|
}
|
|
for (size_t i = 0; i < numArg; i++) {
|
|
if (type->mOperand2[i].mInstruction != argType[i]) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
},
|
|
[=]() -> TypeFunctionInst * {
|
|
TypeFunctionInst *funcTy = mBuilder->MakeTypeFunction(retType);
|
|
for (size_t i = 0; i < numArg; i++) {
|
|
funcTy->mOperand2.push_back(argType[i]);
|
|
}
|
|
return funcTy;
|
|
},
|
|
&mGlobalDefs);
|
|
}
|
|
|
|
GlobalSection *GlobalSection::addStructType(TypeStructInst *structType) {
|
|
mGlobalDefs.push_back(structType);
|
|
return this;
|
|
}
|
|
|
|
GlobalSection *GlobalSection::addVariable(VariableInst *var) {
|
|
mGlobalDefs.push_back(var);
|
|
return this;
|
|
}
|
|
|
|
VariableInst *GlobalSection::getInvocationId() {
|
|
if (mInvocationId) {
|
|
return mInvocationId.get();
|
|
}
|
|
|
|
TypeIntInst *UIntTy = getIntType(32, false);
|
|
TypeVectorInst *V3UIntTy = getVectorType(UIntTy, 3);
|
|
TypePointerInst *V3UIntPtrTy = getPointerType(StorageClass::Input, V3UIntTy);
|
|
|
|
VariableInst *InvocationId =
|
|
mBuilder->MakeVariable(V3UIntPtrTy, StorageClass::Input);
|
|
InvocationId->decorate(Decoration::BuiltIn)
|
|
->addExtraOperand(static_cast<uint32_t>(BuiltIn::GlobalInvocationId));
|
|
|
|
mInvocationId.reset(InvocationId);
|
|
|
|
return InvocationId;
|
|
}
|
|
|
|
VariableInst *GlobalSection::getNumWorkgroups() {
|
|
if (mNumWorkgroups) {
|
|
return mNumWorkgroups.get();
|
|
}
|
|
|
|
TypeIntInst *UIntTy = getIntType(32, false);
|
|
TypeVectorInst *V3UIntTy = getVectorType(UIntTy, 3);
|
|
TypePointerInst *V3UIntPtrTy = getPointerType(StorageClass::Input, V3UIntTy);
|
|
|
|
VariableInst *GNum = mBuilder->MakeVariable(V3UIntPtrTy, StorageClass::Input);
|
|
GNum->decorate(Decoration::BuiltIn)
|
|
->addExtraOperand(static_cast<uint32_t>(BuiltIn::NumWorkgroups));
|
|
|
|
mNumWorkgroups.reset(GNum);
|
|
|
|
return GNum;
|
|
}
|
|
|
|
bool FunctionDeclaration::DeserializeInternal(InputWordStream &IS) {
|
|
if (!Deserialize<FunctionInst>(IS)) {
|
|
return false;
|
|
}
|
|
|
|
DeserializeZeroOrMore<FunctionParameterInst>(IS, mParams);
|
|
|
|
if (!Deserialize<FunctionEndInst>(IS)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
template <> Instruction *Deserialize(InputWordStream &IS) {
|
|
Instruction *inst;
|
|
|
|
switch ((*IS) & 0xFFFF) {
|
|
#define HANDLE_INSTRUCTION(OPCODE, INST_CLASS) \
|
|
case OPCODE: \
|
|
inst = Deserialize<INST_CLASS>(IS); \
|
|
break;
|
|
#include "instruction_dispatches_generated.h"
|
|
#undef HANDLE_INSTRUCTION
|
|
default:
|
|
Module::errs() << "unrecognized instruction";
|
|
inst = nullptr;
|
|
}
|
|
|
|
return inst;
|
|
}
|
|
|
|
bool Block::DeserializeInternal(InputWordStream &IS) {
|
|
Instruction *inst;
|
|
while (((*IS) & 0xFFFF) != OpFunctionEnd &&
|
|
(inst = Deserialize<Instruction>(IS))) {
|
|
mInsts.push_back(inst);
|
|
if (inst->getOpCode() == OpBranch ||
|
|
inst->getOpCode() == OpBranchConditional ||
|
|
inst->getOpCode() == OpSwitch || inst->getOpCode() == OpKill ||
|
|
inst->getOpCode() == OpReturn || inst->getOpCode() == OpReturnValue ||
|
|
inst->getOpCode() == OpUnreachable) {
|
|
break;
|
|
}
|
|
}
|
|
return !mInsts.empty();
|
|
}
|
|
|
|
FunctionDefinition::FunctionDefinition()
|
|
: mParamsDeleter(mParams), mBlocksDeleter(mBlocks) {}
|
|
|
|
FunctionDefinition::FunctionDefinition(Builder *builder, FunctionInst *func,
|
|
FunctionEndInst *end)
|
|
: Entity(builder), mFunc(func), mFuncEnd(end), mParamsDeleter(mParams),
|
|
mBlocksDeleter(mBlocks) {}
|
|
|
|
bool FunctionDefinition::DeserializeInternal(InputWordStream &IS) {
|
|
mFunc.reset(Deserialize<FunctionInst>(IS));
|
|
if (!mFunc) {
|
|
return false;
|
|
}
|
|
|
|
DeserializeZeroOrMore<FunctionParameterInst>(IS, mParams);
|
|
DeserializeZeroOrMore<Block>(IS, mBlocks);
|
|
|
|
mFuncEnd.reset(Deserialize<FunctionEndInst>(IS));
|
|
if (!mFuncEnd) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
Instruction *FunctionDefinition::getReturnType() const {
|
|
return mFunc->mResultType.mInstruction;
|
|
}
|
|
|
|
} // namespace spirit
|
|
} // namespace android
|