blob: 0803c2b8b85a3445fb2511767abae5d190b9377c [file] [log] [blame]
//===- 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->getSuccessOrdering()));
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());
}