Home | History | Annotate | Download | only in libSPIRV
      1 //===- SPIRVInstruction.cpp -Class to represent SPIR-V instruction - C++ -*-===//
      2 //
      3 //                     The LLVM/SPIRV Translator
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 // Copyright (c) 2014 Advanced Micro Devices, Inc. All rights reserved.
      9 //
     10 // Permission is hereby granted, free of charge, to any person obtaining a
     11 // copy of this software and associated documentation files (the "Software"),
     12 // to deal with the Software without restriction, including without limitation
     13 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
     14 // and/or sell copies of the Software, and to permit persons to whom the
     15 // Software is furnished to do so, subject to the following conditions:
     16 //
     17 // Redistributions of source code must retain the above copyright notice,
     18 // this list of conditions and the following disclaimers.
     19 // Redistributions in binary form must reproduce the above copyright notice,
     20 // this list of conditions and the following disclaimers in the documentation
     21 // and/or other materials provided with the distribution.
     22 // Neither the names of Advanced Micro Devices, Inc., nor the names of its
     23 // contributors may be used to endorse or promote products derived from this
     24 // Software without specific prior written permission.
     25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     26 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     27 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     28 // CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     29 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     30 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH
     31 // THE SOFTWARE.
     32 //
     33 //===----------------------------------------------------------------------===//
     34 /// \file
     35 ///
     36 /// This file implements SPIR-V instructions.
     37 ///
     38 //===----------------------------------------------------------------------===//
     39 
     40 #include "SPIRVInstruction.h"
     41 #include "SPIRVBasicBlock.h"
     42 #include "SPIRVFunction.h"
     43 
     44 #include <unordered_set>
     45 
     46 namespace SPIRV {
     47 
     48 // Complete constructor for instruction with type and id
     49 SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC,
     50     SPIRVType *TheType, SPIRVId TheId, SPIRVBasicBlock *TheBB)
     51   :SPIRVValue(TheBB->getModule(), TheWordCount, TheOC, TheType, TheId),
     52    BB(TheBB){
     53   validate();
     54 }
     55 
     56 SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC,
     57   SPIRVType *TheType, SPIRVId TheId, SPIRVBasicBlock *TheBB, SPIRVModule *TheBM)
     58   : SPIRVValue(TheBM, TheWordCount, TheOC, TheType, TheId), BB(TheBB){
     59   validate();
     60 }
     61 
     62 // Complete constructor for instruction with id but no type
     63 SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC,
     64     SPIRVId TheId, SPIRVBasicBlock *TheBB)
     65   :SPIRVValue(TheBB->getModule(), TheWordCount, TheOC, TheId), BB(TheBB){
     66   validate();
     67 }
     68 // Complete constructor for instruction without type and id
     69 SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC,
     70     SPIRVBasicBlock *TheBB)
     71   :SPIRVValue(TheBB->getModule(), TheWordCount, TheOC), BB(TheBB){
     72   validate();
     73 }
     74 // Complete constructor for instruction with type but no id
     75 SPIRVInstruction::SPIRVInstruction(unsigned TheWordCount, Op TheOC,
     76     SPIRVType *TheType, SPIRVBasicBlock *TheBB)
     77   :SPIRVValue(TheBB->getModule(), TheWordCount, TheOC, TheType), BB(TheBB){
     78   validate();
     79 }
     80 
     81 void
     82 SPIRVInstruction::setParent(SPIRVBasicBlock *TheBB) {
     83   assert(TheBB && "Invalid BB");
     84   if (BB == TheBB)
     85     return;
     86   assert(BB == NULL && "BB cannot change parent");
     87   BB = TheBB;
     88 }
     89 
     90 void
     91 SPIRVInstruction::setScope(SPIRVEntry *Scope) {
     92   assert(Scope && Scope->getOpCode() == OpLabel && "Invalid scope");
     93   setParent(static_cast<SPIRVBasicBlock*>(Scope));
     94 }
     95 
     96 SPIRVFunctionCall::SPIRVFunctionCall(SPIRVId TheId, SPIRVFunction *TheFunction,
     97     const std::vector<SPIRVWord> &TheArgs, SPIRVBasicBlock *BB)
     98   :SPIRVFunctionCallGeneric(
     99       TheFunction->getFunctionType()->getReturnType(),
    100       TheId, TheArgs, BB), FunctionId(TheFunction->getId()){
    101   validate();
    102 }
    103 
    104 void
    105 SPIRVFunctionCall::validate()const {
    106   SPIRVFunctionCallGeneric::validate();
    107 }
    108 
    109 // ToDo: Each instruction should implement this function
    110 std::vector<SPIRVValue *>
    111 SPIRVInstruction::getOperands() {
    112   std::vector<SPIRVValue *> Empty;
    113   assert(0 && "not supported");
    114   return Empty;
    115 }
    116 
    117 std::vector<SPIRVType*>
    118 SPIRVInstruction::getOperandTypes(const std::vector<SPIRVValue *> &Ops) {
    119   std::vector<SPIRVType*> Tys;
    120   for (auto& I : Ops) {
    121     SPIRVType* Ty = nullptr;
    122     if (I->getOpCode() == OpFunction)
    123       Ty = reinterpret_cast<SPIRVFunction*>(I)->getFunctionType();
    124     else
    125       Ty = I->getType();
    126 
    127     Tys.push_back(Ty);
    128   }
    129   return Tys;
    130 }
    131 
    132 std::vector<SPIRVType*>
    133 SPIRVInstruction::getOperandTypes() {
    134   return getOperandTypes(getOperands());
    135 }
    136 
    137 bool
    138 isSpecConstantOpAllowedOp(Op OC) {
    139   static SPIRVWord Table[] =
    140   {
    141     OpSConvert,
    142     OpFConvert,
    143     OpConvertFToS,
    144     OpConvertSToF,
    145     OpConvertFToU,
    146     OpConvertUToF,
    147     OpUConvert,
    148     OpConvertPtrToU,
    149     OpConvertUToPtr,
    150     OpGenericCastToPtr,
    151     OpPtrCastToGeneric,
    152     OpBitcast,
    153     OpQuantizeToF16,
    154     OpSNegate,
    155     OpNot,
    156     OpIAdd,
    157     OpISub,
    158     OpIMul,
    159     OpUDiv,
    160     OpSDiv,
    161     OpUMod,
    162     OpSRem,
    163     OpSMod,
    164     OpShiftRightLogical,
    165     OpShiftRightArithmetic,
    166     OpShiftLeftLogical,
    167     OpBitwiseOr,
    168     OpBitwiseXor,
    169     OpBitwiseAnd,
    170     OpFNegate,
    171     OpFAdd,
    172     OpFSub,
    173     OpFMul,
    174     OpFDiv,
    175     OpFRem,
    176     OpFMod,
    177     OpVectorShuffle,
    178     OpCompositeExtract,
    179     OpCompositeInsert,
    180     OpLogicalOr,
    181     OpLogicalAnd,
    182     OpLogicalNot,
    183     OpLogicalEqual,
    184     OpLogicalNotEqual,
    185     OpSelect,
    186     OpIEqual,
    187     OpULessThan,
    188     OpSLessThan,
    189     OpUGreaterThan,
    190     OpSGreaterThan,
    191     OpULessThanEqual,
    192     OpSLessThanEqual,
    193     OpUGreaterThanEqual,
    194     OpSGreaterThanEqual,
    195     OpAccessChain,
    196     OpInBoundsAccessChain,
    197     OpPtrAccessChain,
    198     OpInBoundsPtrAccessChain,
    199   };
    200   static std::unordered_set<SPIRVWord>
    201     Allow(std::begin(Table), std::end(Table));
    202   return Allow.count(OC);
    203 }
    204 
    205 SPIRVSpecConstantOp *
    206 createSpecConstantOpInst(SPIRVInstruction *Inst) {
    207   auto OC = Inst->getOpCode();
    208   assert (isSpecConstantOpAllowedOp(OC) &&
    209       "Op code not allowed for OpSpecConstantOp");
    210   auto Ops = Inst->getIds(Inst->getOperands());
    211   Ops.insert(Ops.begin(), OC);
    212   return static_cast<SPIRVSpecConstantOp *>(
    213     SPIRVSpecConstantOp::create(OpSpecConstantOp, Inst->getType(),
    214         Inst->getId(), Ops, nullptr, Inst->getModule()));
    215 }
    216 
    217 SPIRVInstruction *
    218 createInstFromSpecConstantOp(SPIRVSpecConstantOp *Inst) {
    219   assert(Inst->getOpCode() == OpSpecConstantOp &&
    220       "Not OpSpecConstantOp");
    221   auto Ops = Inst->getOpWords();
    222   auto OC = static_cast<Op>(Ops[0]);
    223   assert (isSpecConstantOpAllowedOp(OC) &&
    224       "Op code not allowed for OpSpecConstantOp");
    225   Ops.erase(Ops.begin(), Ops.begin() + 1);
    226   return SPIRVInstTemplateBase::create(OC, Inst->getType(),
    227       Inst->getId(), Ops, nullptr, Inst->getModule());
    228 }
    229 
    230 }
    231 
    232 
    233