|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "ReduceOperands.h" | 
|  | #include "llvm/IR/Constants.h" | 
|  | #include "llvm/IR/InstIterator.h" | 
|  | #include "llvm/IR/InstrTypes.h" | 
|  | #include "llvm/IR/Operator.h" | 
|  | #include "llvm/IR/PatternMatch.h" | 
|  | #include "llvm/IR/Type.h" | 
|  |  | 
|  | using namespace llvm; | 
|  | using namespace PatternMatch; | 
|  |  | 
|  | static void | 
|  | extractOperandsFromModule(Oracle &O, ReducerWorkItem &WorkItem, | 
|  | function_ref<Value *(Use &)> ReduceValue) { | 
|  | Module &Program = WorkItem.getModule(); | 
|  |  | 
|  | for (auto &F : Program.functions()) { | 
|  | for (auto &I : instructions(&F)) { | 
|  | if (PHINode *Phi = dyn_cast<PHINode>(&I)) { | 
|  | for (auto &Op : Phi->incoming_values()) { | 
|  | if (Value *Reduced = ReduceValue(Op)) { | 
|  | if (!O.shouldKeep()) | 
|  | Phi->setIncomingValueForBlock(Phi->getIncomingBlock(Op), Reduced); | 
|  | } | 
|  | } | 
|  |  | 
|  | continue; | 
|  | } | 
|  |  | 
|  | for (auto &Op : I.operands()) { | 
|  | if (Value *Reduced = ReduceValue(Op)) { | 
|  | if (!O.shouldKeep()) | 
|  | Op.set(Reduced); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | static bool isOne(Use &Op) { | 
|  | auto *C = dyn_cast<Constant>(Op); | 
|  | return C && C->isOneValue(); | 
|  | } | 
|  |  | 
|  | static bool isZero(Use &Op) { | 
|  | auto *C = dyn_cast<Constant>(Op); | 
|  | return C && C->isNullValue(); | 
|  | } | 
|  |  | 
|  | static bool isZeroOrOneFP(Value *Op) { | 
|  | const APFloat *C; | 
|  | return match(Op, m_APFloat(C)) && | 
|  | ((C->isZero() && !C->isNegative()) || C->isExactlyValue(1.0)); | 
|  | } | 
|  |  | 
|  | static bool shouldReduceOperand(Use &Op) { | 
|  | Type *Ty = Op->getType(); | 
|  | if (Ty->isLabelTy() || Ty->isMetadataTy()) | 
|  | return false; | 
|  | // TODO: be more precise about which GEP operands we can reduce (e.g. array | 
|  | // indexes) | 
|  | if (isa<GEPOperator>(Op.getUser())) | 
|  | return false; | 
|  | if (auto *CB = dyn_cast<CallBase>(Op.getUser())) { | 
|  | if (&CB->getCalledOperandUse() == &Op) | 
|  | return false; | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | static bool switchCaseExists(Use &Op, ConstantInt *CI) { | 
|  | SwitchInst *SI = dyn_cast<SwitchInst>(Op.getUser()); | 
|  | if (!SI) | 
|  | return false; | 
|  | return SI->findCaseValue(CI) != SI->case_default(); | 
|  | } | 
|  |  | 
|  | void llvm::reduceOperandsOneDeltaPass(Oracle &O, ReducerWorkItem &WorkItem) { | 
|  | auto ReduceValue = [](Use &Op) -> Value * { | 
|  | if (!shouldReduceOperand(Op)) | 
|  | return nullptr; | 
|  |  | 
|  | Type *Ty = Op->getType(); | 
|  | if (auto *IntTy = dyn_cast<IntegerType>(Ty)) { | 
|  | // Don't duplicate an existing switch case. | 
|  | if (switchCaseExists(Op, ConstantInt::get(IntTy, 1))) | 
|  | return nullptr; | 
|  | // Don't replace existing ones and zeroes. | 
|  | return (isOne(Op) || isZero(Op)) ? nullptr : ConstantInt::get(IntTy, 1); | 
|  | } | 
|  |  | 
|  | if (Ty->isFloatingPointTy()) | 
|  | return isZeroOrOneFP(Op) ? nullptr : ConstantFP::get(Ty, 1.0); | 
|  |  | 
|  | if (VectorType *VT = dyn_cast<VectorType>(Ty)) { | 
|  | if (isOne(Op) || isZero(Op) || isZeroOrOneFP(Op)) | 
|  | return nullptr; | 
|  |  | 
|  | Type *ElementType = VT->getElementType(); | 
|  | Constant *C; | 
|  | if (ElementType->isFloatingPointTy()) { | 
|  | C = ConstantFP::get(ElementType, 1.0); | 
|  | } else if (IntegerType *IntTy = dyn_cast<IntegerType>(ElementType)) { | 
|  | C = ConstantInt::get(IntTy, 1); | 
|  | } else { | 
|  | return nullptr; | 
|  | } | 
|  | return ConstantVector::getSplat(VT->getElementCount(), C); | 
|  | } | 
|  |  | 
|  | return nullptr; | 
|  | }; | 
|  | extractOperandsFromModule(O, WorkItem, ReduceValue); | 
|  | } | 
|  |  | 
|  | void llvm::reduceOperandsZeroDeltaPass(Oracle &O, ReducerWorkItem &WorkItem) { | 
|  | auto ReduceValue = [](Use &Op) -> Value * { | 
|  | if (!shouldReduceOperand(Op)) | 
|  | return nullptr; | 
|  |  | 
|  | // Avoid introducing 0-sized allocations. | 
|  | if (isa<AllocaInst>(Op.getUser())) | 
|  | return nullptr; | 
|  |  | 
|  | // Don't duplicate an existing switch case. | 
|  | if (auto *IntTy = dyn_cast<IntegerType>(Op->getType())) | 
|  | if (switchCaseExists(Op, ConstantInt::get(IntTy, 0))) | 
|  | return nullptr; | 
|  |  | 
|  | if (auto *TET = dyn_cast<TargetExtType>(Op->getType())) { | 
|  | if (isa<ConstantTargetNone, PoisonValue>(Op)) | 
|  | return nullptr; | 
|  | if (TET->hasProperty(TargetExtType::HasZeroInit)) | 
|  | return ConstantTargetNone::get(TET); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | // Don't replace existing zeroes. | 
|  | return isZero(Op) ? nullptr : Constant::getNullValue(Op->getType()); | 
|  | }; | 
|  | extractOperandsFromModule(O, WorkItem, ReduceValue); | 
|  | } | 
|  |  | 
|  | void llvm::reduceOperandsNaNDeltaPass(Oracle &O, ReducerWorkItem &WorkItem) { | 
|  | auto ReduceValue = [](Use &Op) -> Value * { | 
|  | Type *Ty = Op->getType(); | 
|  | if (!Ty->isFPOrFPVectorTy()) | 
|  | return nullptr; | 
|  |  | 
|  | // Prefer 0.0 or 1.0 over NaN. | 
|  | // | 
|  | // TODO: Preferring NaN may make more sense because FP operations are more | 
|  | // universally foldable. | 
|  | if (match(Op.get(), m_NaN()) || isZeroOrOneFP(Op.get())) | 
|  | return nullptr; | 
|  |  | 
|  | if (VectorType *VT = dyn_cast<VectorType>(Ty)) { | 
|  | return ConstantVector::getSplat(VT->getElementCount(), | 
|  | ConstantFP::getQNaN(VT->getElementType())); | 
|  | } | 
|  |  | 
|  | return ConstantFP::getQNaN(Ty); | 
|  | }; | 
|  | extractOperandsFromModule(O, WorkItem, ReduceValue); | 
|  | } | 
|  |  | 
|  | void llvm::reduceOperandsPoisonDeltaPass(Oracle &O, ReducerWorkItem &WorkItem) { | 
|  | auto ReduceValue = [](Use &Op) -> Value * { | 
|  | Type *Ty = Op->getType(); | 
|  | if (auto *TET = dyn_cast<TargetExtType>(Ty)) { | 
|  | if (isa<ConstantTargetNone, PoisonValue>(Op)) | 
|  | return nullptr; | 
|  | return PoisonValue::get(TET); | 
|  | } | 
|  |  | 
|  | return nullptr; | 
|  | }; | 
|  |  | 
|  | extractOperandsFromModule(O, WorkItem, ReduceValue); | 
|  | } |