1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-10-26 22:42:46 +02:00
llvm-mirror/lib/Target/Hexagon/MCTargetDesc/HexagonShuffler.cpp
Justin Bogner dcde6ede19 Hexagon: Paper over the undefined behaviour introduced by r238692
This stops shifting a 32-bit value by such absurd amounts as 96 and
120. We do this by dropping a call to the function that was doing this
entirely, which rather surprisingly doesn't break *any* tests.

I've also added an assert in the misbehaving function to prove that
it's no longer being called with completely invalid arguments.

This change looks pretty bogus and we should probably be reverting
r238692 instead, but this is hard to do with the number of follow ups
that have happened since. It can't be any worse than the undefined
behaviour that was happening before though.

llvm-svn: 240526
2015-06-24 07:03:07 +00:00

389 lines
12 KiB
C++

//===----- HexagonShuffler.cpp - Instruction bundle shuffling -------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This implements the shuffling of insns inside a bundle according to the
// packet formation rules of the Hexagon ISA.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "hexagon-shuffle"
#include <algorithm>
#include <utility>
#include "Hexagon.h"
#include "MCTargetDesc/HexagonBaseInfo.h"
#include "MCTargetDesc/HexagonMCTargetDesc.h"
#include "MCTargetDesc/HexagonMCInstrInfo.h"
#include "HexagonShuffler.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
// Insn shuffling priority.
class HexagonBid {
// The priority is directly proportional to how restricted the insn is based
// on its flexibility to run on the available slots. So, the fewer slots it
// may run on, the higher its priority.
enum { MAX = 360360 }; // LCD of 1/2, 1/3, 1/4,... 1/15.
unsigned Bid;
public:
HexagonBid() : Bid(0){};
HexagonBid(unsigned B) { Bid = B ? MAX / countPopulation(B) : 0; };
// Check if the insn priority is overflowed.
bool isSold() const { return (Bid >= MAX); };
HexagonBid &operator+=(const HexagonBid &B) {
Bid += B.Bid;
return *this;
};
};
// Slot shuffling allocation.
class HexagonUnitAuction {
HexagonBid Scores[HEXAGON_PACKET_SIZE];
// Mask indicating which slot is unavailable.
unsigned isSold : HEXAGON_PACKET_SIZE;
public:
HexagonUnitAuction() : isSold(0){};
// Allocate slots.
bool bid(unsigned B) {
// Exclude already auctioned slots from the bid.
unsigned b = B & ~isSold;
if (b) {
for (unsigned i = 0; i < HEXAGON_PACKET_SIZE; ++i)
if (b & (1 << i)) {
// Request candidate slots.
Scores[i] += HexagonBid(b);
isSold |= Scores[i].isSold() << i;
}
return true;
;
} else
// Error if the desired slots are already full.
return false;
};
};
unsigned HexagonResource::setWeight(unsigned s) {
const unsigned SlotWeight = 8;
const unsigned MaskWeight = SlotWeight - 1;
bool Key = (1 << s) & getUnits();
// TODO: Improve this API so that we can prevent misuse statically.
assert(SlotWeight * s < 32 && "Argument to setWeight too large.");
// Calculate relative weight of the insn for the given slot, weighing it the
// heavier the more restrictive the insn is and the lowest the slots that the
// insn may be executed in.
Weight =
(Key << (SlotWeight * s)) * ((MaskWeight - countPopulation(getUnits()))
<< countTrailingZeros(getUnits()));
return (Weight);
}
HexagonShuffler::HexagonShuffler(MCInstrInfo const &MCII,
MCSubtargetInfo const &STI)
: MCII(MCII), STI(STI) {
reset();
}
void HexagonShuffler::reset() {
Packet.clear();
BundleFlags = 0;
Error = SHUFFLE_SUCCESS;
}
void HexagonShuffler::append(MCInst const *ID, MCInst const *Extender,
unsigned S, bool X) {
HexagonInstr PI(ID, Extender, S, X);
Packet.push_back(PI);
}
/// Check that the packet is legal and enforce relative insn order.
bool HexagonShuffler::check() {
// Descriptive slot masks.
const unsigned slotSingleLoad = 0x1, slotSingleStore = 0x1, slotOne = 0x2,
slotThree = 0x8, slotFirstJump = 0x8, slotLastJump = 0x4,
slotFirstLoadStore = 0x2, slotLastLoadStore = 0x1;
// Highest slots for branches and stores used to keep their original order.
unsigned slotJump = slotFirstJump;
unsigned slotLoadStore = slotFirstLoadStore;
// Number of branches, solo branches, indirect branches.
unsigned jumps = 0, jump1 = 0, jumpr = 0;
// Number of memory operations, loads, solo loads, stores, solo stores, single
// stores.
unsigned memory = 0, loads = 0, load0 = 0, stores = 0, store0 = 0, store1 = 0;
// Number of duplex insns, solo insns.
unsigned duplex = 0, solo = 0;
// Number of insns restricting other insns in the packet to A and X types,
// which is neither A or X types.
unsigned onlyAX = 0, neitherAnorX = 0;
// Number of insns restricting other insns in slot #1 to A type.
unsigned onlyAin1 = 0;
// Number of insns restricting any insn in slot #1, except A2_nop.
unsigned onlyNo1 = 0;
unsigned xtypeFloat = 0;
unsigned pSlot3Cnt = 0;
iterator slot3ISJ = end();
// Collect information from the insns in the packet.
for (iterator ISJ = begin(); ISJ != end(); ++ISJ) {
MCInst const *ID = ISJ->getDesc();
if (HexagonMCInstrInfo::isSolo(MCII, *ID))
solo += !ISJ->isSoloException();
else if (HexagonMCInstrInfo::isSoloAX(MCII, *ID))
onlyAX += !ISJ->isSoloException();
else if (HexagonMCInstrInfo::isSoloAin1(MCII, *ID))
onlyAin1 += !ISJ->isSoloException();
if (HexagonMCInstrInfo::getType(MCII, *ID) != HexagonII::TypeALU32 &&
HexagonMCInstrInfo::getType(MCII, *ID) != HexagonII::TypeXTYPE)
++neitherAnorX;
if (HexagonMCInstrInfo::prefersSlot3(MCII, *ID)) {
++pSlot3Cnt;
slot3ISJ = ISJ;
}
switch (HexagonMCInstrInfo::getType(MCII, *ID)) {
case HexagonII::TypeXTYPE:
if (HexagonMCInstrInfo::isFloat(MCII, *ID))
++xtypeFloat;
break;
case HexagonII::TypeJR:
++jumpr;
// Fall-through.
case HexagonII::TypeJ:
++jumps;
break;
case HexagonII::TypeLD:
++loads;
++memory;
if (ISJ->Core.getUnits() == slotSingleLoad)
++load0;
if (HexagonMCInstrInfo::getDesc(MCII, *ID).isReturn())
++jumps, ++jump1; // DEALLOC_RETURN is of type LD.
break;
case HexagonII::TypeST:
++stores;
++memory;
if (ISJ->Core.getUnits() == slotSingleStore)
++store0;
break;
case HexagonII::TypeMEMOP:
++loads;
++stores;
++store1;
++memory;
break;
case HexagonII::TypeNV:
++memory; // NV insns are memory-like.
if (HexagonMCInstrInfo::getDesc(MCII, *ID).isBranch())
++jumps, ++jump1;
break;
case HexagonII::TypeCR:
// Legacy conditional branch predicated on a register.
case HexagonII::TypeSYSTEM:
if (HexagonMCInstrInfo::getDesc(MCII, *ID).mayLoad())
++loads;
break;
}
}
// Check if the packet is legal.
if ((load0 > 1 || store0 > 1) || (duplex > 1 || (duplex && memory)) ||
(solo && size() > 1) || (onlyAX && neitherAnorX > 1) ||
(onlyAX && xtypeFloat)) {
Error = SHUFFLE_ERROR_INVALID;
return false;
}
if (jump1 && jumps > 1) {
// Error if single branch with another branch.
Error = SHUFFLE_ERROR_BRANCHES;
return false;
}
// Modify packet accordingly.
// TODO: need to reserve slots #0 and #1 for duplex insns.
bool bOnlySlot3 = false;
for (iterator ISJ = begin(); ISJ != end(); ++ISJ) {
MCInst const *ID = ISJ->getDesc();
if (!ISJ->Core.getUnits()) {
// Error if insn may not be executed in any slot.
Error = SHUFFLE_ERROR_UNKNOWN;
return false;
}
// Exclude from slot #1 any insn but A2_nop.
if (HexagonMCInstrInfo::getDesc(MCII, *ID).getOpcode() != Hexagon::A2_nop)
if (onlyNo1)
ISJ->Core.setUnits(ISJ->Core.getUnits() & ~slotOne);
// Exclude from slot #1 any insn but A-type.
if (HexagonMCInstrInfo::getType(MCII, *ID) != HexagonII::TypeALU32)
if (onlyAin1)
ISJ->Core.setUnits(ISJ->Core.getUnits() & ~slotOne);
// Branches must keep the original order.
if (HexagonMCInstrInfo::getDesc(MCII, *ID).isBranch() ||
HexagonMCInstrInfo::getDesc(MCII, *ID).isCall())
if (jumps > 1) {
if (jumpr || slotJump < slotLastJump) {
// Error if indirect branch with another branch or
// no more slots available for branches.
Error = SHUFFLE_ERROR_BRANCHES;
return false;
}
// Pin the branch to the highest slot available to it.
ISJ->Core.setUnits(ISJ->Core.getUnits() & slotJump);
// Update next highest slot available to branches.
slotJump >>= 1;
}
// A single load must use slot #0.
if (HexagonMCInstrInfo::getDesc(MCII, *ID).mayLoad()) {
if (loads == 1 && loads == memory)
// Pin the load to slot #0.
ISJ->Core.setUnits(ISJ->Core.getUnits() & slotSingleLoad);
}
// A single store must use slot #0.
if (HexagonMCInstrInfo::getDesc(MCII, *ID).mayStore()) {
if (!store0) {
if (stores == 1)
ISJ->Core.setUnits(ISJ->Core.getUnits() & slotSingleStore);
else if (stores > 1) {
if (slotLoadStore < slotLastLoadStore) {
// Error if no more slots available for stores.
Error = SHUFFLE_ERROR_STORES;
return false;
}
// Pin the store to the highest slot available to it.
ISJ->Core.setUnits(ISJ->Core.getUnits() & slotLoadStore);
// Update the next highest slot available to stores.
slotLoadStore >>= 1;
}
}
if (store1 && stores > 1) {
// Error if a single store with another store.
Error = SHUFFLE_ERROR_STORES;
return false;
}
}
// flag if an instruction can only be executed in slot 3
if (ISJ->Core.getUnits() == slotThree)
bOnlySlot3 = true;
if (!ISJ->Core.getUnits()) {
// Error if insn may not be executed in any slot.
Error = SHUFFLE_ERROR_NOSLOTS;
return false;
}
}
bool validateSlots = true;
if (bOnlySlot3 == false && pSlot3Cnt == 1 && slot3ISJ != end()) {
// save off slot mask of instruction marked with A_PREFER_SLOT3
// and then pin it to slot #3
unsigned saveUnits = slot3ISJ->Core.getUnits();
slot3ISJ->Core.setUnits(saveUnits & slotThree);
HexagonUnitAuction AuctionCore;
std::sort(begin(), end(), HexagonInstr::lessCore);
// see if things ok with that instruction being pinned to slot #3
bool bFail = false;
for (iterator I = begin(); I != end() && bFail != true; ++I)
if (!AuctionCore.bid(I->Core.getUnits()))
bFail = true;
// if yes, great, if not then restore original slot mask
if (!bFail)
validateSlots = false; // all good, no need to re-do auction
else
for (iterator ISJ = begin(); ISJ != end(); ++ISJ) {
MCInst const *ID = ISJ->getDesc();
if (HexagonMCInstrInfo::prefersSlot3(MCII, *ID))
ISJ->Core.setUnits(saveUnits);
}
}
// Check if any slot, core, is over-subscribed.
// Verify the core slot subscriptions.
if (validateSlots) {
HexagonUnitAuction AuctionCore;
std::sort(begin(), end(), HexagonInstr::lessCore);
for (iterator I = begin(); I != end(); ++I)
if (!AuctionCore.bid(I->Core.getUnits())) {
Error = SHUFFLE_ERROR_SLOTS;
return false;
}
}
Error = SHUFFLE_SUCCESS;
return true;
}
bool HexagonShuffler::shuffle() {
if (size() > HEXAGON_PACKET_SIZE) {
// Ignore a packet with with more than what a packet can hold
// or with compound or duplex insns for now.
Error = SHUFFLE_ERROR_INVALID;
return false;
}
// Check and prepare packet.
if (size() > 1 && check())
// Reorder the handles for each slot.
for (unsigned nSlot = 0, emptySlots = 0; nSlot < HEXAGON_PACKET_SIZE;
++nSlot) {
iterator ISJ, ISK;
unsigned slotSkip, slotWeight;
// Prioritize the handles considering their restrictions.
for (ISJ = ISK = Packet.begin(), slotSkip = slotWeight = 0;
ISK != Packet.end(); ++ISK, ++slotSkip)
if (slotSkip < nSlot - emptySlots)
// Note which handle to begin at.
++ISJ;
else
// Calculate the weight of the slot.
slotWeight += ISK->Core.setWeight(HEXAGON_PACKET_SIZE - nSlot - 1);
if (slotWeight)
// Sort the packet, favoring source order,
// beginning after the previous slot.
std::sort(ISJ, Packet.end());
else
// Skip unused slot.
++emptySlots;
}
for (iterator ISJ = begin(); ISJ != end(); ++ISJ)
DEBUG(dbgs().write_hex(ISJ->Core.getUnits());
dbgs() << ':'
<< HexagonMCInstrInfo::getDesc(MCII, *ISJ->getDesc())
.getOpcode();
dbgs() << '\n');
DEBUG(dbgs() << '\n');
return (!getError());
}