Path: blob/main/contrib/llvm-project/llvm/lib/Target/Hexagon/HexagonGenExtract.cpp
35266 views
//===- HexagonGenExtract.cpp ----------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "llvm/ADT/APInt.h"9#include "llvm/ADT/GraphTraits.h"10#include "llvm/IR/BasicBlock.h"11#include "llvm/IR/CFG.h"12#include "llvm/IR/Constants.h"13#include "llvm/IR/Dominators.h"14#include "llvm/IR/Function.h"15#include "llvm/IR/IRBuilder.h"16#include "llvm/IR/Instruction.h"17#include "llvm/IR/Instructions.h"18#include "llvm/IR/Intrinsics.h"19#include "llvm/IR/IntrinsicsHexagon.h"20#include "llvm/IR/PatternMatch.h"21#include "llvm/IR/Type.h"22#include "llvm/IR/Value.h"23#include "llvm/InitializePasses.h"24#include "llvm/Pass.h"25#include "llvm/Support/CommandLine.h"26#include <algorithm>27#include <cstdint>28#include <iterator>2930using namespace llvm;3132static cl::opt<unsigned> ExtractCutoff("extract-cutoff", cl::init(~0U),33cl::Hidden, cl::desc("Cutoff for generating \"extract\""34" instructions"));3536// This prevents generating extract instructions that have the offset of 0.37// One of the reasons for "extract" is to put a sequence of bits in a regis-38// ter, starting at offset 0 (so that these bits can then be used by an39// "insert"). If the bits are already at offset 0, it is better not to gene-40// rate "extract", since logical bit operations can be merged into compound41// instructions (as opposed to "extract").42static cl::opt<bool> NoSR0("extract-nosr0", cl::init(true), cl::Hidden,43cl::desc("No extract instruction with offset 0"));4445static cl::opt<bool> NeedAnd("extract-needand", cl::init(true), cl::Hidden,46cl::desc("Require & in extract patterns"));4748namespace llvm {4950void initializeHexagonGenExtractPass(PassRegistry&);51FunctionPass *createHexagonGenExtract();5253} // end namespace llvm5455namespace {5657class HexagonGenExtract : public FunctionPass {58public:59static char ID;6061HexagonGenExtract() : FunctionPass(ID) {62initializeHexagonGenExtractPass(*PassRegistry::getPassRegistry());63}6465StringRef getPassName() const override {66return "Hexagon generate \"extract\" instructions";67}6869bool runOnFunction(Function &F) override;7071void getAnalysisUsage(AnalysisUsage &AU) const override {72AU.addRequired<DominatorTreeWrapperPass>();73AU.addPreserved<DominatorTreeWrapperPass>();74FunctionPass::getAnalysisUsage(AU);75}7677private:78bool visitBlock(BasicBlock *B);79bool convert(Instruction *In);8081unsigned ExtractCount = 0;82DominatorTree *DT;83};8485} // end anonymous namespace8687char HexagonGenExtract::ID = 0;8889INITIALIZE_PASS_BEGIN(HexagonGenExtract, "hextract", "Hexagon generate "90"\"extract\" instructions", false, false)91INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)92INITIALIZE_PASS_END(HexagonGenExtract, "hextract", "Hexagon generate "93"\"extract\" instructions", false, false)9495bool HexagonGenExtract::convert(Instruction *In) {96using namespace PatternMatch;9798Value *BF = nullptr;99ConstantInt *CSL = nullptr, *CSR = nullptr, *CM = nullptr;100BasicBlock *BB = In->getParent();101LLVMContext &Ctx = BB->getContext();102bool LogicalSR;103104// (and (shl (lshr x, #sr), #sl), #m)105LogicalSR = true;106bool Match = match(In, m_And(m_Shl(m_LShr(m_Value(BF), m_ConstantInt(CSR)),107m_ConstantInt(CSL)),108m_ConstantInt(CM)));109110if (!Match) {111// (and (shl (ashr x, #sr), #sl), #m)112LogicalSR = false;113Match = match(In, m_And(m_Shl(m_AShr(m_Value(BF), m_ConstantInt(CSR)),114m_ConstantInt(CSL)),115m_ConstantInt(CM)));116}117if (!Match) {118// (and (shl x, #sl), #m)119LogicalSR = true;120CSR = ConstantInt::get(Type::getInt32Ty(Ctx), 0);121Match = match(In, m_And(m_Shl(m_Value(BF), m_ConstantInt(CSL)),122m_ConstantInt(CM)));123if (Match && NoSR0)124return false;125}126if (!Match) {127// (and (lshr x, #sr), #m)128LogicalSR = true;129CSL = ConstantInt::get(Type::getInt32Ty(Ctx), 0);130Match = match(In, m_And(m_LShr(m_Value(BF), m_ConstantInt(CSR)),131m_ConstantInt(CM)));132}133if (!Match) {134// (and (ashr x, #sr), #m)135LogicalSR = false;136CSL = ConstantInt::get(Type::getInt32Ty(Ctx), 0);137Match = match(In, m_And(m_AShr(m_Value(BF), m_ConstantInt(CSR)),138m_ConstantInt(CM)));139}140if (!Match) {141CM = nullptr;142// (shl (lshr x, #sr), #sl)143LogicalSR = true;144Match = match(In, m_Shl(m_LShr(m_Value(BF), m_ConstantInt(CSR)),145m_ConstantInt(CSL)));146}147if (!Match) {148CM = nullptr;149// (shl (ashr x, #sr), #sl)150LogicalSR = false;151Match = match(In, m_Shl(m_AShr(m_Value(BF), m_ConstantInt(CSR)),152m_ConstantInt(CSL)));153}154if (!Match)155return false;156157Type *Ty = BF->getType();158if (!Ty->isIntegerTy())159return false;160unsigned BW = Ty->getPrimitiveSizeInBits();161if (BW != 32 && BW != 64)162return false;163164uint32_t SR = CSR->getZExtValue();165uint32_t SL = CSL->getZExtValue();166167if (!CM) {168// If there was no and, and the shift left did not remove all potential169// sign bits created by the shift right, then extractu cannot reproduce170// this value.171if (!LogicalSR && (SR > SL))172return false;173APInt A = APInt(BW, ~0ULL).lshr(SR).shl(SL);174CM = ConstantInt::get(Ctx, A);175}176177// CM is the shifted-left mask. Shift it back right to remove the zero178// bits on least-significant positions.179APInt M = CM->getValue().lshr(SL);180uint32_t T = M.countr_one();181182// During the shifts some of the bits will be lost. Calculate how many183// of the original value will remain after shift right and then left.184uint32_t U = BW - std::max(SL, SR);185// The width of the extracted field is the minimum of the original bits186// that remain after the shifts and the number of contiguous 1s in the mask.187uint32_t W = std::min(U, T);188if (W == 0 || W == 1)189return false;190191// Check if the extracted bits are contained within the mask that it is192// and-ed with. The extract operation will copy these bits, and so the193// mask cannot any holes in it that would clear any of the bits of the194// extracted field.195if (!LogicalSR) {196// If the shift right was arithmetic, it could have included some 1 bits.197// It is still ok to generate extract, but only if the mask eliminates198// those bits (i.e. M does not have any bits set beyond U).199APInt C = APInt::getHighBitsSet(BW, BW-U);200if (M.intersects(C) || !M.isMask(W))201return false;202} else {203// Check if M starts with a contiguous sequence of W times 1 bits. Get204// the low U bits of M (which eliminates the 0 bits shifted in on the205// left), and check if the result is APInt's "mask":206if (!M.getLoBits(U).isMask(W))207return false;208}209210IRBuilder<> IRB(In);211Intrinsic::ID IntId = (BW == 32) ? Intrinsic::hexagon_S2_extractu212: Intrinsic::hexagon_S2_extractup;213Module *Mod = BB->getParent()->getParent();214Function *ExtF = Intrinsic::getDeclaration(Mod, IntId);215Value *NewIn = IRB.CreateCall(ExtF, {BF, IRB.getInt32(W), IRB.getInt32(SR)});216if (SL != 0)217NewIn = IRB.CreateShl(NewIn, SL, CSL->getName());218In->replaceAllUsesWith(NewIn);219return true;220}221222bool HexagonGenExtract::visitBlock(BasicBlock *B) {223bool Changed = false;224225// Depth-first, bottom-up traversal.226for (auto *DTN : children<DomTreeNode*>(DT->getNode(B)))227Changed |= visitBlock(DTN->getBlock());228229// Allow limiting the number of generated extracts for debugging purposes.230bool HasCutoff = ExtractCutoff.getPosition();231unsigned Cutoff = ExtractCutoff;232233BasicBlock::iterator I = std::prev(B->end()), NextI, Begin = B->begin();234while (true) {235if (HasCutoff && (ExtractCount >= Cutoff))236return Changed;237bool Last = (I == Begin);238if (!Last)239NextI = std::prev(I);240Instruction *In = &*I;241bool Done = convert(In);242if (HasCutoff && Done)243ExtractCount++;244Changed |= Done;245if (Last)246break;247I = NextI;248}249return Changed;250}251252bool HexagonGenExtract::runOnFunction(Function &F) {253if (skipFunction(F))254return false;255256DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();257bool Changed;258259// Traverse the function bottom-up, to see super-expressions before their260// sub-expressions.261BasicBlock *Entry = GraphTraits<Function*>::getEntryNode(&F);262Changed = visitBlock(Entry);263264return Changed;265}266267FunctionPass *llvm::createHexagonGenExtract() {268return new HexagonGenExtract();269}270271272