blob: bf3bad36dfe55da8a4843e04ec1bbc44e126a656 [file] [log] [blame] [edit]
//===- HexagonShuffler.h - Instruction bundle shuffling ---------*- C++ -*-===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// This implements the shuffling of insns inside a bundle according to the
// packet formation rules of the Hexagon ISA.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_TARGET_HEXAGON_MCTARGETDESC_HEXAGONSHUFFLER_H
#define LLVM_LIB_TARGET_HEXAGON_MCTARGETDESC_HEXAGONSHUFFLER_H
#include "MCTargetDesc/HexagonMCInstrInfo.h"
#include "MCTargetDesc/HexagonMCTargetDesc.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/SMLoc.h"
#include <cstdint>
#include <utility>
namespace llvm {
class MCContext;
class MCInst;
class MCInstrInfo;
class MCSubtargetInfo;
// Insn resources.
class HexagonResource {
// Mask of the slots or units that may execute the insn and
// the weight or priority that the insn requires to be assigned a slot.
unsigned Slots, Weight;
public:
HexagonResource(unsigned s) { setUnits(s); }
void setUnits(unsigned s) {
Slots = s & ((1u << HEXAGON_PACKET_SIZE) - 1);
setWeight(s);
}
unsigned setWeight(unsigned s);
unsigned getUnits() const { return (Slots); }
unsigned getWeight() const { return (Weight); }
// Check if the resources are in ascending slot order.
static bool lessUnits(const HexagonResource &A, const HexagonResource &B) {
return (countPopulation(A.getUnits()) < countPopulation(B.getUnits()));
}
// Check if the resources are in ascending weight order.
static bool lessWeight(const HexagonResource &A, const HexagonResource &B) {
return (A.getWeight() < B.getWeight());
}
};
// HVX insn resources.
class HexagonCVIResource : public HexagonResource {
public:
using UnitsAndLanes = std::pair<unsigned, unsigned>;
using TypeUnitsAndLanes = DenseMap<unsigned, UnitsAndLanes>;
private:
// Available HVX slots.
enum {
CVI_NONE = 0,
CVI_XLANE = 1 << 0,
CVI_SHIFT = 1 << 1,
CVI_MPY0 = 1 << 2,
CVI_MPY1 = 1 << 3,
CVI_ZW = 1 << 4
};
// Count of adjacent slots that the insn requires to be executed.
unsigned Lanes;
// Flag whether the insn is a load or a store.
bool Load, Store;
// Flag whether the HVX resources are valid.
bool Valid;
void setLanes(unsigned l) { Lanes = l; }
void setLoad(bool f = true) { Load = f; }
void setStore(bool f = true) { Store = f; }
public:
HexagonCVIResource(TypeUnitsAndLanes *TUL, MCInstrInfo const &MCII,
unsigned s, MCInst const *id);
static void SetupTUL(TypeUnitsAndLanes *TUL, StringRef CPU);
bool isValid() const { return Valid; }
unsigned getLanes() const { return Lanes; }
bool mayLoad() const { return Load; }
bool mayStore() const { return Store; }
};
// Handle to an insn used by the shuffling algorithm.
class HexagonInstr {
friend class HexagonShuffler;
MCInst const *ID;
MCInst const *Extender;
HexagonResource Core;
HexagonCVIResource CVI;
public:
HexagonInstr(HexagonCVIResource::TypeUnitsAndLanes *T,
MCInstrInfo const &MCII, MCInst const *id,
MCInst const *Extender, unsigned s)
: ID(id), Extender(Extender), Core(s), CVI(T, MCII, s, id) {}
MCInst const &getDesc() const { return *ID; }
MCInst const *getExtender() const { return Extender; }
// Check if the handles are in ascending order for shuffling purposes.
bool operator<(const HexagonInstr &B) const {
return (HexagonResource::lessWeight(B.Core, Core));
}
// Check if the handles are in ascending order by core slots.
static bool lessCore(const HexagonInstr &A, const HexagonInstr &B) {
return (HexagonResource::lessUnits(A.Core, B.Core));
}
// Check if the handles are in ascending order by HVX slots.
static bool lessCVI(const HexagonInstr &A, const HexagonInstr &B) {
return (HexagonResource::lessUnits(A.CVI, B.CVI));
}
};
// Bundle shuffler.
class HexagonShuffler {
using HexagonPacket =
SmallVector<HexagonInstr, HEXAGON_PRESHUFFLE_PACKET_SIZE>;
// Insn handles in a bundle.
HexagonPacket Packet;
HexagonPacket PacketSave;
HexagonCVIResource::TypeUnitsAndLanes TUL;
protected:
MCContext &Context;
int64_t BundleFlags;
MCInstrInfo const &MCII;
MCSubtargetInfo const &STI;
SMLoc Loc;
bool ReportErrors;
std::vector<std::pair<SMLoc, std::string>> AppliedRestrictions;
void applySlotRestrictions();
void restrictSlot1AOK();
void restrictNoSlot1Store();
public:
using iterator = HexagonPacket::iterator;
HexagonShuffler(MCContext &Context, bool ReportErrors,
MCInstrInfo const &MCII, MCSubtargetInfo const &STI);
// Reset to initial state.
void reset();
// Check if the bundle may be validly shuffled.
bool check();
// Reorder the insn handles in the bundle.
bool shuffle();
unsigned size() const { return (Packet.size()); }
bool isMemReorderDisabled() const {
return (BundleFlags & HexagonMCInstrInfo::memReorderDisabledMask) != 0;
}
iterator begin() { return (Packet.begin()); }
iterator end() { return (Packet.end()); }
// Add insn handle to the bundle .
void append(MCInst const &ID, MCInst const *Extender, unsigned S);
// Return the error code for the last check or shuffling of the bundle.
void reportError(Twine const &Msg);
};
} // end namespace llvm
#endif // LLVM_LIB_TARGET_HEXAGON_MCTARGETDESC_HEXAGONSHUFFLER_H