blob: 8a2681496285d0bc60d5d8c59e353cb25db20d9d [file] [log] [blame]
// Copyright (c) 2017 Google Inc.
//
// 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 "ir_context.h"
#include <spirv/1.0/GLSL.std.450.h>
#include <cstring>
#include "log.h"
#include "mem_pass.h"
namespace spvtools {
namespace ir {
void IRContext::BuildInvalidAnalyses(IRContext::Analysis set) {
if (set & kAnalysisDefUse) {
BuildDefUseManager();
}
if (set & kAnalysisInstrToBlockMapping) {
BuildInstrToBlockMapping();
}
if (set & kAnalysisDecorations) {
BuildDecorationManager();
}
}
void IRContext::InvalidateAnalysesExceptFor(
IRContext::Analysis preserved_analyses) {
uint32_t analyses_to_invalidate = valid_analyses_ & (~preserved_analyses);
InvalidateAnalyses(static_cast<IRContext::Analysis>(analyses_to_invalidate));
}
void IRContext::InvalidateAnalyses(IRContext::Analysis analyses_to_invalidate) {
if (analyses_to_invalidate & kAnalysisDefUse) {
def_use_mgr_.reset(nullptr);
}
if (analyses_to_invalidate & kAnalysisInstrToBlockMapping) {
instr_to_block_.clear();
}
if (analyses_to_invalidate & kAnalysisDecorations) {
decoration_mgr_.reset(nullptr);
}
if (analyses_to_invalidate & kAnalysisCombinators) {
combinator_ops_.clear();
}
valid_analyses_ = Analysis(valid_analyses_ & ~analyses_to_invalidate);
}
void IRContext::KillInst(ir::Instruction* inst) {
if (!inst) {
return;
}
KillNamesAndDecorates(inst);
if (AreAnalysesValid(kAnalysisDefUse)) {
get_def_use_mgr()->ClearInst(inst);
}
if (AreAnalysesValid(kAnalysisInstrToBlockMapping)) {
instr_to_block_.erase(inst);
}
if (AreAnalysesValid(kAnalysisDecorations)) {
if (inst->result_id() != 0) {
decoration_mgr_->RemoveDecorationsFrom(inst->result_id());
}
if (inst->IsDecoration()) {
decoration_mgr_->RemoveDecoration(inst);
}
}
inst->ToNop();
}
bool IRContext::KillDef(uint32_t id) {
ir::Instruction* def = get_def_use_mgr()->GetDef(id);
if (def != nullptr) {
KillInst(def);
return true;
}
return false;
}
bool IRContext::ReplaceAllUsesWith(uint32_t before, uint32_t after) {
if (before == after) return false;
// Ensure that |after| has been registered as def.
assert(get_def_use_mgr()->GetDef(after) && "'after' is not a registered def.");
std::vector<std::pair<ir::Instruction*,uint32_t>> uses_to_update;
get_def_use_mgr()->ForEachUse(before, [&uses_to_update](ir::Instruction* user, uint32_t index) {
uses_to_update.emplace_back(user, index);
});
ir::Instruction* prev = nullptr;
for (auto p : uses_to_update) {
ir::Instruction* user = p.first;
uint32_t index = p.second;
if (prev == nullptr || prev != user) {
ForgetUses(user);
prev = user;
}
const uint32_t type_result_id_count =
(user->result_id() != 0) + (user->type_id() != 0);
if (index < type_result_id_count) {
// Update the type_id. Note that result id is immutable so it should
// never be updated.
if (user->type_id() != 0 && index == 0) {
user->SetResultType(after);
} else if (user->type_id() == 0) {
SPIRV_ASSERT(consumer_, false,
"Result type id considered as use while the instruction "
"doesn't have a result type id.");
(void)consumer_; // Makes the compiler happy for release build.
} else {
SPIRV_ASSERT(consumer_, false,
"Trying setting the immutable result id.");
}
} else {
// Update an in-operand.
uint32_t in_operand_pos = index - type_result_id_count;
// Make the modification in the instruction.
user->SetInOperand(in_operand_pos, {after});
}
AnalyzeUses(user);
};
return true;
}
bool IRContext::IsConsistent() {
#ifndef SPIRV_CHECK_CONTEXT
return true;
#endif
if (AreAnalysesValid(kAnalysisDefUse)) {
opt::analysis::DefUseManager new_def_use(module());
if (*get_def_use_mgr() != new_def_use) {
return false;
}
}
return true;
}
void spvtools::ir::IRContext::ForgetUses(Instruction* inst) {
if (AreAnalysesValid(kAnalysisDefUse)) {
get_def_use_mgr()->EraseUseRecordsOfOperandIds(inst);
}
if (AreAnalysesValid(kAnalysisDecorations)) {
if (inst->IsDecoration()) {
get_decoration_mgr()->RemoveDecoration(inst);
}
}
}
void IRContext::AnalyzeUses(Instruction* inst) {
if (AreAnalysesValid(kAnalysisDefUse)) {
get_def_use_mgr()->AnalyzeInstUse(inst);
}
if (AreAnalysesValid(kAnalysisDecorations)) {
if (inst->IsDecoration()) {
get_decoration_mgr()->AddDecoration(inst);
}
}
}
void IRContext::KillNamesAndDecorates(uint32_t id) {
std::vector<ir::Instruction*> decorations =
get_decoration_mgr()->GetDecorationsFor(id, true);
for (Instruction* inst : decorations) {
KillInst(inst);
}
for (auto& di : debugs2()) {
if (di.opcode() == SpvOpMemberName || di.opcode() == SpvOpName) {
if (di.GetSingleWordInOperand(0) == id) {
KillInst(&di);
}
}
}
}
void IRContext::KillNamesAndDecorates(Instruction* inst) {
const uint32_t rId = inst->result_id();
if (rId == 0) return;
KillNamesAndDecorates(rId);
}
void IRContext::AddCombinatorsForCapability(uint32_t capability) {
if (capability == SpvCapabilityShader) {
combinator_ops_[0].insert({
SpvOpNop,
SpvOpUndef,
SpvOpVariable,
SpvOpImageTexelPointer,
SpvOpLoad,
SpvOpAccessChain,
SpvOpInBoundsAccessChain,
SpvOpArrayLength,
SpvOpVectorExtractDynamic,
SpvOpVectorInsertDynamic,
SpvOpVectorShuffle,
SpvOpCompositeConstruct,
SpvOpCompositeExtract,
SpvOpCompositeInsert,
SpvOpCopyObject,
SpvOpTranspose,
SpvOpSampledImage,
SpvOpImageSampleImplicitLod,
SpvOpImageSampleExplicitLod,
SpvOpImageSampleDrefImplicitLod,
SpvOpImageSampleDrefExplicitLod,
SpvOpImageSampleProjImplicitLod,
SpvOpImageSampleProjExplicitLod,
SpvOpImageSampleProjDrefImplicitLod,
SpvOpImageSampleProjDrefExplicitLod,
SpvOpImageFetch,
SpvOpImageGather,
SpvOpImageDrefGather,
SpvOpImageRead,
SpvOpImage,
SpvOpConvertFToU,
SpvOpConvertFToS,
SpvOpConvertSToF,
SpvOpConvertUToF,
SpvOpUConvert,
SpvOpSConvert,
SpvOpFConvert,
SpvOpQuantizeToF16,
SpvOpBitcast,
SpvOpSNegate,
SpvOpFNegate,
SpvOpIAdd,
SpvOpFAdd,
SpvOpISub,
SpvOpFSub,
SpvOpIMul,
SpvOpFMul,
SpvOpUDiv,
SpvOpSDiv,
SpvOpFDiv,
SpvOpUMod,
SpvOpSRem,
SpvOpSMod,
SpvOpFRem,
SpvOpFMod,
SpvOpVectorTimesScalar,
SpvOpMatrixTimesScalar,
SpvOpVectorTimesMatrix,
SpvOpMatrixTimesVector,
SpvOpMatrixTimesMatrix,
SpvOpOuterProduct,
SpvOpDot,
SpvOpIAddCarry,
SpvOpISubBorrow,
SpvOpUMulExtended,
SpvOpSMulExtended,
SpvOpAny,
SpvOpAll,
SpvOpIsNan,
SpvOpIsInf,
SpvOpLogicalEqual,
SpvOpLogicalNotEqual,
SpvOpLogicalOr,
SpvOpLogicalAnd,
SpvOpLogicalNot,
SpvOpSelect,
SpvOpIEqual,
SpvOpINotEqual,
SpvOpUGreaterThan,
SpvOpSGreaterThan,
SpvOpUGreaterThanEqual,
SpvOpSGreaterThanEqual,
SpvOpULessThan,
SpvOpSLessThan,
SpvOpULessThanEqual,
SpvOpSLessThanEqual,
SpvOpFOrdEqual,
SpvOpFUnordEqual,
SpvOpFOrdNotEqual,
SpvOpFUnordNotEqual,
SpvOpFOrdLessThan,
SpvOpFUnordLessThan,
SpvOpFOrdGreaterThan,
SpvOpFUnordGreaterThan,
SpvOpFOrdLessThanEqual,
SpvOpFUnordLessThanEqual,
SpvOpFOrdGreaterThanEqual,
SpvOpFUnordGreaterThanEqual,
SpvOpShiftRightLogical,
SpvOpShiftRightArithmetic,
SpvOpShiftLeftLogical,
SpvOpBitwiseOr,
SpvOpBitwiseXor,
SpvOpBitwiseAnd,
SpvOpNot,
SpvOpBitFieldInsert,
SpvOpBitFieldSExtract,
SpvOpBitFieldUExtract,
SpvOpBitReverse,
SpvOpBitCount,
SpvOpDPdx,
SpvOpDPdy,
SpvOpFwidth,
SpvOpDPdxFine,
SpvOpDPdyFine,
SpvOpFwidthFine,
SpvOpDPdxCoarse,
SpvOpDPdyCoarse,
SpvOpFwidthCoarse,
SpvOpPhi,
SpvOpImageSparseSampleImplicitLod,
SpvOpImageSparseSampleExplicitLod,
SpvOpImageSparseSampleDrefImplicitLod,
SpvOpImageSparseSampleDrefExplicitLod,
SpvOpImageSparseSampleProjImplicitLod,
SpvOpImageSparseSampleProjExplicitLod,
SpvOpImageSparseSampleProjDrefImplicitLod,
SpvOpImageSparseSampleProjDrefExplicitLod,
SpvOpImageSparseFetch,
SpvOpImageSparseGather,
SpvOpImageSparseDrefGather,
SpvOpImageSparseTexelsResident,
SpvOpImageSparseRead,
SpvOpSizeOf
// TODO(dneto): Add instructions enabled by ImageQuery
});
}
}
void IRContext::AddCombinatorsForExtension(ir::Instruction* extension) {
assert(extension->opcode() == SpvOpExtInstImport &&
"Expecting an import of an extension's instruction set.");
const char* extension_name =
reinterpret_cast<const char*>(&extension->GetInOperand(0).words[0]);
if (!strcmp(extension_name, "GLSL.std.450")) {
combinator_ops_[extension->result_id()] = {GLSLstd450Round,
GLSLstd450RoundEven,
GLSLstd450Trunc,
GLSLstd450FAbs,
GLSLstd450SAbs,
GLSLstd450FSign,
GLSLstd450SSign,
GLSLstd450Floor,
GLSLstd450Ceil,
GLSLstd450Fract,
GLSLstd450Radians,
GLSLstd450Degrees,
GLSLstd450Sin,
GLSLstd450Cos,
GLSLstd450Tan,
GLSLstd450Asin,
GLSLstd450Acos,
GLSLstd450Atan,
GLSLstd450Sinh,
GLSLstd450Cosh,
GLSLstd450Tanh,
GLSLstd450Asinh,
GLSLstd450Acosh,
GLSLstd450Atanh,
GLSLstd450Atan2,
GLSLstd450Pow,
GLSLstd450Exp,
GLSLstd450Log,
GLSLstd450Exp2,
GLSLstd450Log2,
GLSLstd450Sqrt,
GLSLstd450InverseSqrt,
GLSLstd450Determinant,
GLSLstd450MatrixInverse,
GLSLstd450ModfStruct,
GLSLstd450FMin,
GLSLstd450UMin,
GLSLstd450SMin,
GLSLstd450FMax,
GLSLstd450UMax,
GLSLstd450SMax,
GLSLstd450FClamp,
GLSLstd450UClamp,
GLSLstd450SClamp,
GLSLstd450FMix,
GLSLstd450IMix,
GLSLstd450Step,
GLSLstd450SmoothStep,
GLSLstd450Fma,
GLSLstd450FrexpStruct,
GLSLstd450Ldexp,
GLSLstd450PackSnorm4x8,
GLSLstd450PackUnorm4x8,
GLSLstd450PackSnorm2x16,
GLSLstd450PackUnorm2x16,
GLSLstd450PackHalf2x16,
GLSLstd450PackDouble2x32,
GLSLstd450UnpackSnorm2x16,
GLSLstd450UnpackUnorm2x16,
GLSLstd450UnpackHalf2x16,
GLSLstd450UnpackSnorm4x8,
GLSLstd450UnpackUnorm4x8,
GLSLstd450UnpackDouble2x32,
GLSLstd450Length,
GLSLstd450Distance,
GLSLstd450Cross,
GLSLstd450Normalize,
GLSLstd450FaceForward,
GLSLstd450Reflect,
GLSLstd450Refract,
GLSLstd450FindILsb,
GLSLstd450FindSMsb,
GLSLstd450FindUMsb,
GLSLstd450InterpolateAtCentroid,
GLSLstd450InterpolateAtSample,
GLSLstd450InterpolateAtOffset,
GLSLstd450NMin,
GLSLstd450NMax,
GLSLstd450NClamp};
} else {
// Map the result id to the empty set.
combinator_ops_[extension->result_id()];
}
}
void IRContext::InitializeCombinators() {
for( auto& capability : module()->capabilities()) {
AddCombinatorsForCapability(capability.GetSingleWordInOperand(0));
}
for( auto& extension : module()->ext_inst_imports()) {
AddCombinatorsForExtension(&extension);
}
valid_analyses_ |= kAnalysisCombinators;
}
} // namespace ir
} // namespace spvtools