| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250 |
- //===--- RelaxedPrecisionVisitor.cpp - RelaxedPrecision Visitor --*- C++ -*-==//
- //
- // The LLVM Compiler Infrastructure
- //
- // This file is distributed under the University of Illinois Open Source
- // License. See LICENSE.TXT for details.
- //
- //===----------------------------------------------------------------------===//
- #include "RelaxedPrecisionVisitor.h"
- #include "clang/SPIRV/AstTypeProbe.h"
- #include "clang/SPIRV/SpirvBuilder.h"
- namespace clang {
- namespace spirv {
- bool RelaxedPrecisionVisitor::visit(SpirvFunction *fn, Phase phase) {
- assert(fn);
- if (phase == Visitor::Phase::Init)
- if (isRelaxedPrecisionType(fn->getAstReturnType(), spvOptions))
- fn->setRelaxedPrecision();
- return true;
- }
- bool RelaxedPrecisionVisitor::visit(SpirvVectorShuffle *inst) {
- // The result of vector shuffle must have RelaxedPrecision if the chosen
- // elements come from a vector that is RelaxedPrecision.
- auto *vec1 = inst->getVec1();
- auto *vec2 = inst->getVec2();
- const auto vec1Type = vec1->getAstResultType();
- const auto vec2Type = vec2->getAstResultType();
- const bool isVec1Relaxed = isRelaxedPrecisionType(vec1Type, spvOptions);
- const bool isVec2Relaxed = isRelaxedPrecisionType(vec2Type, spvOptions);
- uint32_t vec1Size;
- uint32_t vec2Size;
- (void)isVectorType(vec1Type, nullptr, &vec1Size);
- (void)isVectorType(vec2Type, nullptr, &vec2Size);
- bool vec1ElemUsed = false;
- bool vec2ElemUsed = false;
- for (auto component : inst->getComponents()) {
- if (component < vec1Size)
- vec1ElemUsed = true;
- else
- vec2ElemUsed = true;
- }
- const bool onlyVec1Used = vec1ElemUsed && !vec2ElemUsed;
- const bool onlyVec2Used = vec2ElemUsed && !vec1ElemUsed;
- if ((onlyVec1Used && isVec1Relaxed) || (onlyVec2Used && isVec2Relaxed) ||
- (vec1ElemUsed && vec2ElemUsed && isVec1Relaxed && isVec2Relaxed))
- inst->setRelaxedPrecision();
- return true;
- }
- bool RelaxedPrecisionVisitor::visit(SpirvUnaryOp *inst) {
- // For conversion operations, check the result QualType. For example: if we
- // are converting from min12int to int, the result should no longet get
- // RelaxedPrecision.
- switch (inst->getopcode()) {
- case spv::Op::OpBitcast:
- case spv::Op::OpFConvert:
- case spv::Op::OpSConvert:
- case spv::Op::OpUConvert: {
- if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions)) {
- inst->setRelaxedPrecision();
- }
- return true;
- }
- default:
- break;
- }
- // If the argument of the unary operation is RelaxedPrecision, the result is
- // also RelaxedPrecision.
- if (inst->getOperand()->isRelaxedPrecision())
- inst->setRelaxedPrecision();
- return true;
- }
- bool RelaxedPrecisionVisitor::visit(SpirvBinaryOp *inst) {
- // If either argument of the binary operation is RelaxedPrecision, the result
- // is also RelaxedPrecision.
- if (inst->getOperand1()->isRelaxedPrecision() &&
- inst->getOperand2()->isRelaxedPrecision())
- inst->setRelaxedPrecision();
- return true;
- }
- bool RelaxedPrecisionVisitor::visit(SpirvSpecConstantUnaryOp *inst) {
- // If the argument of the unary operation is RelaxedPrecision, the result is
- // also RelaxedPrecision.
- if (inst->getOperand()->isRelaxedPrecision())
- inst->setRelaxedPrecision();
- return true;
- }
- bool RelaxedPrecisionVisitor::visit(SpirvSpecConstantBinaryOp *inst) {
- // If either argument of the binary operation is RelaxedPrecision, the result
- // is also RelaxedPrecision.
- if (inst->getOperand1()->isRelaxedPrecision() &&
- inst->getOperand2()->isRelaxedPrecision())
- inst->setRelaxedPrecision();
- return true;
- }
- bool RelaxedPrecisionVisitor::visit(SpirvLoad *inst) {
- // If loading from a RelaxedPrecision variable, the result is also decorated
- // with RelaxedPrecision.
- if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions))
- inst->setRelaxedPrecision();
- return true;
- }
- bool RelaxedPrecisionVisitor::visit(SpirvStore *inst) { return true; }
- bool RelaxedPrecisionVisitor::visit(SpirvSelect *inst) {
- if (inst->getTrueObject()->isRelaxedPrecision() &&
- inst->getFalseObject()->isRelaxedPrecision())
- inst->setRelaxedPrecision();
- return true;
- }
- bool RelaxedPrecisionVisitor::visit(SpirvFunctionCall *inst) {
- // If the return type of the function is RelaxedPrecision, we can decorate the
- // result-id of the OpFunctionCall.
- if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions))
- inst->setRelaxedPrecision();
- return true;
- }
- bool RelaxedPrecisionVisitor::visit(SpirvExtInst *inst) {
- // If all operands to numeric instructions in GLSL extended instruction set is
- // RelaxedPrecision, the result of the opration is also RelaxedPrecision.
- if (inst->getInstructionSet()->getExtendedInstSetName() == "GLSL.std.450") {
- const auto &operands = inst->getOperands();
- if (std::all_of(operands.begin(), operands.end(), [](SpirvInstruction *op) {
- return op->isRelaxedPrecision();
- })) {
- inst->setRelaxedPrecision();
- }
- }
- return true;
- }
- bool RelaxedPrecisionVisitor::visit(SpirvCompositeInsert *inst) {
- // If inserting a RelaxedPrecision object into a composite, check the type of
- // the resulting composite. For example: if you are inserting a
- // RelaxedPrecision object as a member into a structure, the resulting
- // structure type is not RelaxedPrecision. But, if you are inserting a
- // RelaxedPrecision object into a vector of RelaxedPrecision integers, the
- // resulting composite *is* RelaxedPrecision.
- // In short, it simply depends on the composite type.
- if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions))
- inst->setRelaxedPrecision();
- return true;
- }
- bool RelaxedPrecisionVisitor::visit(SpirvCompositeExtract *inst) {
- // If extracting a RelaxedPrecision object from a composite, check the type of
- // the extracted object. For example: if extracting different members of a
- // structure, depending on the member, you may or may not want to apply the
- // RelaxedPrecision decoration.
- // In short, it simply depends on the type of what you have extracted.
- if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions))
- inst->setRelaxedPrecision();
- return true;
- }
- bool RelaxedPrecisionVisitor::visit(SpirvCompositeConstruct *inst) {
- // When constructing a composite, only look at the type of the resulting
- // composite.
- if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions))
- inst->setRelaxedPrecision();
- return true;
- }
- bool RelaxedPrecisionVisitor::visit(SpirvConstantBoolean *) {
- // Booleans do not have precision!
- return true;
- }
- bool RelaxedPrecisionVisitor::visit(SpirvConstantInteger *inst) {
- if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions))
- inst->setRelaxedPrecision();
- return true;
- }
- bool RelaxedPrecisionVisitor::visit(SpirvConstantFloat *inst) {
- if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions))
- inst->setRelaxedPrecision();
- return true;
- }
- bool RelaxedPrecisionVisitor::visit(SpirvConstantComposite *inst) {
- if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions))
- inst->setRelaxedPrecision();
- return true;
- }
- bool RelaxedPrecisionVisitor::visit(SpirvBitFieldExtract *inst) {
- if (inst->getBase()->isRelaxedPrecision())
- inst->setRelaxedPrecision();
- return true;
- }
- bool RelaxedPrecisionVisitor::visit(SpirvBitFieldInsert *inst) {
- if (inst->getBase()->isRelaxedPrecision())
- inst->setRelaxedPrecision();
- return true;
- }
- bool RelaxedPrecisionVisitor::visit(SpirvAtomic *inst) {
- // If the original pointer is RelaxedPrecision or operating on a value that is
- // RelaxedPrecision, result is RelaxedPrecision.
- if (inst->getPointer()->isRelaxedPrecision()) {
- if (!inst->hasValue() ||
- (inst->hasValue() && inst->getValue()->isRelaxedPrecision()))
- inst->setRelaxedPrecision();
- }
- return true;
- }
- bool RelaxedPrecisionVisitor::visit(SpirvAccessChain *) {
- // The access chain operation itself is irrelevant regarding precision.
- return true;
- }
- bool RelaxedPrecisionVisitor::visit(SpirvFunctionParameter *inst) {
- if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions))
- inst->setRelaxedPrecision();
- return true;
- }
- bool RelaxedPrecisionVisitor::visit(SpirvVariable *inst) {
- if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions))
- inst->setRelaxedPrecision();
- return true;
- }
- bool RelaxedPrecisionVisitor::visit(SpirvImageOp *inst) {
- // If the operation result type or the underlying image type is relaxed
- // precision, the instruction can be considered relaxed precision.
- if (isRelaxedPrecisionType(inst->getAstResultType(), spvOptions) ||
- isRelaxedPrecisionType(inst->getImage()->getAstResultType(), spvOptions))
- inst->setRelaxedPrecision();
- return true;
- }
- } // end namespace spirv
- } // namespace clang
|