//===- 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());
}
}