/* * 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 #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 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 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(IS, mCapabilities); DeserializeZeroOrMore(IS, mExtensions); DeserializeZeroOrMore(IS, mExtInstImports); mMemoryModel.reset(Deserialize(IS)); if (!mMemoryModel) { errs() << "Missing memory model specification.\n"; return false; } DeserializeZeroOrMore(IS, mEntryPoints); DeserializeZeroOrMore(IS, mExecutionModes); for (auto entry : mEntryPoints) { mEntryPointInsts.push_back(entry->getInstruction()); for (auto mode : mExecutionModes) { entry->applyExecutionMode(mode); } } mDebugInfo.reset(Deserialize(IS)); mAnnotations.reset(Deserialize(IS)); mGlobals.reset(Deserialize(IS)); DeserializeZeroOrMore(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 &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(inst)); case OpTypeInt: return getSize(static_cast(inst)); case OpTypeFloat: return getSize(static_cast(inst)); case OpTypeVector: return getSize(static_cast(inst)); case OpTypeStruct: return getSize(static_cast(inst)); case OpTypeFunction: return getSize(static_cast(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(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 annotations(mAnnotations->begin(), mAnnotations->end()); std::unique_ptr 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); (void)mExecutionModel; // suppress unused private field warning } bool EntryPointDefinition::DeserializeInternal(InputWordStream &IS) { if (IS.empty()) { return false; } if ((mEntryPointInst = Deserialize(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(IS)) { mSources.push_back(str); } else if (auto src = Deserialize(IS)) { mSources.push_back(src); } else if (auto srcExt = Deserialize(IS)) { mSources.push_back(srcExt); } else if (auto srcCont = Deserialize(IS)) { mSources.push_back(srcCont); } else { break; } } while (true) { if (auto name = Deserialize(IS)) { mNames.push_back(name); } else if (auto memName = Deserialize(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(inst); const std::string &str = strInst->mOperand1; return str.find(prefix) == 0; }); if (it == mSources.end()) { return ""; } StringInst *strInst = static_cast(*it); return strInst->mOperand1; } Instruction *DebugInfoSection::lookupByName(const char *name) const { for (auto inst : mNames) { if (inst->getOpCode() == OpName) { NameInst *nameInst = static_cast(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(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(IS)) { mAnnotations.push_back(decor); } else if (auto decor = Deserialize(IS)) { mAnnotations.push_back(decor); } else if (auto decor = Deserialize(IS)) { mAnnotations.push_back(decor); } else if (auto decor = Deserialize(IS)) { mAnnotations.push_back(decor); } else if (auto decor = Deserialize(IS)) { mAnnotations.push_back(decor); } else { break; } } return true; } GlobalSection::GlobalSection() : mGlobalDefsDeleter(mGlobalDefs) {} GlobalSection::GlobalSection(Builder *builder) : Entity(builder), mGlobalDefsDeleter(mGlobalDefs) {} namespace { template T *findOrCreate(std::function criteria, std::function factory, std::vector *globals) { T *derived; for (auto inst : *globals) { if (inst->getOpCode() == T::mOpCode) { T *derived = static_cast(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(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(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(IS)) { mGlobalDefs.push_back(globalInst); continue; } break; } return true; } ConstantInst *GlobalSection::getConstant(TypeIntInst *type, int32_t value) { return findOrCreate( [=](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 *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 *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 *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 *) -> 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 *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 *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 *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 *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 * /*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 *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(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(BuiltIn::NumWorkgroups)); mNumWorkgroups.reset(GNum); return GNum; } bool FunctionDeclaration::DeserializeInternal(InputWordStream &IS) { if (!(mFunc = Deserialize(IS))) { return false; } DeserializeZeroOrMore(IS, mParams); if (!(mFuncEnd = Deserialize(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(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(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(IS)); if (!mFunc) { return false; } DeserializeZeroOrMore(IS, mParams); DeserializeZeroOrMore(IS, mBlocks); mFuncEnd.reset(Deserialize(IS)); if (!mFuncEnd) { return false; } return true; } Instruction *FunctionDefinition::getReturnType() const { return mFunc->mResultType.mInstruction; } } // namespace spirit } // namespace android