195 lines
7.9 KiB
C++
195 lines
7.9 KiB
C++
//===- lib/CodeGen/MachineStableHash.cpp ----------------------------------===//
|
|
//
|
|
// 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
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Stable hashing for MachineInstr and MachineOperand. Useful or getting a
|
|
// hash across runs, modules, etc.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "llvm/CodeGen/MachineStableHash.h"
|
|
#include "llvm/ADT/FoldingSet.h"
|
|
#include "llvm/ADT/Statistic.h"
|
|
#include "llvm/ADT/StringExtras.h"
|
|
#include "llvm/Analysis/Loads.h"
|
|
#include "llvm/Analysis/MemoryLocation.h"
|
|
#include "llvm/CodeGen/MIRFormatter.h"
|
|
#include "llvm/CodeGen/MIRPrinter.h"
|
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
|
#include "llvm/CodeGen/MachineInstr.h"
|
|
#include "llvm/CodeGen/MachineJumpTableInfo.h"
|
|
#include "llvm/CodeGen/MachineOperand.h"
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
|
#include "llvm/CodeGen/StableHashing.h"
|
|
#include "llvm/CodeGen/TargetInstrInfo.h"
|
|
#include "llvm/CodeGen/TargetRegisterInfo.h"
|
|
#include "llvm/Config/llvm-config.h"
|
|
#include "llvm/IR/Constants.h"
|
|
#include "llvm/IR/IRPrintingPasses.h"
|
|
#include "llvm/IR/Instructions.h"
|
|
#include "llvm/IR/ModuleSlotTracker.h"
|
|
#include "llvm/MC/MCDwarf.h"
|
|
#include "llvm/Target/TargetIntrinsicInfo.h"
|
|
#include "llvm/Target/TargetMachine.h"
|
|
|
|
#define DEBUG_TYPE "machine-stable-hash"
|
|
|
|
using namespace llvm;
|
|
|
|
STATISTIC(StableHashBailingMachineBasicBlock,
|
|
"Number of encountered unsupported MachineOperands that were "
|
|
"MachineBasicBlocks while computing stable hashes");
|
|
STATISTIC(StableHashBailingConstantPoolIndex,
|
|
"Number of encountered unsupported MachineOperands that were "
|
|
"ConstantPoolIndex while computing stable hashes");
|
|
STATISTIC(StableHashBailingTargetIndexNoName,
|
|
"Number of encountered unsupported MachineOperands that were "
|
|
"TargetIndex with no name");
|
|
STATISTIC(StableHashBailingGlobalAddress,
|
|
"Number of encountered unsupported MachineOperands that were "
|
|
"GlobalAddress while computing stable hashes");
|
|
STATISTIC(StableHashBailingBlockAddress,
|
|
"Number of encountered unsupported MachineOperands that were "
|
|
"BlockAddress while computing stable hashes");
|
|
STATISTIC(StableHashBailingMetadataUnsupported,
|
|
"Number of encountered unsupported MachineOperands that were "
|
|
"Metadata of an unsupported kind while computing stable hashes");
|
|
|
|
stable_hash llvm::stableHashValue(const MachineOperand &MO) {
|
|
switch (MO.getType()) {
|
|
case MachineOperand::MO_Register:
|
|
if (Register::isVirtualRegister(MO.getReg())) {
|
|
const MachineRegisterInfo &MRI = MO.getParent()->getMF()->getRegInfo();
|
|
return MRI.getVRegDef(MO.getReg())->getOpcode();
|
|
}
|
|
|
|
// Register operands don't have target flags.
|
|
return stable_hash_combine(MO.getType(), MO.getReg(), MO.getSubReg(),
|
|
MO.isDef());
|
|
case MachineOperand::MO_Immediate:
|
|
return stable_hash_combine(MO.getType(), MO.getTargetFlags(), MO.getImm());
|
|
case MachineOperand::MO_CImmediate:
|
|
case MachineOperand::MO_FPImmediate: {
|
|
auto Val = MO.isCImm() ? MO.getCImm()->getValue()
|
|
: MO.getFPImm()->getValueAPF().bitcastToAPInt();
|
|
auto ValHash =
|
|
stable_hash_combine_array(Val.getRawData(), Val.getNumWords());
|
|
return hash_combine(MO.getType(), MO.getTargetFlags(), ValHash);
|
|
}
|
|
|
|
case MachineOperand::MO_MachineBasicBlock:
|
|
StableHashBailingMachineBasicBlock++;
|
|
return 0;
|
|
case MachineOperand::MO_ConstantPoolIndex:
|
|
StableHashBailingConstantPoolIndex++;
|
|
return 0;
|
|
case MachineOperand::MO_BlockAddress:
|
|
StableHashBailingBlockAddress++;
|
|
return 0;
|
|
case MachineOperand::MO_Metadata:
|
|
StableHashBailingMetadataUnsupported++;
|
|
return 0;
|
|
case MachineOperand::MO_GlobalAddress:
|
|
StableHashBailingGlobalAddress++;
|
|
return 0;
|
|
case MachineOperand::MO_TargetIndex: {
|
|
if (const char *Name = MO.getTargetIndexName())
|
|
return stable_hash_combine(MO.getType(), MO.getTargetFlags(),
|
|
stable_hash_combine_string(Name),
|
|
MO.getOffset());
|
|
StableHashBailingTargetIndexNoName++;
|
|
return 0;
|
|
}
|
|
|
|
case MachineOperand::MO_FrameIndex:
|
|
case MachineOperand::MO_JumpTableIndex:
|
|
return stable_hash_combine(MO.getType(), MO.getTargetFlags(),
|
|
MO.getIndex());
|
|
|
|
case MachineOperand::MO_ExternalSymbol:
|
|
return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getOffset(),
|
|
stable_hash_combine_string(MO.getSymbolName()));
|
|
|
|
case MachineOperand::MO_RegisterMask:
|
|
case MachineOperand::MO_RegisterLiveOut:
|
|
return hash_combine(MO.getType(), MO.getTargetFlags(), MO.getRegMask());
|
|
|
|
case MachineOperand::MO_ShuffleMask: {
|
|
std::vector<llvm::stable_hash> ShuffleMaskHashes;
|
|
|
|
llvm::transform(
|
|
MO.getShuffleMask(), std::back_inserter(ShuffleMaskHashes),
|
|
[](int S) -> llvm::stable_hash { return llvm::stable_hash(S); });
|
|
|
|
return hash_combine(MO.getType(), MO.getTargetFlags(),
|
|
stable_hash_combine_array(ShuffleMaskHashes.data(),
|
|
ShuffleMaskHashes.size()));
|
|
}
|
|
case MachineOperand::MO_MCSymbol: {
|
|
auto SymbolName = MO.getMCSymbol()->getName();
|
|
return hash_combine(MO.getType(), MO.getTargetFlags(),
|
|
stable_hash_combine_string(SymbolName));
|
|
}
|
|
case MachineOperand::MO_CFIIndex:
|
|
return stable_hash_combine(MO.getType(), MO.getTargetFlags(),
|
|
MO.getCFIIndex());
|
|
case MachineOperand::MO_IntrinsicID:
|
|
return stable_hash_combine(MO.getType(), MO.getTargetFlags(),
|
|
MO.getIntrinsicID());
|
|
case MachineOperand::MO_Predicate:
|
|
return stable_hash_combine(MO.getType(), MO.getTargetFlags(),
|
|
MO.getPredicate());
|
|
}
|
|
llvm_unreachable("Invalid machine operand type");
|
|
}
|
|
|
|
/// A stable hash value for machine instructions.
|
|
/// Returns 0 if no stable hash could be computed.
|
|
/// The hashing and equality testing functions ignore definitions so this is
|
|
/// useful for CSE, etc.
|
|
stable_hash llvm::stableHashValue(const MachineInstr &MI, bool HashVRegs,
|
|
bool HashConstantPoolIndices,
|
|
bool HashMemOperands) {
|
|
// Build up a buffer of hash code components.
|
|
SmallVector<stable_hash, 16> HashComponents;
|
|
HashComponents.reserve(MI.getNumOperands() + MI.getNumMemOperands() + 2);
|
|
HashComponents.push_back(MI.getOpcode());
|
|
HashComponents.push_back(MI.getFlags());
|
|
for (const MachineOperand &MO : MI.operands()) {
|
|
if (!HashVRegs && MO.isReg() && MO.isDef() &&
|
|
Register::isVirtualRegister(MO.getReg()))
|
|
continue; // Skip virtual register defs.
|
|
|
|
if (MO.isCPI()) {
|
|
HashComponents.push_back(stable_hash_combine(
|
|
MO.getType(), MO.getTargetFlags(), MO.getIndex()));
|
|
continue;
|
|
}
|
|
|
|
stable_hash StableHash = stableHashValue(MO);
|
|
if (!StableHash)
|
|
return 0;
|
|
HashComponents.push_back(StableHash);
|
|
}
|
|
|
|
for (const auto *Op : MI.memoperands()) {
|
|
if (!HashMemOperands)
|
|
break;
|
|
HashComponents.push_back(static_cast<unsigned>(Op->getSize()));
|
|
HashComponents.push_back(static_cast<unsigned>(Op->getFlags()));
|
|
HashComponents.push_back(static_cast<unsigned>(Op->getOffset()));
|
|
HashComponents.push_back(static_cast<unsigned>(Op->getOrdering()));
|
|
HashComponents.push_back(static_cast<unsigned>(Op->getAddrSpace()));
|
|
HashComponents.push_back(static_cast<unsigned>(Op->getSyncScopeID()));
|
|
HashComponents.push_back(static_cast<unsigned>(Op->getBaseAlign().value()));
|
|
HashComponents.push_back(static_cast<unsigned>(Op->getFailureOrdering()));
|
|
}
|
|
|
|
return stable_hash_combine_range(HashComponents.begin(),
|
|
HashComponents.end());
|
|
}
|