//===----------------------------------------------------------------------===// // // 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 ReduceValue) { Module &Program = WorkItem.getModule(); for (auto &F : Program.functions()) { for (auto &I : instructions(&F)) { if (PHINode *Phi = dyn_cast(&I)) { for (auto &Op : Phi->incoming_values()) { if (!O.shouldKeep()) { if (Value *Reduced = ReduceValue(Op)) 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(Op); return C && C->isOneValue(); } static bool isZero(Use &Op) { auto *C = dyn_cast(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(Op.getUser())) return false; if (auto *CB = dyn_cast(Op.getUser())) { if (&CB->getCalledOperandUse() == &Op) return false; } return true; } static bool switchCaseExists(Use &Op, ConstantInt *CI) { SwitchInst *SI = dyn_cast(Op.getUser()); if (!SI) return false; return SI->findCaseValue(CI) != SI->case_default(); } void llvm::reduceOperandsOneDeltaPass(TestRunner &Test) { auto ReduceValue = [](Use &Op) -> Value * { if (!shouldReduceOperand(Op)) return nullptr; Type *Ty = Op->getType(); if (auto *IntTy = dyn_cast(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(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(ElementType)) { C = ConstantInt::get(IntTy, 1); } else { return nullptr; } return ConstantVector::getSplat(VT->getElementCount(), C); } return nullptr; }; runDeltaPass( Test, [ReduceValue](Oracle &O, ReducerWorkItem &WorkItem) { extractOperandsFromModule(O, WorkItem, ReduceValue); }, "Reducing Operands to one"); } void llvm::reduceOperandsZeroDeltaPass(TestRunner &Test) { auto ReduceValue = [](Use &Op) -> Value * { if (!shouldReduceOperand(Op)) return nullptr; // Don't duplicate an existing switch case. if (auto *IntTy = dyn_cast(Op->getType())) if (switchCaseExists(Op, ConstantInt::get(IntTy, 0))) return nullptr; // Don't replace existing zeroes. return isZero(Op) ? nullptr : Constant::getNullValue(Op->getType()); }; runDeltaPass( Test, [ReduceValue](Oracle &O, ReducerWorkItem &Program) { extractOperandsFromModule(O, Program, ReduceValue); }, "Reducing Operands to zero"); } void llvm::reduceOperandsNaNDeltaPass(TestRunner &Test) { 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(Ty)) { return ConstantVector::getSplat(VT->getElementCount(), ConstantFP::getQNaN(VT->getElementType())); } return ConstantFP::getQNaN(Ty); }; runDeltaPass( Test, [ReduceValue](Oracle &O, ReducerWorkItem &Program) { extractOperandsFromModule(O, Program, ReduceValue); }, "Reducing Operands to NaN"); }