| /* |
| * 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 |