llvm-project/llvm/lib/Analysis/IRSimilarityIdentifier.cpp

166 lines
5.9 KiB
C++

//===- IRSimilarityIdentifier.cpp - Find similarity in a module -----------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// \file
// Implementation file for the IRSimilarityIdentifier for identifying
// similarities in IR including the IRInstructionMapper.
//
//===----------------------------------------------------------------------===//
#include "llvm/Analysis/IRSimilarityIdentifier.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/User.h"
using namespace llvm;
using namespace IRSimilarity;
IRInstructionData::IRInstructionData(Instruction &I, bool Legality,
IRInstructionDataList &IDList)
: Inst(&I), Legal(Legality), IDL(&IDList) {
// Here we collect the operands to be used to determine whether two
// instructions are similar to one another.
for (Use &OI : I.operands())
OperVals.push_back(OI.get());
}
bool IRSimilarity::isClose(const IRInstructionData &A,
const IRInstructionData &B) {
return A.Legal && A.Inst->isSameOperationAs(B.Inst);
}
// TODO: This is the same as the MachineOutliner, and should be consolidated
// into the same interface.
void IRInstructionMapper::convertToUnsignedVec(
BasicBlock &BB, std::vector<IRInstructionData *> &InstrList,
std::vector<unsigned> &IntegerMapping) {
BasicBlock::iterator It = BB.begin();
std::vector<unsigned> IntegerMappingForBB;
std::vector<IRInstructionData *> InstrListForBB;
HaveLegalRange = false;
CanCombineWithPrevInstr = false;
AddedIllegalLastTime = true;
for (BasicBlock::iterator Et = BB.end(); It != Et; ++It) {
switch (InstClassifier.visit(*It)) {
case InstrType::Legal:
mapToLegalUnsigned(It, IntegerMappingForBB, InstrListForBB);
break;
case InstrType::Illegal:
mapToIllegalUnsigned(It, IntegerMappingForBB, InstrListForBB);
break;
case InstrType::Invisible:
AddedIllegalLastTime = false;
break;
}
}
if (HaveLegalRange) {
mapToIllegalUnsigned(It, IntegerMappingForBB, InstrListForBB, true);
for_each(InstrListForBB,
[this](IRInstructionData *ID) { this->IDL->push_back(*ID); });
InstrList.insert(InstrList.end(), InstrListForBB.begin(),
InstrListForBB.end());
IntegerMapping.insert(IntegerMapping.end(), IntegerMappingForBB.begin(),
IntegerMappingForBB.end());
}
}
// TODO: This is the same as the MachineOutliner, and should be consolidated
// into the same interface.
unsigned IRInstructionMapper::mapToLegalUnsigned(
BasicBlock::iterator &It, std::vector<unsigned> &IntegerMappingForBB,
std::vector<IRInstructionData *> &InstrListForBB) {
// We added something legal, so we should unset the AddedLegalLastTime
// flag.
AddedIllegalLastTime = false;
// If we have at least two adjacent legal instructions (which may have
// invisible instructions in between), remember that.
if (CanCombineWithPrevInstr)
HaveLegalRange = true;
CanCombineWithPrevInstr = true;
// Get the integer for this instruction or give it the current
// LegalInstrNumber.
IRInstructionData *ID = allocateIRInstructionData(*It, true, *IDL);
InstrListForBB.push_back(ID);
// Add to the instruction list
bool WasInserted;
DenseMap<IRInstructionData *, unsigned, IRInstructionDataTraits>::iterator
ResultIt;
std::tie(ResultIt, WasInserted) =
InstructionIntegerMap.insert(std::make_pair(ID, LegalInstrNumber));
unsigned INumber = ResultIt->second;
// There was an insertion.
if (WasInserted)
LegalInstrNumber++;
IntegerMappingForBB.push_back(INumber);
// Make sure we don't overflow or use any integers reserved by the DenseMap.
assert(LegalInstrNumber < IllegalInstrNumber &&
"Instruction mapping overflow!");
assert(LegalInstrNumber != DenseMapInfo<unsigned>::getEmptyKey() &&
"Tried to assign DenseMap tombstone or empty key to instruction.");
assert(LegalInstrNumber != DenseMapInfo<unsigned>::getTombstoneKey() &&
"Tried to assign DenseMap tombstone or empty key to instruction.");
return INumber;
}
IRInstructionData *
IRInstructionMapper::allocateIRInstructionData(Instruction &I, bool Legality,
IRInstructionDataList &IDL) {
return new (InstDataAllocator->Allocate()) IRInstructionData(I, Legality, IDL);
}
IRInstructionDataList *
IRInstructionMapper::allocateIRInstructionDataList() {
return new (IDLAllocator->Allocate()) IRInstructionDataList();
}
// TODO: This is the same as the MachineOutliner, and should be consolidated
// into the same interface.
unsigned IRInstructionMapper::mapToIllegalUnsigned(
BasicBlock::iterator &It, std::vector<unsigned> &IntegerMappingForBB,
std::vector<IRInstructionData *> &InstrListForBB, bool End) {
// Can't combine an illegal instruction. Set the flag.
CanCombineWithPrevInstr = false;
// Only add one illegal number per range of legal numbers.
if (AddedIllegalLastTime)
return IllegalInstrNumber;
IRInstructionData *ID = nullptr;
if (!End)
ID = allocateIRInstructionData(*It, false, *IDL);
InstrListForBB.push_back(ID);
// Remember that we added an illegal number last time.
AddedIllegalLastTime = true;
unsigned INumber = IllegalInstrNumber;
IntegerMappingForBB.push_back(IllegalInstrNumber--);
assert(LegalInstrNumber < IllegalInstrNumber &&
"Instruction mapping overflow!");
assert(IllegalInstrNumber != DenseMapInfo<unsigned>::getEmptyKey() &&
"IllegalInstrNumber cannot be DenseMap tombstone or empty key!");
assert(IllegalInstrNumber != DenseMapInfo<unsigned>::getTombstoneKey() &&
"IllegalInstrNumber cannot be DenseMap tombstone or empty key!");
return INumber;
}