Path: blob/main/contrib/llvm-project/llvm/lib/Target/AArch64/AArch64CompressJumpTables.cpp
35267 views
//==-- AArch64CompressJumpTables.cpp - Compress jump tables for AArch64 --====//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// This pass looks at the basic blocks each jump-table refers to and works out7// whether they can be emitted in a compressed form (with 8 or 16-bit8// entries). If so, it changes the opcode and flags them in the associated9// AArch64FunctionInfo.10//11//===----------------------------------------------------------------------===//1213#include "AArch64.h"14#include "AArch64MachineFunctionInfo.h"15#include "AArch64Subtarget.h"16#include "llvm/ADT/Statistic.h"17#include "llvm/CodeGen/MachineFunctionPass.h"18#include "llvm/CodeGen/MachineJumpTableInfo.h"19#include "llvm/CodeGen/TargetInstrInfo.h"20#include "llvm/CodeGen/TargetSubtargetInfo.h"21#include "llvm/MC/MCContext.h"22#include "llvm/Support/Alignment.h"23#include "llvm/Support/Debug.h"2425using namespace llvm;2627#define DEBUG_TYPE "aarch64-jump-tables"2829STATISTIC(NumJT8, "Number of jump-tables with 1-byte entries");30STATISTIC(NumJT16, "Number of jump-tables with 2-byte entries");31STATISTIC(NumJT32, "Number of jump-tables with 4-byte entries");3233namespace {34class AArch64CompressJumpTables : public MachineFunctionPass {35const TargetInstrInfo *TII;36MachineFunction *MF;37SmallVector<int, 8> BlockInfo;3839/// Returns the size of instructions in the block \p MBB, or std::nullopt if40/// we couldn't get a safe upper bound.41std::optional<int> computeBlockSize(MachineBasicBlock &MBB);4243/// Gather information about the function, returns false if we can't perform44/// this optimization for some reason.45bool scanFunction();4647bool compressJumpTable(MachineInstr &MI, int Offset);4849public:50static char ID;51AArch64CompressJumpTables() : MachineFunctionPass(ID) {52initializeAArch64CompressJumpTablesPass(*PassRegistry::getPassRegistry());53}5455bool runOnMachineFunction(MachineFunction &MF) override;5657MachineFunctionProperties getRequiredProperties() const override {58return MachineFunctionProperties().set(59MachineFunctionProperties::Property::NoVRegs);60}61StringRef getPassName() const override {62return "AArch64 Compress Jump Tables";63}64};65char AArch64CompressJumpTables::ID = 0;66} // namespace6768INITIALIZE_PASS(AArch64CompressJumpTables, DEBUG_TYPE,69"AArch64 compress jump tables pass", false, false)7071std::optional<int>72AArch64CompressJumpTables::computeBlockSize(MachineBasicBlock &MBB) {73int Size = 0;74for (const MachineInstr &MI : MBB) {75// Inline asm may contain some directives like .bytes which we don't76// currently have the ability to parse accurately. To be safe, just avoid77// computing a size and bail out.78if (MI.getOpcode() == AArch64::INLINEASM ||79MI.getOpcode() == AArch64::INLINEASM_BR)80return std::nullopt;81Size += TII->getInstSizeInBytes(MI);82}83return Size;84}8586bool AArch64CompressJumpTables::scanFunction() {87BlockInfo.clear();88BlockInfo.resize(MF->getNumBlockIDs());8990// NOTE: BlockSize, Offset, OffsetAfterAlignment are all upper bounds.9192unsigned Offset = 0;93for (MachineBasicBlock &MBB : *MF) {94const Align Alignment = MBB.getAlignment();95unsigned OffsetAfterAlignment = Offset;96// We don't know the exact size of MBB so assume worse case padding.97if (Alignment > Align(4))98OffsetAfterAlignment += Alignment.value() - 4;99BlockInfo[MBB.getNumber()] = OffsetAfterAlignment;100auto BlockSize = computeBlockSize(MBB);101if (!BlockSize)102return false;103Offset = OffsetAfterAlignment + *BlockSize;104}105return true;106}107108bool AArch64CompressJumpTables::compressJumpTable(MachineInstr &MI,109int Offset) {110if (MI.getOpcode() != AArch64::JumpTableDest32)111return false;112113int JTIdx = MI.getOperand(4).getIndex();114auto &JTInfo = *MF->getJumpTableInfo();115const MachineJumpTableEntry &JT = JTInfo.getJumpTables()[JTIdx];116117// The jump-table might have been optimized away.118if (JT.MBBs.empty())119return false;120121int MaxOffset = std::numeric_limits<int>::min(),122MinOffset = std::numeric_limits<int>::max();123MachineBasicBlock *MinBlock = nullptr;124for (auto *Block : JT.MBBs) {125int BlockOffset = BlockInfo[Block->getNumber()];126assert(BlockOffset % 4 == 0 && "misaligned basic block");127128MaxOffset = std::max(MaxOffset, BlockOffset);129if (BlockOffset <= MinOffset) {130MinOffset = BlockOffset;131MinBlock = Block;132}133}134assert(MinBlock && "Failed to find minimum offset block");135136// The ADR instruction needed to calculate the address of the first reachable137// basic block can address +/-1MB.138if (!isInt<21>(MinOffset - Offset)) {139++NumJT32;140return false;141}142143int Span = MaxOffset - MinOffset;144auto *AFI = MF->getInfo<AArch64FunctionInfo>();145if (isUInt<8>(Span / 4)) {146AFI->setJumpTableEntryInfo(JTIdx, 1, MinBlock->getSymbol());147MI.setDesc(TII->get(AArch64::JumpTableDest8));148++NumJT8;149return true;150}151if (isUInt<16>(Span / 4)) {152AFI->setJumpTableEntryInfo(JTIdx, 2, MinBlock->getSymbol());153MI.setDesc(TII->get(AArch64::JumpTableDest16));154++NumJT16;155return true;156}157158++NumJT32;159return false;160}161162bool AArch64CompressJumpTables::runOnMachineFunction(MachineFunction &MFIn) {163bool Changed = false;164MF = &MFIn;165166const auto &ST = MF->getSubtarget<AArch64Subtarget>();167TII = ST.getInstrInfo();168169if (ST.force32BitJumpTables() && !MF->getFunction().hasMinSize())170return false;171172if (!scanFunction())173return false;174175for (MachineBasicBlock &MBB : *MF) {176int Offset = BlockInfo[MBB.getNumber()];177for (MachineInstr &MI : MBB) {178Changed |= compressJumpTable(MI, Offset);179Offset += TII->getInstSizeInBytes(MI);180}181}182183return Changed;184}185186FunctionPass *llvm::createAArch64CompressJumpTablesPass() {187return new AArch64CompressJumpTables();188}189190191