1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
|
/*========================== begin_copyright_notice ============================
Copyright (C) 2022-2023 Intel Corporation
SPDX-License-Identifier: MIT
============================= end_copyright_notice ===========================*/
#include "AdaptorCommon/FreezeIntDiv.hpp"
#include "Compiler/IGCPassSupport.h"
#include "common/LLVMWarningsPush.hpp"
#include "llvm/IR/InstVisitor.h"
#include "llvm/IR/IRBuilder.h"
#include "common/LLVMWarningsPop.hpp"
using namespace llvm;
namespace IGC {
class FreezeIntDiv : public FunctionPass, public InstVisitor<FreezeIntDiv> {
public:
static char ID;
FreezeIntDiv() : FunctionPass(ID), changed(false) { initializeFreezeIntDivPass(*PassRegistry::getPassRegistry()); }
bool runOnFunction(Function &F) override;
StringRef getPassName() const override { return "FreezeIntDiv"; }
void getAnalysisUsage(AnalysisUsage &AU) const override { AU.setPreservesCFG(); }
void visitBinaryOperator(BinaryOperator &I);
void freezeIntDiv(BinaryOperator &I);
private:
bool changed;
};
char FreezeIntDiv::ID = 0;
#define PASS_FLAG "igc-freeze-int-div-pass"
#define PASS_DESCRIPTION "Freeze integer division"
#define PASS_CFG_ONLY false
#define PASS_ANALYSIS false
IGC_INITIALIZE_PASS_BEGIN(FreezeIntDiv, PASS_FLAG, PASS_DESCRIPTION, PASS_CFG_ONLY, PASS_ANALYSIS)
IGC_INITIALIZE_PASS_END(FreezeIntDiv, PASS_FLAG, PASS_DESCRIPTION, PASS_CFG_ONLY, PASS_ANALYSIS)
FunctionPass *createFreezeIntDivPass() { return new FreezeIntDiv(); }
////////////////////////////////////////////////////////////////////////////
bool FreezeIntDiv::runOnFunction(Function &F) {
changed = false;
visit(F);
return changed;
}
void FreezeIntDiv::freezeIntDiv(BinaryOperator &I) {
llvm::IRBuilder<> builder(I.getNextNode());
Value *FI = builder.CreateFreeze(&I, "freeze");
I.replaceAllUsesWith(FI);
cast<Instruction>(FI)->setOperand(0, &I);
}
void FreezeIntDiv::visitBinaryOperator(BinaryOperator &I) {
switch (I.getOpcode()) {
case Instruction::UDiv:
case Instruction::SDiv:
case Instruction::URem:
case Instruction::SRem:
// Stop propagation of poison values generated by LLVM in case of
// integer division by zero. Use LLVM 10+ freeze instruction.
{
// In theory, we shouldn't have to check whether the input is, in
// fact, poison/undef - the resulting freeze should simply resolve
// to a no-op otherwise. However, until we resolve all freeze insts
// in codegen, LLVM passes (InstCombine, GVN, SimplifyCFG, etc.)
// can be sloppy with checking the operand's validity - as a
// result, valuable optimizations can be skipped in some cases.
// Therefore, minimize freeze emission for cases that are
// guaranteed to be valid.
auto *constDivisor = dyn_cast<ConstantInt>(I.getOperand(1));
if (constDivisor && !constDivisor->isZero())
break;
freezeIntDiv(I);
changed = true;
break;
}
default:
break;
}
}
} // namespace IGC
|