10b57cec5SDimitry Andric //===- HexagonGenExtract.cpp ----------------------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric
90b57cec5SDimitry Andric #include "llvm/ADT/APInt.h"
100b57cec5SDimitry Andric #include "llvm/ADT/GraphTraits.h"
110b57cec5SDimitry Andric #include "llvm/IR/BasicBlock.h"
120b57cec5SDimitry Andric #include "llvm/IR/CFG.h"
130b57cec5SDimitry Andric #include "llvm/IR/Constants.h"
140b57cec5SDimitry Andric #include "llvm/IR/Dominators.h"
150b57cec5SDimitry Andric #include "llvm/IR/Function.h"
160b57cec5SDimitry Andric #include "llvm/IR/IRBuilder.h"
170b57cec5SDimitry Andric #include "llvm/IR/Instruction.h"
180b57cec5SDimitry Andric #include "llvm/IR/Instructions.h"
190b57cec5SDimitry Andric #include "llvm/IR/Intrinsics.h"
20480093f4SDimitry Andric #include "llvm/IR/IntrinsicsHexagon.h"
210b57cec5SDimitry Andric #include "llvm/IR/PatternMatch.h"
220b57cec5SDimitry Andric #include "llvm/IR/Type.h"
230b57cec5SDimitry Andric #include "llvm/IR/Value.h"
24480093f4SDimitry Andric #include "llvm/InitializePasses.h"
250b57cec5SDimitry Andric #include "llvm/Pass.h"
260b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
270b57cec5SDimitry Andric #include <algorithm>
280b57cec5SDimitry Andric #include <cstdint>
290b57cec5SDimitry Andric #include <iterator>
300b57cec5SDimitry Andric
310b57cec5SDimitry Andric using namespace llvm;
320b57cec5SDimitry Andric
330b57cec5SDimitry Andric static cl::opt<unsigned> ExtractCutoff("extract-cutoff", cl::init(~0U),
340b57cec5SDimitry Andric cl::Hidden, cl::desc("Cutoff for generating \"extract\""
350b57cec5SDimitry Andric " instructions"));
360b57cec5SDimitry Andric
370b57cec5SDimitry Andric // This prevents generating extract instructions that have the offset of 0.
380b57cec5SDimitry Andric // One of the reasons for "extract" is to put a sequence of bits in a regis-
390b57cec5SDimitry Andric // ter, starting at offset 0 (so that these bits can then be used by an
400b57cec5SDimitry Andric // "insert"). If the bits are already at offset 0, it is better not to gene-
410b57cec5SDimitry Andric // rate "extract", since logical bit operations can be merged into compound
420b57cec5SDimitry Andric // instructions (as opposed to "extract").
430b57cec5SDimitry Andric static cl::opt<bool> NoSR0("extract-nosr0", cl::init(true), cl::Hidden,
440b57cec5SDimitry Andric cl::desc("No extract instruction with offset 0"));
450b57cec5SDimitry Andric
460b57cec5SDimitry Andric static cl::opt<bool> NeedAnd("extract-needand", cl::init(true), cl::Hidden,
470b57cec5SDimitry Andric cl::desc("Require & in extract patterns"));
480b57cec5SDimitry Andric
490b57cec5SDimitry Andric namespace llvm {
500b57cec5SDimitry Andric
510b57cec5SDimitry Andric void initializeHexagonGenExtractPass(PassRegistry&);
520b57cec5SDimitry Andric FunctionPass *createHexagonGenExtract();
530b57cec5SDimitry Andric
540b57cec5SDimitry Andric } // end namespace llvm
550b57cec5SDimitry Andric
560b57cec5SDimitry Andric namespace {
570b57cec5SDimitry Andric
580b57cec5SDimitry Andric class HexagonGenExtract : public FunctionPass {
590b57cec5SDimitry Andric public:
600b57cec5SDimitry Andric static char ID;
610b57cec5SDimitry Andric
HexagonGenExtract()620b57cec5SDimitry Andric HexagonGenExtract() : FunctionPass(ID) {
630b57cec5SDimitry Andric initializeHexagonGenExtractPass(*PassRegistry::getPassRegistry());
640b57cec5SDimitry Andric }
650b57cec5SDimitry Andric
getPassName() const660b57cec5SDimitry Andric StringRef getPassName() const override {
670b57cec5SDimitry Andric return "Hexagon generate \"extract\" instructions";
680b57cec5SDimitry Andric }
690b57cec5SDimitry Andric
700b57cec5SDimitry Andric bool runOnFunction(Function &F) override;
710b57cec5SDimitry Andric
getAnalysisUsage(AnalysisUsage & AU) const720b57cec5SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override {
730b57cec5SDimitry Andric AU.addRequired<DominatorTreeWrapperPass>();
740b57cec5SDimitry Andric AU.addPreserved<DominatorTreeWrapperPass>();
750b57cec5SDimitry Andric FunctionPass::getAnalysisUsage(AU);
760b57cec5SDimitry Andric }
770b57cec5SDimitry Andric
780b57cec5SDimitry Andric private:
790b57cec5SDimitry Andric bool visitBlock(BasicBlock *B);
800b57cec5SDimitry Andric bool convert(Instruction *In);
810b57cec5SDimitry Andric
820b57cec5SDimitry Andric unsigned ExtractCount = 0;
830b57cec5SDimitry Andric DominatorTree *DT;
840b57cec5SDimitry Andric };
850b57cec5SDimitry Andric
860b57cec5SDimitry Andric } // end anonymous namespace
870b57cec5SDimitry Andric
880b57cec5SDimitry Andric char HexagonGenExtract::ID = 0;
890b57cec5SDimitry Andric
900b57cec5SDimitry Andric INITIALIZE_PASS_BEGIN(HexagonGenExtract, "hextract", "Hexagon generate "
910b57cec5SDimitry Andric "\"extract\" instructions", false, false)
INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)920b57cec5SDimitry Andric INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)
930b57cec5SDimitry Andric INITIALIZE_PASS_END(HexagonGenExtract, "hextract", "Hexagon generate "
940b57cec5SDimitry Andric "\"extract\" instructions", false, false)
950b57cec5SDimitry Andric
960b57cec5SDimitry Andric bool HexagonGenExtract::convert(Instruction *In) {
970b57cec5SDimitry Andric using namespace PatternMatch;
980b57cec5SDimitry Andric
990b57cec5SDimitry Andric Value *BF = nullptr;
1000b57cec5SDimitry Andric ConstantInt *CSL = nullptr, *CSR = nullptr, *CM = nullptr;
1010b57cec5SDimitry Andric BasicBlock *BB = In->getParent();
1020b57cec5SDimitry Andric LLVMContext &Ctx = BB->getContext();
1030b57cec5SDimitry Andric bool LogicalSR;
1040b57cec5SDimitry Andric
1050b57cec5SDimitry Andric // (and (shl (lshr x, #sr), #sl), #m)
1060b57cec5SDimitry Andric LogicalSR = true;
1070b57cec5SDimitry Andric bool Match = match(In, m_And(m_Shl(m_LShr(m_Value(BF), m_ConstantInt(CSR)),
1080b57cec5SDimitry Andric m_ConstantInt(CSL)),
1090b57cec5SDimitry Andric m_ConstantInt(CM)));
1100b57cec5SDimitry Andric
1110b57cec5SDimitry Andric if (!Match) {
1120b57cec5SDimitry Andric // (and (shl (ashr x, #sr), #sl), #m)
1130b57cec5SDimitry Andric LogicalSR = false;
1140b57cec5SDimitry Andric Match = match(In, m_And(m_Shl(m_AShr(m_Value(BF), m_ConstantInt(CSR)),
1150b57cec5SDimitry Andric m_ConstantInt(CSL)),
1160b57cec5SDimitry Andric m_ConstantInt(CM)));
1170b57cec5SDimitry Andric }
1180b57cec5SDimitry Andric if (!Match) {
1190b57cec5SDimitry Andric // (and (shl x, #sl), #m)
1200b57cec5SDimitry Andric LogicalSR = true;
1210b57cec5SDimitry Andric CSR = ConstantInt::get(Type::getInt32Ty(Ctx), 0);
1220b57cec5SDimitry Andric Match = match(In, m_And(m_Shl(m_Value(BF), m_ConstantInt(CSL)),
1230b57cec5SDimitry Andric m_ConstantInt(CM)));
1240b57cec5SDimitry Andric if (Match && NoSR0)
1250b57cec5SDimitry Andric return false;
1260b57cec5SDimitry Andric }
1270b57cec5SDimitry Andric if (!Match) {
1280b57cec5SDimitry Andric // (and (lshr x, #sr), #m)
1290b57cec5SDimitry Andric LogicalSR = true;
1300b57cec5SDimitry Andric CSL = ConstantInt::get(Type::getInt32Ty(Ctx), 0);
1310b57cec5SDimitry Andric Match = match(In, m_And(m_LShr(m_Value(BF), m_ConstantInt(CSR)),
1320b57cec5SDimitry Andric m_ConstantInt(CM)));
1330b57cec5SDimitry Andric }
1340b57cec5SDimitry Andric if (!Match) {
1350b57cec5SDimitry Andric // (and (ashr x, #sr), #m)
1360b57cec5SDimitry Andric LogicalSR = false;
1370b57cec5SDimitry Andric CSL = ConstantInt::get(Type::getInt32Ty(Ctx), 0);
1380b57cec5SDimitry Andric Match = match(In, m_And(m_AShr(m_Value(BF), m_ConstantInt(CSR)),
1390b57cec5SDimitry Andric m_ConstantInt(CM)));
1400b57cec5SDimitry Andric }
1410b57cec5SDimitry Andric if (!Match) {
1420b57cec5SDimitry Andric CM = nullptr;
1430b57cec5SDimitry Andric // (shl (lshr x, #sr), #sl)
1440b57cec5SDimitry Andric LogicalSR = true;
1450b57cec5SDimitry Andric Match = match(In, m_Shl(m_LShr(m_Value(BF), m_ConstantInt(CSR)),
1460b57cec5SDimitry Andric m_ConstantInt(CSL)));
1470b57cec5SDimitry Andric }
1480b57cec5SDimitry Andric if (!Match) {
1490b57cec5SDimitry Andric CM = nullptr;
1500b57cec5SDimitry Andric // (shl (ashr x, #sr), #sl)
1510b57cec5SDimitry Andric LogicalSR = false;
1520b57cec5SDimitry Andric Match = match(In, m_Shl(m_AShr(m_Value(BF), m_ConstantInt(CSR)),
1530b57cec5SDimitry Andric m_ConstantInt(CSL)));
1540b57cec5SDimitry Andric }
1550b57cec5SDimitry Andric if (!Match)
1560b57cec5SDimitry Andric return false;
1570b57cec5SDimitry Andric
1580b57cec5SDimitry Andric Type *Ty = BF->getType();
1590b57cec5SDimitry Andric if (!Ty->isIntegerTy())
1600b57cec5SDimitry Andric return false;
1610b57cec5SDimitry Andric unsigned BW = Ty->getPrimitiveSizeInBits();
1620b57cec5SDimitry Andric if (BW != 32 && BW != 64)
1630b57cec5SDimitry Andric return false;
1640b57cec5SDimitry Andric
1650b57cec5SDimitry Andric uint32_t SR = CSR->getZExtValue();
1660b57cec5SDimitry Andric uint32_t SL = CSL->getZExtValue();
1670b57cec5SDimitry Andric
1680b57cec5SDimitry Andric if (!CM) {
1690b57cec5SDimitry Andric // If there was no and, and the shift left did not remove all potential
1700b57cec5SDimitry Andric // sign bits created by the shift right, then extractu cannot reproduce
1710b57cec5SDimitry Andric // this value.
1720b57cec5SDimitry Andric if (!LogicalSR && (SR > SL))
1730b57cec5SDimitry Andric return false;
1740b57cec5SDimitry Andric APInt A = APInt(BW, ~0ULL).lshr(SR).shl(SL);
1750b57cec5SDimitry Andric CM = ConstantInt::get(Ctx, A);
1760b57cec5SDimitry Andric }
1770b57cec5SDimitry Andric
1780b57cec5SDimitry Andric // CM is the shifted-left mask. Shift it back right to remove the zero
1790b57cec5SDimitry Andric // bits on least-significant positions.
1800b57cec5SDimitry Andric APInt M = CM->getValue().lshr(SL);
181*06c3fb27SDimitry Andric uint32_t T = M.countr_one();
1820b57cec5SDimitry Andric
1830b57cec5SDimitry Andric // During the shifts some of the bits will be lost. Calculate how many
1840b57cec5SDimitry Andric // of the original value will remain after shift right and then left.
1850b57cec5SDimitry Andric uint32_t U = BW - std::max(SL, SR);
1860b57cec5SDimitry Andric // The width of the extracted field is the minimum of the original bits
1870b57cec5SDimitry Andric // that remain after the shifts and the number of contiguous 1s in the mask.
1880b57cec5SDimitry Andric uint32_t W = std::min(U, T);
1898bcb0991SDimitry Andric if (W == 0 || W == 1)
1900b57cec5SDimitry Andric return false;
1910b57cec5SDimitry Andric
1920b57cec5SDimitry Andric // Check if the extracted bits are contained within the mask that it is
1930b57cec5SDimitry Andric // and-ed with. The extract operation will copy these bits, and so the
1940b57cec5SDimitry Andric // mask cannot any holes in it that would clear any of the bits of the
1950b57cec5SDimitry Andric // extracted field.
1960b57cec5SDimitry Andric if (!LogicalSR) {
1970b57cec5SDimitry Andric // If the shift right was arithmetic, it could have included some 1 bits.
1980b57cec5SDimitry Andric // It is still ok to generate extract, but only if the mask eliminates
1990b57cec5SDimitry Andric // those bits (i.e. M does not have any bits set beyond U).
2000b57cec5SDimitry Andric APInt C = APInt::getHighBitsSet(BW, BW-U);
2010b57cec5SDimitry Andric if (M.intersects(C) || !M.isMask(W))
2020b57cec5SDimitry Andric return false;
2030b57cec5SDimitry Andric } else {
2040b57cec5SDimitry Andric // Check if M starts with a contiguous sequence of W times 1 bits. Get
2050b57cec5SDimitry Andric // the low U bits of M (which eliminates the 0 bits shifted in on the
2060b57cec5SDimitry Andric // left), and check if the result is APInt's "mask":
2070b57cec5SDimitry Andric if (!M.getLoBits(U).isMask(W))
2080b57cec5SDimitry Andric return false;
2090b57cec5SDimitry Andric }
2100b57cec5SDimitry Andric
2110b57cec5SDimitry Andric IRBuilder<> IRB(In);
2120b57cec5SDimitry Andric Intrinsic::ID IntId = (BW == 32) ? Intrinsic::hexagon_S2_extractu
2130b57cec5SDimitry Andric : Intrinsic::hexagon_S2_extractup;
2140b57cec5SDimitry Andric Module *Mod = BB->getParent()->getParent();
2150b57cec5SDimitry Andric Function *ExtF = Intrinsic::getDeclaration(Mod, IntId);
2160b57cec5SDimitry Andric Value *NewIn = IRB.CreateCall(ExtF, {BF, IRB.getInt32(W), IRB.getInt32(SR)});
2170b57cec5SDimitry Andric if (SL != 0)
2180b57cec5SDimitry Andric NewIn = IRB.CreateShl(NewIn, SL, CSL->getName());
2190b57cec5SDimitry Andric In->replaceAllUsesWith(NewIn);
2200b57cec5SDimitry Andric return true;
2210b57cec5SDimitry Andric }
2220b57cec5SDimitry Andric
visitBlock(BasicBlock * B)2230b57cec5SDimitry Andric bool HexagonGenExtract::visitBlock(BasicBlock *B) {
2245ffd83dbSDimitry Andric bool Changed = false;
2255ffd83dbSDimitry Andric
2260b57cec5SDimitry Andric // Depth-first, bottom-up traversal.
2270b57cec5SDimitry Andric for (auto *DTN : children<DomTreeNode*>(DT->getNode(B)))
2285ffd83dbSDimitry Andric Changed |= visitBlock(DTN->getBlock());
2290b57cec5SDimitry Andric
2300b57cec5SDimitry Andric // Allow limiting the number of generated extracts for debugging purposes.
2310b57cec5SDimitry Andric bool HasCutoff = ExtractCutoff.getPosition();
2320b57cec5SDimitry Andric unsigned Cutoff = ExtractCutoff;
2330b57cec5SDimitry Andric
2340b57cec5SDimitry Andric BasicBlock::iterator I = std::prev(B->end()), NextI, Begin = B->begin();
2350b57cec5SDimitry Andric while (true) {
2360b57cec5SDimitry Andric if (HasCutoff && (ExtractCount >= Cutoff))
2370b57cec5SDimitry Andric return Changed;
2380b57cec5SDimitry Andric bool Last = (I == Begin);
2390b57cec5SDimitry Andric if (!Last)
2400b57cec5SDimitry Andric NextI = std::prev(I);
2410b57cec5SDimitry Andric Instruction *In = &*I;
2420b57cec5SDimitry Andric bool Done = convert(In);
2430b57cec5SDimitry Andric if (HasCutoff && Done)
2440b57cec5SDimitry Andric ExtractCount++;
2450b57cec5SDimitry Andric Changed |= Done;
2460b57cec5SDimitry Andric if (Last)
2470b57cec5SDimitry Andric break;
2480b57cec5SDimitry Andric I = NextI;
2490b57cec5SDimitry Andric }
2500b57cec5SDimitry Andric return Changed;
2510b57cec5SDimitry Andric }
2520b57cec5SDimitry Andric
runOnFunction(Function & F)2530b57cec5SDimitry Andric bool HexagonGenExtract::runOnFunction(Function &F) {
2540b57cec5SDimitry Andric if (skipFunction(F))
2550b57cec5SDimitry Andric return false;
2560b57cec5SDimitry Andric
2570b57cec5SDimitry Andric DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();
2580b57cec5SDimitry Andric bool Changed;
2590b57cec5SDimitry Andric
2600b57cec5SDimitry Andric // Traverse the function bottom-up, to see super-expressions before their
2610b57cec5SDimitry Andric // sub-expressions.
2620b57cec5SDimitry Andric BasicBlock *Entry = GraphTraits<Function*>::getEntryNode(&F);
2630b57cec5SDimitry Andric Changed = visitBlock(Entry);
2640b57cec5SDimitry Andric
2650b57cec5SDimitry Andric return Changed;
2660b57cec5SDimitry Andric }
2670b57cec5SDimitry Andric
createHexagonGenExtract()2680b57cec5SDimitry Andric FunctionPass *llvm::createHexagonGenExtract() {
2690b57cec5SDimitry Andric return new HexagonGenExtract();
2700b57cec5SDimitry Andric }
271