259 lines · cpp
1//===- HexagonGenExtract.cpp ----------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "Hexagon.h"10#include "llvm/ADT/APInt.h"11#include "llvm/ADT/GraphTraits.h"12#include "llvm/IR/BasicBlock.h"13#include "llvm/IR/CFG.h"14#include "llvm/IR/Constants.h"15#include "llvm/IR/Dominators.h"16#include "llvm/IR/Function.h"17#include "llvm/IR/IRBuilder.h"18#include "llvm/IR/Instruction.h"19#include "llvm/IR/Instructions.h"20#include "llvm/IR/Intrinsics.h"21#include "llvm/IR/IntrinsicsHexagon.h"22#include "llvm/IR/PatternMatch.h"23#include "llvm/IR/Type.h"24#include "llvm/IR/Value.h"25#include "llvm/InitializePasses.h"26#include "llvm/Pass.h"27#include "llvm/Support/CommandLine.h"28#include <algorithm>29#include <cstdint>30#include <iterator>31 32using namespace llvm;33 34static cl::opt<unsigned> ExtractCutoff("extract-cutoff", cl::init(~0U),35 cl::Hidden, cl::desc("Cutoff for generating \"extract\""36 " instructions"));37 38// This prevents generating extract instructions that have the offset of 0.39// One of the reasons for "extract" is to put a sequence of bits in a regis-40// ter, starting at offset 0 (so that these bits can then be used by an41// "insert"). If the bits are already at offset 0, it is better not to gene-42// rate "extract", since logical bit operations can be merged into compound43// instructions (as opposed to "extract").44static cl::opt<bool> NoSR0("extract-nosr0", cl::init(true), cl::Hidden,45 cl::desc("No extract instruction with offset 0"));46 47namespace {48 49 class HexagonGenExtract : public FunctionPass {50 public:51 static char ID;52 53 HexagonGenExtract() : FunctionPass(ID) {}54 55 StringRef getPassName() const override {56 return "Hexagon generate \"extract\" instructions";57 }58 59 bool runOnFunction(Function &F) override;60 61 void getAnalysisUsage(AnalysisUsage &AU) const override {62 AU.addRequired<DominatorTreeWrapperPass>();63 AU.addPreserved<DominatorTreeWrapperPass>();64 FunctionPass::getAnalysisUsage(AU);65 }66 67 private:68 bool visitBlock(BasicBlock *B);69 bool convert(Instruction *In);70 71 unsigned ExtractCount = 0;72 DominatorTree *DT;73 };74 75} // end anonymous namespace76 77char HexagonGenExtract::ID = 0;78 79INITIALIZE_PASS_BEGIN(HexagonGenExtract, "hextract", "Hexagon generate "80 "\"extract\" instructions", false, false)81INITIALIZE_PASS_DEPENDENCY(DominatorTreeWrapperPass)82INITIALIZE_PASS_END(HexagonGenExtract, "hextract", "Hexagon generate "83 "\"extract\" instructions", false, false)84 85bool HexagonGenExtract::convert(Instruction *In) {86 using namespace PatternMatch;87 88 Value *BF = nullptr;89 ConstantInt *CSL = nullptr, *CSR = nullptr, *CM = nullptr;90 BasicBlock *BB = In->getParent();91 LLVMContext &Ctx = BB->getContext();92 bool LogicalSR;93 94 // (and (shl (lshr x, #sr), #sl), #m)95 LogicalSR = true;96 bool Match = match(In, m_And(m_Shl(m_LShr(m_Value(BF), m_ConstantInt(CSR)),97 m_ConstantInt(CSL)),98 m_ConstantInt(CM)));99 100 if (!Match) {101 // (and (shl (ashr x, #sr), #sl), #m)102 LogicalSR = false;103 Match = match(In, m_And(m_Shl(m_AShr(m_Value(BF), m_ConstantInt(CSR)),104 m_ConstantInt(CSL)),105 m_ConstantInt(CM)));106 }107 if (!Match) {108 // (and (shl x, #sl), #m)109 LogicalSR = true;110 CSR = ConstantInt::get(Type::getInt32Ty(Ctx), 0);111 Match = match(In, m_And(m_Shl(m_Value(BF), m_ConstantInt(CSL)),112 m_ConstantInt(CM)));113 if (Match && NoSR0)114 return false;115 }116 if (!Match) {117 // (and (lshr x, #sr), #m)118 LogicalSR = true;119 CSL = ConstantInt::get(Type::getInt32Ty(Ctx), 0);120 Match = match(In, m_And(m_LShr(m_Value(BF), m_ConstantInt(CSR)),121 m_ConstantInt(CM)));122 }123 if (!Match) {124 // (and (ashr x, #sr), #m)125 LogicalSR = false;126 CSL = ConstantInt::get(Type::getInt32Ty(Ctx), 0);127 Match = match(In, m_And(m_AShr(m_Value(BF), m_ConstantInt(CSR)),128 m_ConstantInt(CM)));129 }130 if (!Match) {131 CM = nullptr;132 // (shl (lshr x, #sr), #sl)133 LogicalSR = true;134 Match = match(In, m_Shl(m_LShr(m_Value(BF), m_ConstantInt(CSR)),135 m_ConstantInt(CSL)));136 }137 if (!Match) {138 CM = nullptr;139 // (shl (ashr x, #sr), #sl)140 LogicalSR = false;141 Match = match(In, m_Shl(m_AShr(m_Value(BF), m_ConstantInt(CSR)),142 m_ConstantInt(CSL)));143 }144 if (!Match)145 return false;146 147 Type *Ty = BF->getType();148 if (!Ty->isIntegerTy())149 return false;150 unsigned BW = Ty->getPrimitiveSizeInBits();151 if (BW != 32 && BW != 64)152 return false;153 154 uint32_t SR = CSR->getZExtValue();155 uint32_t SL = CSL->getZExtValue();156 157 if (!CM) {158 // If there was no and, and the shift left did not remove all potential159 // sign bits created by the shift right, then extractu cannot reproduce160 // this value.161 if (!LogicalSR && (SR > SL))162 return false;163 APInt A = APInt(BW, ~0ULL, true).lshr(SR).shl(SL);164 CM = ConstantInt::get(Ctx, A);165 }166 167 // CM is the shifted-left mask. Shift it back right to remove the zero168 // bits on least-significant positions.169 APInt M = CM->getValue().lshr(SL);170 uint32_t T = M.countr_one();171 172 // During the shifts some of the bits will be lost. Calculate how many173 // of the original value will remain after shift right and then left.174 uint32_t U = BW - std::max(SL, SR);175 // The width of the extracted field is the minimum of the original bits176 // that remain after the shifts and the number of contiguous 1s in the mask.177 uint32_t W = std::min(U, T);178 if (W == 0 || W == 1)179 return false;180 181 // Check if the extracted bits are contained within the mask that it is182 // and-ed with. The extract operation will copy these bits, and so the183 // mask cannot any holes in it that would clear any of the bits of the184 // extracted field.185 if (!LogicalSR) {186 // If the shift right was arithmetic, it could have included some 1 bits.187 // It is still ok to generate extract, but only if the mask eliminates188 // those bits (i.e. M does not have any bits set beyond U).189 APInt C = APInt::getHighBitsSet(BW, BW-U);190 if (M.intersects(C) || !M.isMask(W))191 return false;192 } else {193 // Check if M starts with a contiguous sequence of W times 1 bits. Get194 // the low U bits of M (which eliminates the 0 bits shifted in on the195 // left), and check if the result is APInt's "mask":196 if (!M.getLoBits(U).isMask(W))197 return false;198 }199 200 IRBuilder<> IRB(In);201 Intrinsic::ID IntId = (BW == 32) ? Intrinsic::hexagon_S2_extractu202 : Intrinsic::hexagon_S2_extractup;203 Value *NewIn =204 IRB.CreateIntrinsic(IntId, {BF, IRB.getInt32(W), IRB.getInt32(SR)});205 if (SL != 0)206 NewIn = IRB.CreateShl(NewIn, SL, CSL->getName());207 In->replaceAllUsesWith(NewIn);208 return true;209}210 211bool HexagonGenExtract::visitBlock(BasicBlock *B) {212 bool Changed = false;213 214 // Depth-first, bottom-up traversal.215 for (auto *DTN : children<DomTreeNode*>(DT->getNode(B)))216 Changed |= visitBlock(DTN->getBlock());217 218 // Allow limiting the number of generated extracts for debugging purposes.219 bool HasCutoff = ExtractCutoff.getPosition();220 unsigned Cutoff = ExtractCutoff;221 222 BasicBlock::iterator I = std::prev(B->end()), NextI, Begin = B->begin();223 while (true) {224 if (HasCutoff && (ExtractCount >= Cutoff))225 return Changed;226 bool Last = (I == Begin);227 if (!Last)228 NextI = std::prev(I);229 Instruction *In = &*I;230 bool Done = convert(In);231 if (HasCutoff && Done)232 ExtractCount++;233 Changed |= Done;234 if (Last)235 break;236 I = NextI;237 }238 return Changed;239}240 241bool HexagonGenExtract::runOnFunction(Function &F) {242 if (skipFunction(F))243 return false;244 245 DT = &getAnalysis<DominatorTreeWrapperPass>().getDomTree();246 bool Changed;247 248 // Traverse the function bottom-up, to see super-expressions before their249 // sub-expressions.250 BasicBlock *Entry = GraphTraits<Function*>::getEntryNode(&F);251 Changed = visitBlock(Entry);252 253 return Changed;254}255 256FunctionPass *llvm::createHexagonGenExtract() {257 return new HexagonGenExtract();258}259