//===- SPIRVInstruction.cpp -Class to represent SPIR-V instruction - C++ -*-===// // // The LLVM/SPIRV Translator // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved. // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal with the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimers. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimers in the documentation // and/or other materials provided with the distribution. // Neither the names of Advanced Micro Devices, Inc., nor the names of its // contributors may be used to endorse or promote products derived from this // Software without specific prior written permission. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH // THE SOFTWARE. // //===----------------------------------------------------------------------===// /// \file /// /// This file implements SPIR-V instructions. /// //===----------------------------------------------------------------------===// #include "SPIRVInstruction.h" #include "SPIRVBasicBlock.h" #include "SPIRVFunction.h" #include <unordered_set> namespace SPIRV { // Complete constructor for instruction with type and id SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVType *TheType, SPIRVId TheId, SPIRVBasicBlock *TheBB) :SPIRVValue(TheBB->getModule(), TheWordCount, TheOC, TheType, TheId), BB(TheBB){ validate(); } SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVType *TheType, SPIRVId TheId, SPIRVBasicBlock *TheBB, SPIRVModule *TheBM) : SPIRVValue(TheBM, TheWordCount, TheOC, TheType, TheId), BB(TheBB){ validate(); } // Complete constructor for instruction with id but no type SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVId TheId, SPIRVBasicBlock *TheBB) :SPIRVValue(TheBB->getModule(), TheWordCount, TheOC, TheId), BB(TheBB){ validate(); } // Complete constructor for instruction without type and id SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVBasicBlock *TheBB) :SPIRVValue(TheBB->getModule(), TheWordCount, TheOC), BB(TheBB){ validate(); } // Complete constructor for instruction with type but no id SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC, SPIRVType *TheType, SPIRVBasicBlock *TheBB) :SPIRVValue(TheBB->getModule(), TheWordCount, TheOC, TheType), BB(TheBB){ validate(); } void SPIRVInstruction::setParent(SPIRVBasicBlock *TheBB) { assert(TheBB && "Invalid BB"); if (BB == TheBB) return; assert(BB == NULL && "BB cannot change parent"); BB = TheBB; } void SPIRVInstruction::setScope(SPIRVEntry *Scope) { assert(Scope && Scope->getOpCode() == OpLabel && "Invalid scope"); setParent(static_cast<SPIRVBasicBlock*>(Scope)); } SPIRVFunctionCall::SPIRVFunctionCall(SPIRVId TheId, SPIRVFunction *TheFunction, const std::vector<SPIRVWord> &TheArgs, SPIRVBasicBlock *BB) :SPIRVFunctionCallGeneric( TheFunction->getFunctionType()->getReturnType(), TheId, TheArgs, BB), FunctionId(TheFunction->getId()){ validate(); } void SPIRVFunctionCall::validate()const { SPIRVFunctionCallGeneric::validate(); } // ToDo: Each instruction should implement this function std::vector<SPIRVValue *> SPIRVInstruction::getOperands() { std::vector<SPIRVValue *> Empty; assert(0 && "not supported"); return Empty; } std::vector<SPIRVType*> SPIRVInstruction::getOperandTypes(const std::vector<SPIRVValue *> &Ops) { std::vector<SPIRVType*> Tys; for (auto& I : Ops) { SPIRVType* Ty = nullptr; if (I->getOpCode() == OpFunction) Ty = reinterpret_cast<SPIRVFunction*>(I)->getFunctionType(); else Ty = I->getType(); Tys.push_back(Ty); } return Tys; } std::vector<SPIRVType*> SPIRVInstruction::getOperandTypes() { return getOperandTypes(getOperands()); } bool isSpecConstantOpAllowedOp(Op OC) { static SPIRVWord Table[] = { OpSConvert, OpFConvert, OpConvertFToS, OpConvertSToF, OpConvertFToU, OpConvertUToF, OpUConvert, OpConvertPtrToU, OpConvertUToPtr, OpGenericCastToPtr, OpPtrCastToGeneric, OpBitcast, OpQuantizeToF16, OpSNegate, OpNot, OpIAdd, OpISub, OpIMul, OpUDiv, OpSDiv, OpUMod, OpSRem, OpSMod, OpShiftRightLogical, OpShiftRightArithmetic, OpShiftLeftLogical, OpBitwiseOr, OpBitwiseXor, OpBitwiseAnd, OpFNegate, OpFAdd, OpFSub, OpFMul, OpFDiv, OpFRem, OpFMod, OpVectorShuffle, OpCompositeExtract, OpCompositeInsert, OpLogicalOr, OpLogicalAnd, OpLogicalNot, OpLogicalEqual, OpLogicalNotEqual, OpSelect, OpIEqual, OpULessThan, OpSLessThan, OpUGreaterThan, OpSGreaterThan, OpULessThanEqual, OpSLessThanEqual, OpUGreaterThanEqual, OpSGreaterThanEqual, OpAccessChain, OpInBoundsAccessChain, OpPtrAccessChain, OpInBoundsPtrAccessChain, }; static std::unordered_set<SPIRVWord> Allow(std::begin(Table), std::end(Table)); return Allow.count(OC); } SPIRVSpecConstantOp * createSpecConstantOpInst(SPIRVInstruction *Inst) { auto OC = Inst->getOpCode(); assert (isSpecConstantOpAllowedOp(OC) && "Op code not allowed for OpSpecConstantOp"); auto Ops = Inst->getIds(Inst->getOperands()); Ops.insert(Ops.begin(), OC); return static_cast<SPIRVSpecConstantOp *>( SPIRVSpecConstantOp::create(OpSpecConstantOp, Inst->getType(), Inst->getId(), Ops, nullptr, Inst->getModule())); } SPIRVInstruction * createInstFromSpecConstantOp(SPIRVSpecConstantOp *Inst) { assert(Inst->getOpCode() == OpSpecConstantOp && "Not OpSpecConstantOp"); auto Ops = Inst->getOpWords(); auto OC = static_cast<Op>(Ops[0]); assert (isSpecConstantOpAllowedOp(OC) && "Op code not allowed for OpSpecConstantOp"); Ops.erase(Ops.begin(), Ops.begin() + 1); return SPIRVInstTemplateBase::create(OC, Inst->getType(), Inst->getId(), Ops, nullptr, Inst->getModule()); } }