mirror of
https://github.com/hedge-dev/XenonRecomp.git
synced 2025-11-04 23:07:06 +00:00
Initial Commit
This commit is contained in:
45
thirdparty/capstone/suite/synctools/tablegen/gen-tablegen-arch.sh
vendored
Normal file
45
thirdparty/capstone/suite/synctools/tablegen/gen-tablegen-arch.sh
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
#!/bin/sh
|
||||
# Generate raw .inc files for non-x86 architectures of Capstone, by Nguyen Anh Quynh
|
||||
|
||||
# Syntax: gen-tablegen-arch.sh <path-to-llvm-tblgen> <arch>
|
||||
|
||||
# Example: ./gen-tablegen-arch.sh ~/projects/llvm/7.0.1/build/bin ARM
|
||||
|
||||
TBLGEN_PATH=$1
|
||||
DIR_TD=$2
|
||||
ARCH=$2
|
||||
|
||||
echo "Using llvm-tblgen from ${TBLGEN_PATH}"
|
||||
|
||||
echo "Generating ${ARCH}GenInstrInfo.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-instr-info -I include -I ${DIR_TD} ${DIR_TD}/${ARCH}.td -o ${ARCH}GenInstrInfo.inc
|
||||
|
||||
echo "Generating ${ARCH}GenRegisterInfo.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-register-info -I include -I ${DIR_TD} ${DIR_TD}/${ARCH}.td -o ${ARCH}GenRegisterInfo.inc
|
||||
|
||||
echo "Generating ${ARCH}GenAsmMatcher.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-asm-matcher -I include -I ${DIR_TD} ${DIR_TD}/${ARCH}.td -o ${ARCH}GenAsmMatcher.inc
|
||||
|
||||
echo "Generating ${ARCH}GenDisassemblerTables.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-disassembler -I include -I ${DIR_TD} ${DIR_TD}/${ARCH}.td -o ${ARCH}GenDisassemblerTables.inc
|
||||
|
||||
echo "Generating ${ARCH}GenAsmWriter.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-asm-writer -I include -I ${DIR_TD} ${DIR_TD}/${ARCH}.td -o ${ARCH}GenAsmWriter.inc
|
||||
|
||||
echo "Generating ${ARCH}GenSubtargetInfo.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-subtarget -I include -I ${DIR_TD} ${DIR_TD}/${ARCH}.td -o ${ARCH}GenSubtargetInfo.inc
|
||||
|
||||
case $2 in
|
||||
ARM)
|
||||
# for ARM only
|
||||
echo "Generating ${ARCH}GenAsmWriter-digit.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-asm-writer -I include -I ${DIR_TD} ${DIR_TD}/${ARCH}-digit.td -o ${ARCH}GenAsmWriter-digit.inc
|
||||
echo "Generating ${ARCH}GenSystemRegister.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-searchable-tables -I include -I ${DIR_TD} ${DIR_TD}/${ARCH}.td -o ${ARCH}GenSystemRegister.inc
|
||||
;;
|
||||
AArch64)
|
||||
echo "Generating ${ARCH}GenSystemOperands.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-searchable-tables -I include -I ${DIR_TD} ${DIR_TD}/${ARCH}.td -o ${ARCH}GenSystemOperands.inc
|
||||
;;
|
||||
esac
|
||||
|
||||
32
thirdparty/capstone/suite/synctools/tablegen/gen-tablegen-full.sh
vendored
Normal file
32
thirdparty/capstone/suite/synctools/tablegen/gen-tablegen-full.sh
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
#!/bin/sh
|
||||
# Generate raw X86*.inc files for Capstone, by Nguyen Anh Quynh
|
||||
|
||||
# Syntax: gen-tablegen-full.sh <path-to-llvm-tblgen> <path-to-X86-td-files>
|
||||
|
||||
# Example: ./gen-tablegen-full.sh ~/projects/llvm/7.0.1/build/bin X86
|
||||
|
||||
#TBLGEN_PATH=~/projects/llvm/7.0.1/build/bin
|
||||
TBLGEN_PATH=$1
|
||||
#DIR_TD="X86"
|
||||
DIR_TD=$2
|
||||
|
||||
echo "Using llvm-tblgen from ${TBLGEN_PATH}"
|
||||
|
||||
echo "Generating X86GenInstrInfo.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-instr-info -I include -I ${DIR_TD} ${DIR_TD}/X86.td -o X86GenInstrInfo.inc
|
||||
|
||||
echo "Generating X86GenRegisterInfo.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-register-info -I include -I ${DIR_TD} ${DIR_TD}/X86.td -o X86GenRegisterInfo.inc
|
||||
|
||||
echo "Generating X86GenAsmMatcher.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-asm-matcher -I include -I ${DIR_TD} ${DIR_TD}/X86.td -o X86GenAsmMatcher.inc
|
||||
|
||||
echo "Generating X86GenDisassemblerTables.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-disassembler -I include -I ${DIR_TD} ${DIR_TD}/X86.td -o X86GenDisassemblerTables.inc
|
||||
|
||||
echo "Generating X86GenAsmWriter1.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-asm-writer -asmwriternum=1 -I include -I ${DIR_TD} ${DIR_TD}/X86.td -o X86GenAsmWriter1.inc
|
||||
|
||||
echo "Generating X86GenAsmWriter.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-asm-writer -I include -I ${DIR_TD} ${DIR_TD}/X86.td -o X86GenAsmWriter.inc
|
||||
|
||||
28
thirdparty/capstone/suite/synctools/tablegen/gen-tablegen-reduce.sh
vendored
Normal file
28
thirdparty/capstone/suite/synctools/tablegen/gen-tablegen-reduce.sh
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
#!/bin/sh
|
||||
# Generate raw X86*reduce.inc files for Capstone, by Nguyen Anh Quynh
|
||||
|
||||
# Syntax: gen-tablegen-reduce.sh <path-to-llvm-tblgen> X86
|
||||
# Example: ./gen-tablegen-reduce.sh ~/projects/llvm/7.0.1/build/bin X86
|
||||
|
||||
#TBLGEN_PATH=~/projects/llvm/7.0.1/build/bin
|
||||
TBLGEN_PATH=$1
|
||||
#DIR_TD="X86"
|
||||
DIR_TD=$2
|
||||
|
||||
echo "Using llvm-tblgen from ${TBLGEN_PATH}"
|
||||
|
||||
echo "Generating X86GenAsmMatcher_reduce.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-asm-matcher -I include -I ${DIR_TD} ${DIR_TD}/X86_reduce.td -o X86GenAsmMatcher_reduce.inc
|
||||
|
||||
echo "Generating GenInstrInfo_reduce.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-instr-info -I include -I ${DIR_TD} ${DIR_TD}/X86_reduce.td -o X86GenInstrInfo_reduce.inc
|
||||
|
||||
echo "Generating X86GenDisassemblerTables_reduce.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-disassembler -I include -I ${DIR_TD} ${DIR_TD}/X86_reduce.td -o X86GenDisassemblerTables_reduce.inc
|
||||
|
||||
echo "Generating X86GenAsmWriter1_reduce.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-asm-writer -asmwriternum=1 -I include -I ${DIR_TD} ${DIR_TD}/X86_reduce.td -o X86GenAsmWriter1_reduce.inc
|
||||
|
||||
echo "Generating X86GenAsmWriter_reduce.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-asm-writer -I include -I ${DIR_TD} ${DIR_TD}/X86_reduce.td -o X86GenAsmWriter_reduce.inc
|
||||
|
||||
47
thirdparty/capstone/suite/synctools/tablegen/gen-tablegen.sh
vendored
Normal file
47
thirdparty/capstone/suite/synctools/tablegen/gen-tablegen.sh
vendored
Normal file
@@ -0,0 +1,47 @@
|
||||
#!/bin/sh
|
||||
# Generate raw X86*.inc files for Capstone, by Nguyen Anh Quynh
|
||||
# This combines both -full & -reduce scripts, so we keep it here for reference only.
|
||||
|
||||
# Syntax: gen-tablegen.sh <path-to-llvm-tblgen>
|
||||
# Example: ./gen-tablegen.sh ~/projects/llvm/7.0.1/build/bin
|
||||
|
||||
#TBLGEN_PATH=~/projects/llvm/7.0.1/build/bin
|
||||
TBLGEN_PATH=$1
|
||||
|
||||
echo "Using llvm-tblgen from ${TBLGEN_PATH}"
|
||||
|
||||
echo "Generating X86GenInstrInfo.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-instr-info -I include -I X86 X86/X86.td -o X86GenInstrInfo.inc
|
||||
|
||||
echo "Generating X86GenRegisterInfo.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-register-info -I include -I X86 X86/X86.td -o X86GenRegisterInfo.inc
|
||||
|
||||
echo "Generating X86GenAsmMatcher.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-asm-matcher -I include -I X86 X86/X86.td -o X86GenAsmMatcher.inc
|
||||
|
||||
echo "Generating X86GenDisassemblerTables.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-disassembler -I include -I X86 X86/X86.td -o X86GenDisassemblerTables.inc
|
||||
|
||||
echo "Generating X86GenAsmWriter1.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-asm-writer -asmwriternum=1 -I include -I X86 X86/X86.td -o X86GenAsmWriter1.inc
|
||||
|
||||
echo "Generating X86GenAsmWriter.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-asm-writer -I include -I X86 X86/X86.td -o X86GenAsmWriter.inc
|
||||
|
||||
|
||||
echo "Generating X86GenAsmMatcher_reduce.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-asm-matcher -I include -I X86 X86/X86_reduce.td -o X86GenAsmMatcher_reduce.inc
|
||||
|
||||
echo "Generating GenInstrInfo_reduce.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-instr-info -I include -I X86 X86/X86_reduce.td -o X86GenInstrInfo_reduce.inc
|
||||
|
||||
echo "Generating X86GenDisassemblerTables_reduce.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-disassembler -I include -I X86 X86/X86_reduce.td -o X86GenDisassemblerTables_reduce.inc
|
||||
|
||||
echo "Generating X86GenAsmWriter1_reduce.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-asm-writer -asmwriternum=1 -I include -I X86 X86/X86_reduce.td -o X86GenAsmWriter1_reduce.inc
|
||||
|
||||
echo "Generating X86GenAsmWriter.inc"
|
||||
$TBLGEN_PATH/llvm-tblgen -gen-asm-writer -I include -I X86 X86/X86_reduce.td -o X86GenAsmWriter_reduce.inc
|
||||
|
||||
|
||||
408
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/AccelTable.h
vendored
Normal file
408
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/AccelTable.h
vendored
Normal file
@@ -0,0 +1,408 @@
|
||||
//==- include/llvm/CodeGen/AccelTable.h - Accelerator Tables -----*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// This file contains support for writing accelerator tables.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_ACCELTABLE_H
|
||||
#define LLVM_CODEGEN_ACCELTABLE_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/BinaryFormat/Dwarf.h"
|
||||
#include "llvm/CodeGen/DIE.h"
|
||||
#include "llvm/CodeGen/DwarfStringPoolEntry.h"
|
||||
#include "llvm/MC/MCSymbol.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/DJB.h"
|
||||
#include "llvm/Support/Debug.h"
|
||||
#include "llvm/Support/Format.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
|
||||
/// \file
|
||||
/// The DWARF and Apple accelerator tables are an indirect hash table optimized
|
||||
/// for null lookup rather than access to known data. The Apple accelerator
|
||||
/// tables are a precursor of the newer DWARF v5 accelerator tables. Both
|
||||
/// formats share common design ideas.
|
||||
///
|
||||
/// The Apple accelerator table are output into an on-disk format that looks
|
||||
/// like this:
|
||||
///
|
||||
/// .------------------.
|
||||
/// | HEADER |
|
||||
/// |------------------|
|
||||
/// | BUCKETS |
|
||||
/// |------------------|
|
||||
/// | HASHES |
|
||||
/// |------------------|
|
||||
/// | OFFSETS |
|
||||
/// |------------------|
|
||||
/// | DATA |
|
||||
/// `------------------'
|
||||
///
|
||||
/// The header contains a magic number, version, type of hash function,
|
||||
/// the number of buckets, total number of hashes, and room for a special struct
|
||||
/// of data and the length of that struct.
|
||||
///
|
||||
/// The buckets contain an index (e.g. 6) into the hashes array. The hashes
|
||||
/// section contains all of the 32-bit hash values in contiguous memory, and the
|
||||
/// offsets contain the offset into the data area for the particular hash.
|
||||
///
|
||||
/// For a lookup example, we could hash a function name and take it modulo the
|
||||
/// number of buckets giving us our bucket. From there we take the bucket value
|
||||
/// as an index into the hashes table and look at each successive hash as long
|
||||
/// as the hash value is still the same modulo result (bucket value) as earlier.
|
||||
/// If we have a match we look at that same entry in the offsets table and grab
|
||||
/// the offset in the data for our final match.
|
||||
///
|
||||
/// The DWARF v5 accelerator table consists of zero or more name indices that
|
||||
/// are output into an on-disk format that looks like this:
|
||||
///
|
||||
/// .------------------.
|
||||
/// | HEADER |
|
||||
/// |------------------|
|
||||
/// | CU LIST |
|
||||
/// |------------------|
|
||||
/// | LOCAL TU LIST |
|
||||
/// |------------------|
|
||||
/// | FOREIGN TU LIST |
|
||||
/// |------------------|
|
||||
/// | HASH TABLE |
|
||||
/// |------------------|
|
||||
/// | NAME TABLE |
|
||||
/// |------------------|
|
||||
/// | ABBREV TABLE |
|
||||
/// |------------------|
|
||||
/// | ENTRY POOL |
|
||||
/// `------------------'
|
||||
///
|
||||
/// For the full documentation please refer to the DWARF 5 standard.
|
||||
///
|
||||
///
|
||||
/// This file defines the class template AccelTable, which is represents an
|
||||
/// abstract view of an Accelerator table, without any notion of an on-disk
|
||||
/// layout. This class is parameterized by an entry type, which should derive
|
||||
/// from AccelTableData. This is the type of individual entries in the table,
|
||||
/// and it should store the data necessary to emit them. AppleAccelTableData is
|
||||
/// the base class for Apple Accelerator Table entries, which have a uniform
|
||||
/// structure based on a sequence of Atoms. There are different sub-classes
|
||||
/// derived from AppleAccelTable, which differ in the set of Atoms and how they
|
||||
/// obtain their values.
|
||||
///
|
||||
/// An Apple Accelerator Table can be serialized by calling emitAppleAccelTable
|
||||
/// function.
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class AsmPrinter;
|
||||
class DwarfCompileUnit;
|
||||
class DwarfDebug;
|
||||
|
||||
/// Interface which the different types of accelerator table data have to
|
||||
/// conform. It serves as a base class for different values of the template
|
||||
/// argument of the AccelTable class template.
|
||||
class AccelTableData {
|
||||
public:
|
||||
virtual ~AccelTableData() = default;
|
||||
|
||||
bool operator<(const AccelTableData &Other) const {
|
||||
return order() < Other.order();
|
||||
}
|
||||
|
||||
// Subclasses should implement:
|
||||
// static uint32_t hash(StringRef Name);
|
||||
|
||||
#ifndef NDEBUG
|
||||
virtual void print(raw_ostream &OS) const = 0;
|
||||
#endif
|
||||
protected:
|
||||
virtual uint64_t order() const = 0;
|
||||
};
|
||||
|
||||
/// A base class holding non-template-dependant functionality of the AccelTable
|
||||
/// class. Clients should not use this class directly but rather instantiate
|
||||
/// AccelTable with a type derived from AccelTableData.
|
||||
class AccelTableBase {
|
||||
public:
|
||||
using HashFn = uint32_t(StringRef);
|
||||
|
||||
/// Represents a group of entries with identical name (and hence, hash value).
|
||||
struct HashData {
|
||||
DwarfStringPoolEntryRef Name;
|
||||
uint32_t HashValue;
|
||||
std::vector<AccelTableData *> Values;
|
||||
MCSymbol *Sym;
|
||||
|
||||
HashData(DwarfStringPoolEntryRef Name, HashFn *Hash)
|
||||
: Name(Name), HashValue(Hash(Name.getString())) {}
|
||||
|
||||
#ifndef NDEBUG
|
||||
void print(raw_ostream &OS) const;
|
||||
void dump() const { print(dbgs()); }
|
||||
#endif
|
||||
};
|
||||
using HashList = std::vector<HashData *>;
|
||||
using BucketList = std::vector<HashList>;
|
||||
|
||||
protected:
|
||||
/// Allocator for HashData and Values.
|
||||
BumpPtrAllocator Allocator;
|
||||
|
||||
using StringEntries = StringMap<HashData, BumpPtrAllocator &>;
|
||||
StringEntries Entries;
|
||||
|
||||
HashFn *Hash;
|
||||
uint32_t BucketCount;
|
||||
uint32_t UniqueHashCount;
|
||||
|
||||
HashList Hashes;
|
||||
BucketList Buckets;
|
||||
|
||||
void computeBucketCount();
|
||||
|
||||
AccelTableBase(HashFn *Hash) : Entries(Allocator), Hash(Hash) {}
|
||||
|
||||
public:
|
||||
void finalize(AsmPrinter *Asm, StringRef Prefix);
|
||||
ArrayRef<HashList> getBuckets() const { return Buckets; }
|
||||
uint32_t getBucketCount() const { return BucketCount; }
|
||||
uint32_t getUniqueHashCount() const { return UniqueHashCount; }
|
||||
uint32_t getUniqueNameCount() const { return Entries.size(); }
|
||||
|
||||
#ifndef NDEBUG
|
||||
void print(raw_ostream &OS) const;
|
||||
void dump() const { print(dbgs()); }
|
||||
#endif
|
||||
|
||||
AccelTableBase(const AccelTableBase &) = delete;
|
||||
void operator=(const AccelTableBase &) = delete;
|
||||
};
|
||||
|
||||
/// This class holds an abstract representation of an Accelerator Table,
|
||||
/// consisting of a sequence of buckets, each bucket containing a sequence of
|
||||
/// HashData entries. The class is parameterized by the type of entries it
|
||||
/// holds. The type template parameter also defines the hash function to use for
|
||||
/// hashing names.
|
||||
template <typename DataT> class AccelTable : public AccelTableBase {
|
||||
public:
|
||||
AccelTable() : AccelTableBase(DataT::hash) {}
|
||||
|
||||
template <typename... Types>
|
||||
void addName(DwarfStringPoolEntryRef Name, Types &&... Args);
|
||||
};
|
||||
|
||||
template <typename AccelTableDataT>
|
||||
template <typename... Types>
|
||||
void AccelTable<AccelTableDataT>::addName(DwarfStringPoolEntryRef Name,
|
||||
Types &&... Args) {
|
||||
assert(Buckets.empty() && "Already finalized!");
|
||||
// If the string is in the list already then add this die to the list
|
||||
// otherwise add a new one.
|
||||
auto Iter = Entries.try_emplace(Name.getString(), Name, Hash).first;
|
||||
assert(Iter->second.Name == Name);
|
||||
Iter->second.Values.push_back(
|
||||
new (Allocator) AccelTableDataT(std::forward<Types>(Args)...));
|
||||
}
|
||||
|
||||
/// A base class for different implementations of Data classes for Apple
|
||||
/// Accelerator Tables. The columns in the table are defined by the static Atoms
|
||||
/// variable defined on the subclasses.
|
||||
class AppleAccelTableData : public AccelTableData {
|
||||
public:
|
||||
/// An Atom defines the form of the data in an Apple accelerator table.
|
||||
/// Conceptually it is a column in the accelerator consisting of a type and a
|
||||
/// specification of the form of its data.
|
||||
struct Atom {
|
||||
/// Atom Type.
|
||||
const uint16_t Type;
|
||||
/// DWARF Form.
|
||||
const uint16_t Form;
|
||||
|
||||
constexpr Atom(uint16_t Type, uint16_t Form) : Type(Type), Form(Form) {}
|
||||
|
||||
#ifndef NDEBUG
|
||||
void print(raw_ostream &OS) const;
|
||||
void dump() const { print(dbgs()); }
|
||||
#endif
|
||||
};
|
||||
// Subclasses should define:
|
||||
// static constexpr Atom Atoms[];
|
||||
|
||||
virtual void emit(AsmPrinter *Asm) const = 0;
|
||||
|
||||
static uint32_t hash(StringRef Buffer) { return djbHash(Buffer); }
|
||||
};
|
||||
|
||||
/// The Data class implementation for DWARF v5 accelerator table. Unlike the
|
||||
/// Apple Data classes, this class is just a DIE wrapper, and does not know to
|
||||
/// serialize itself. The complete serialization logic is in the
|
||||
/// emitDWARF5AccelTable function.
|
||||
class DWARF5AccelTableData : public AccelTableData {
|
||||
public:
|
||||
static uint32_t hash(StringRef Name) { return caseFoldingDjbHash(Name); }
|
||||
|
||||
DWARF5AccelTableData(const DIE &Die) : Die(Die) {}
|
||||
|
||||
#ifndef NDEBUG
|
||||
void print(raw_ostream &OS) const override;
|
||||
#endif
|
||||
|
||||
const DIE &getDie() const { return Die; }
|
||||
uint64_t getDieOffset() const { return Die.getOffset(); }
|
||||
unsigned getDieTag() const { return Die.getTag(); }
|
||||
|
||||
protected:
|
||||
const DIE &Die;
|
||||
|
||||
uint64_t order() const override { return Die.getOffset(); }
|
||||
};
|
||||
|
||||
class DWARF5AccelTableStaticData : public AccelTableData {
|
||||
public:
|
||||
static uint32_t hash(StringRef Name) { return caseFoldingDjbHash(Name); }
|
||||
|
||||
DWARF5AccelTableStaticData(uint64_t DieOffset, unsigned DieTag,
|
||||
unsigned CUIndex)
|
||||
: DieOffset(DieOffset), DieTag(DieTag), CUIndex(CUIndex) {}
|
||||
|
||||
#ifndef NDEBUG
|
||||
void print(raw_ostream &OS) const override;
|
||||
#endif
|
||||
|
||||
uint64_t getDieOffset() const { return DieOffset; }
|
||||
unsigned getDieTag() const { return DieTag; }
|
||||
unsigned getCUIndex() const { return CUIndex; }
|
||||
|
||||
protected:
|
||||
uint64_t DieOffset;
|
||||
unsigned DieTag;
|
||||
unsigned CUIndex;
|
||||
|
||||
uint64_t order() const override { return DieOffset; }
|
||||
};
|
||||
|
||||
void emitAppleAccelTableImpl(AsmPrinter *Asm, AccelTableBase &Contents,
|
||||
StringRef Prefix, const MCSymbol *SecBegin,
|
||||
ArrayRef<AppleAccelTableData::Atom> Atoms);
|
||||
|
||||
/// Emit an Apple Accelerator Table consisting of entries in the specified
|
||||
/// AccelTable. The DataT template parameter should be derived from
|
||||
/// AppleAccelTableData.
|
||||
template <typename DataT>
|
||||
void emitAppleAccelTable(AsmPrinter *Asm, AccelTable<DataT> &Contents,
|
||||
StringRef Prefix, const MCSymbol *SecBegin) {
|
||||
static_assert(std::is_convertible<DataT *, AppleAccelTableData *>::value, "");
|
||||
emitAppleAccelTableImpl(Asm, Contents, Prefix, SecBegin, DataT::Atoms);
|
||||
}
|
||||
|
||||
void emitDWARF5AccelTable(AsmPrinter *Asm,
|
||||
AccelTable<DWARF5AccelTableData> &Contents,
|
||||
const DwarfDebug &DD,
|
||||
ArrayRef<std::unique_ptr<DwarfCompileUnit>> CUs);
|
||||
|
||||
void emitDWARF5AccelTable(
|
||||
AsmPrinter *Asm, AccelTable<DWARF5AccelTableStaticData> &Contents,
|
||||
ArrayRef<MCSymbol *> CUs,
|
||||
llvm::function_ref<unsigned(const DWARF5AccelTableStaticData &)>
|
||||
getCUIndexForEntry);
|
||||
|
||||
/// Accelerator table data implementation for simple Apple accelerator tables
|
||||
/// with just a DIE reference.
|
||||
class AppleAccelTableOffsetData : public AppleAccelTableData {
|
||||
public:
|
||||
AppleAccelTableOffsetData(const DIE &D) : Die(D) {}
|
||||
|
||||
void emit(AsmPrinter *Asm) const override;
|
||||
|
||||
static constexpr Atom Atoms[] = {
|
||||
Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4)};
|
||||
|
||||
#ifndef NDEBUG
|
||||
void print(raw_ostream &OS) const override;
|
||||
#endif
|
||||
protected:
|
||||
uint64_t order() const override { return Die.getOffset(); }
|
||||
|
||||
const DIE &Die;
|
||||
};
|
||||
|
||||
/// Accelerator table data implementation for Apple type accelerator tables.
|
||||
class AppleAccelTableTypeData : public AppleAccelTableOffsetData {
|
||||
public:
|
||||
AppleAccelTableTypeData(const DIE &D) : AppleAccelTableOffsetData(D) {}
|
||||
|
||||
void emit(AsmPrinter *Asm) const override;
|
||||
|
||||
static constexpr Atom Atoms[] = {
|
||||
Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4),
|
||||
Atom(dwarf::DW_ATOM_die_tag, dwarf::DW_FORM_data2),
|
||||
Atom(dwarf::DW_ATOM_type_flags, dwarf::DW_FORM_data1)};
|
||||
|
||||
#ifndef NDEBUG
|
||||
void print(raw_ostream &OS) const override;
|
||||
#endif
|
||||
};
|
||||
|
||||
/// Accelerator table data implementation for simple Apple accelerator tables
|
||||
/// with a DIE offset but no actual DIE pointer.
|
||||
class AppleAccelTableStaticOffsetData : public AppleAccelTableData {
|
||||
public:
|
||||
AppleAccelTableStaticOffsetData(uint32_t Offset) : Offset(Offset) {}
|
||||
|
||||
void emit(AsmPrinter *Asm) const override;
|
||||
|
||||
static constexpr Atom Atoms[] = {
|
||||
Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4)};
|
||||
|
||||
#ifndef NDEBUG
|
||||
void print(raw_ostream &OS) const override;
|
||||
#endif
|
||||
protected:
|
||||
uint64_t order() const override { return Offset; }
|
||||
|
||||
uint32_t Offset;
|
||||
};
|
||||
|
||||
/// Accelerator table data implementation for type accelerator tables with
|
||||
/// a DIE offset but no actual DIE pointer.
|
||||
class AppleAccelTableStaticTypeData : public AppleAccelTableStaticOffsetData {
|
||||
public:
|
||||
AppleAccelTableStaticTypeData(uint32_t Offset, uint16_t Tag,
|
||||
bool ObjCClassIsImplementation,
|
||||
uint32_t QualifiedNameHash)
|
||||
: AppleAccelTableStaticOffsetData(Offset),
|
||||
QualifiedNameHash(QualifiedNameHash), Tag(Tag),
|
||||
ObjCClassIsImplementation(ObjCClassIsImplementation) {}
|
||||
|
||||
void emit(AsmPrinter *Asm) const override;
|
||||
|
||||
static constexpr Atom Atoms[] = {
|
||||
Atom(dwarf::DW_ATOM_die_offset, dwarf::DW_FORM_data4),
|
||||
Atom(dwarf::DW_ATOM_die_tag, dwarf::DW_FORM_data2),
|
||||
Atom(5, dwarf::DW_FORM_data1), Atom(6, dwarf::DW_FORM_data4)};
|
||||
|
||||
#ifndef NDEBUG
|
||||
void print(raw_ostream &OS) const override;
|
||||
#endif
|
||||
protected:
|
||||
uint64_t order() const override { return Offset; }
|
||||
|
||||
uint32_t QualifiedNameHash;
|
||||
uint16_t Tag;
|
||||
bool ObjCClassIsImplementation;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_ACCELTABLE_H
|
||||
144
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/Analysis.h
vendored
Normal file
144
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/Analysis.h
vendored
Normal file
@@ -0,0 +1,144 @@
|
||||
//===- CodeGen/Analysis.h - CodeGen LLVM IR Analysis Utilities --*- 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 file declares several CodeGen-specific LLVM IR analysis utilities.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_ANALYSIS_H
|
||||
#define LLVM_CODEGEN_ANALYSIS_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/CodeGen/ISDOpcodes.h"
|
||||
#include "llvm/IR/InlineAsm.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/Support/CodeGen.h"
|
||||
|
||||
namespace llvm {
|
||||
class GlobalValue;
|
||||
class LLT;
|
||||
class MachineBasicBlock;
|
||||
class MachineFunction;
|
||||
class TargetLoweringBase;
|
||||
class TargetLowering;
|
||||
class TargetMachine;
|
||||
struct EVT;
|
||||
|
||||
/// Compute the linearized index of a member in a nested
|
||||
/// aggregate/struct/array.
|
||||
///
|
||||
/// Given an LLVM IR aggregate type and a sequence of insertvalue or
|
||||
/// extractvalue indices that identify a member, return the linearized index of
|
||||
/// the start of the member, i.e the number of element in memory before the
|
||||
/// sought one. This is disconnected from the number of bytes.
|
||||
///
|
||||
/// \param Ty is the type indexed by \p Indices.
|
||||
/// \param Indices is an optional pointer in the indices list to the current
|
||||
/// index.
|
||||
/// \param IndicesEnd is the end of the indices list.
|
||||
/// \param CurIndex is the current index in the recursion.
|
||||
///
|
||||
/// \returns \p CurIndex plus the linear index in \p Ty the indices list.
|
||||
unsigned ComputeLinearIndex(Type *Ty,
|
||||
const unsigned *Indices,
|
||||
const unsigned *IndicesEnd,
|
||||
unsigned CurIndex = 0);
|
||||
|
||||
inline unsigned ComputeLinearIndex(Type *Ty,
|
||||
ArrayRef<unsigned> Indices,
|
||||
unsigned CurIndex = 0) {
|
||||
return ComputeLinearIndex(Ty, Indices.begin(), Indices.end(), CurIndex);
|
||||
}
|
||||
|
||||
/// ComputeValueVTs - Given an LLVM IR type, compute a sequence of
|
||||
/// EVTs that represent all the individual underlying
|
||||
/// non-aggregate types that comprise it.
|
||||
///
|
||||
/// If Offsets is non-null, it points to a vector to be filled in
|
||||
/// with the in-memory offsets of each of the individual values.
|
||||
///
|
||||
void ComputeValueVTs(const TargetLowering &TLI, const DataLayout &DL, Type *Ty,
|
||||
SmallVectorImpl<EVT> &ValueVTs,
|
||||
SmallVectorImpl<uint64_t> *Offsets = nullptr,
|
||||
uint64_t StartingOffset = 0);
|
||||
|
||||
/// Variant of ComputeValueVTs that also produces the memory VTs.
|
||||
void ComputeValueVTs(const TargetLowering &TLI, const DataLayout &DL, Type *Ty,
|
||||
SmallVectorImpl<EVT> &ValueVTs,
|
||||
SmallVectorImpl<EVT> *MemVTs,
|
||||
SmallVectorImpl<uint64_t> *Offsets = nullptr,
|
||||
uint64_t StartingOffset = 0);
|
||||
|
||||
/// computeValueLLTs - Given an LLVM IR type, compute a sequence of
|
||||
/// LLTs that represent all the individual underlying
|
||||
/// non-aggregate types that comprise it.
|
||||
///
|
||||
/// If Offsets is non-null, it points to a vector to be filled in
|
||||
/// with the in-memory offsets of each of the individual values.
|
||||
///
|
||||
void computeValueLLTs(const DataLayout &DL, Type &Ty,
|
||||
SmallVectorImpl<LLT> &ValueTys,
|
||||
SmallVectorImpl<uint64_t> *Offsets = nullptr,
|
||||
uint64_t StartingOffset = 0);
|
||||
|
||||
/// ExtractTypeInfo - Returns the type info, possibly bitcast, encoded in V.
|
||||
GlobalValue *ExtractTypeInfo(Value *V);
|
||||
|
||||
/// getFCmpCondCode - Return the ISD condition code corresponding to
|
||||
/// the given LLVM IR floating-point condition code. This includes
|
||||
/// consideration of global floating-point math flags.
|
||||
///
|
||||
ISD::CondCode getFCmpCondCode(FCmpInst::Predicate Pred);
|
||||
|
||||
/// getFCmpCodeWithoutNaN - Given an ISD condition code comparing floats,
|
||||
/// return the equivalent code if we're allowed to assume that NaNs won't occur.
|
||||
ISD::CondCode getFCmpCodeWithoutNaN(ISD::CondCode CC);
|
||||
|
||||
/// getICmpCondCode - Return the ISD condition code corresponding to
|
||||
/// the given LLVM IR integer condition code.
|
||||
ISD::CondCode getICmpCondCode(ICmpInst::Predicate Pred);
|
||||
|
||||
/// getICmpCondCode - Return the LLVM IR integer condition code
|
||||
/// corresponding to the given ISD integer condition code.
|
||||
ICmpInst::Predicate getICmpCondCode(ISD::CondCode Pred);
|
||||
|
||||
/// Test if the given instruction is in a position to be optimized
|
||||
/// with a tail-call. This roughly means that it's in a block with
|
||||
/// a return and there's nothing that needs to be scheduled
|
||||
/// between it and the return.
|
||||
///
|
||||
/// This function only tests target-independent requirements.
|
||||
bool isInTailCallPosition(const CallBase &Call, const TargetMachine &TM);
|
||||
|
||||
/// Test if given that the input instruction is in the tail call position, if
|
||||
/// there is an attribute mismatch between the caller and the callee that will
|
||||
/// inhibit tail call optimizations.
|
||||
/// \p AllowDifferingSizes is an output parameter which, if forming a tail call
|
||||
/// is permitted, determines whether it's permitted only if the size of the
|
||||
/// caller's and callee's return types match exactly.
|
||||
bool attributesPermitTailCall(const Function *F, const Instruction *I,
|
||||
const ReturnInst *Ret,
|
||||
const TargetLoweringBase &TLI,
|
||||
bool *AllowDifferingSizes = nullptr);
|
||||
|
||||
/// Test if given that the input instruction is in the tail call position if the
|
||||
/// return type or any attributes of the function will inhibit tail call
|
||||
/// optimization.
|
||||
bool returnTypeIsEligibleForTailCall(const Function *F, const Instruction *I,
|
||||
const ReturnInst *Ret,
|
||||
const TargetLoweringBase &TLI);
|
||||
|
||||
DenseMap<const MachineBasicBlock *, int>
|
||||
getEHScopeMembership(const MachineFunction &MF);
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
||||
103
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/AntiDepBreaker.h
vendored
Normal file
103
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/AntiDepBreaker.h
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
//===- llvm/CodeGen/AntiDepBreaker.h - Anti-Dependence Breaking -*- 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 file implements the AntiDepBreaker class, which implements
|
||||
// anti-dependence breaking heuristics for post-register-allocation scheduling.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_ANTIDEPBREAKER_H
|
||||
#define LLVM_CODEGEN_ANTIDEPBREAKER_H
|
||||
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
#include "llvm/CodeGen/TargetSubtargetInfo.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class RegisterClassInfo;
|
||||
|
||||
/// This class works in conjunction with the post-RA scheduler to rename
|
||||
/// registers to break register anti-dependencies (WAR hazards).
|
||||
class AntiDepBreaker {
|
||||
public:
|
||||
using DbgValueVector =
|
||||
std::vector<std::pair<MachineInstr *, MachineInstr *>>;
|
||||
|
||||
virtual ~AntiDepBreaker();
|
||||
|
||||
/// Initialize anti-dep breaking for a new basic block.
|
||||
virtual void StartBlock(MachineBasicBlock *BB) = 0;
|
||||
|
||||
/// Identify anti-dependencies within a basic-block region and break them by
|
||||
/// renaming registers. Return the number of anti-dependencies broken.
|
||||
virtual unsigned BreakAntiDependencies(const std::vector<SUnit> &SUnits,
|
||||
MachineBasicBlock::iterator Begin,
|
||||
MachineBasicBlock::iterator End,
|
||||
unsigned InsertPosIndex,
|
||||
DbgValueVector &DbgValues) = 0;
|
||||
|
||||
/// Update liveness information to account for the current
|
||||
/// instruction, which will not be scheduled.
|
||||
virtual void Observe(MachineInstr &MI, unsigned Count,
|
||||
unsigned InsertPosIndex) = 0;
|
||||
|
||||
/// Finish anti-dep breaking for a basic block.
|
||||
virtual void FinishBlock() = 0;
|
||||
|
||||
/// Update DBG_VALUE or DBG_PHI if dependency breaker is updating
|
||||
/// other machine instruction to use NewReg.
|
||||
void UpdateDbgValue(MachineInstr &MI, unsigned OldReg, unsigned NewReg) {
|
||||
if (MI.isDebugValue()) {
|
||||
if (MI.getDebugOperand(0).isReg() &&
|
||||
MI.getDebugOperand(0).getReg() == OldReg)
|
||||
MI.getDebugOperand(0).setReg(NewReg);
|
||||
} else if (MI.isDebugPHI()) {
|
||||
if (MI.getOperand(0).isReg() &&
|
||||
MI.getOperand(0).getReg() == OldReg)
|
||||
MI.getOperand(0).setReg(NewReg);
|
||||
} else {
|
||||
llvm_unreachable("MI is not DBG_VALUE / DBG_PHI!");
|
||||
}
|
||||
}
|
||||
|
||||
/// Update all DBG_VALUE instructions that may be affected by the dependency
|
||||
/// breaker's update of ParentMI to use NewReg.
|
||||
void UpdateDbgValues(const DbgValueVector &DbgValues, MachineInstr *ParentMI,
|
||||
unsigned OldReg, unsigned NewReg) {
|
||||
// The following code is dependent on the order in which the DbgValues are
|
||||
// constructed in ScheduleDAGInstrs::buildSchedGraph.
|
||||
MachineInstr *PrevDbgMI = nullptr;
|
||||
for (const auto &DV : make_range(DbgValues.crbegin(), DbgValues.crend())) {
|
||||
MachineInstr *PrevMI = DV.second;
|
||||
if ((PrevMI == ParentMI) || (PrevMI == PrevDbgMI)) {
|
||||
MachineInstr *DbgMI = DV.first;
|
||||
UpdateDbgValue(*DbgMI, OldReg, NewReg);
|
||||
PrevDbgMI = DbgMI;
|
||||
} else if (PrevDbgMI) {
|
||||
break; // If no match and already found a DBG_VALUE, we're done.
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
AntiDepBreaker *createAggressiveAntiDepBreaker(
|
||||
MachineFunction &MFi, const RegisterClassInfo &RCI,
|
||||
TargetSubtargetInfo::RegClassVector &CriticalPathRCs);
|
||||
|
||||
AntiDepBreaker *createCriticalAntiDepBreaker(MachineFunction &MFi,
|
||||
const RegisterClassInfo &RCI);
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_ANTIDEPBREAKER_H
|
||||
816
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/AsmPrinter.h
vendored
Normal file
816
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/AsmPrinter.h
vendored
Normal file
@@ -0,0 +1,816 @@
|
||||
//===- llvm/CodeGen/AsmPrinter.h - AsmPrinter Framework ---------*- 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 file contains a class to be used as the base class for target specific
|
||||
// asm writers. This class primarily handles common functionality used by
|
||||
// all asm writers.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_ASMPRINTER_H
|
||||
#define LLVM_CODEGEN_ASMPRINTER_H
|
||||
|
||||
#include "llvm/ADT/MapVector.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/BinaryFormat/Dwarf.h"
|
||||
#include "llvm/CodeGen/AsmPrinterHandler.h"
|
||||
#include "llvm/CodeGen/DwarfStringPoolEntry.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/IR/InlineAsm.h"
|
||||
#include "llvm/IR/LLVMContext.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/SourceMgr.h"
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class BasicBlock;
|
||||
class BlockAddress;
|
||||
class Constant;
|
||||
class ConstantArray;
|
||||
class DataLayout;
|
||||
class DIE;
|
||||
class DIEAbbrev;
|
||||
class DwarfDebug;
|
||||
class GCMetadataPrinter;
|
||||
class GCStrategy;
|
||||
class GlobalObject;
|
||||
class GlobalValue;
|
||||
class GlobalVariable;
|
||||
class MachineBasicBlock;
|
||||
class MachineConstantPoolValue;
|
||||
class MachineDominatorTree;
|
||||
class MachineFunction;
|
||||
class MachineInstr;
|
||||
class MachineJumpTableInfo;
|
||||
class MachineLoopInfo;
|
||||
class MachineModuleInfo;
|
||||
class MachineOptimizationRemarkEmitter;
|
||||
class MCAsmInfo;
|
||||
class MCCFIInstruction;
|
||||
class MCContext;
|
||||
class MCExpr;
|
||||
class MCInst;
|
||||
class MCSection;
|
||||
class MCStreamer;
|
||||
class MCSubtargetInfo;
|
||||
class MCSymbol;
|
||||
class MCTargetOptions;
|
||||
class MDNode;
|
||||
class Module;
|
||||
class PseudoProbeHandler;
|
||||
class raw_ostream;
|
||||
class StackMaps;
|
||||
class StringRef;
|
||||
class TargetLoweringObjectFile;
|
||||
class TargetMachine;
|
||||
class Twine;
|
||||
|
||||
namespace remarks {
|
||||
class RemarkStreamer;
|
||||
}
|
||||
|
||||
/// This class is intended to be used as a driving class for all asm writers.
|
||||
class AsmPrinter : public MachineFunctionPass {
|
||||
public:
|
||||
/// Target machine description.
|
||||
TargetMachine &TM;
|
||||
|
||||
/// Target Asm Printer information.
|
||||
const MCAsmInfo *MAI;
|
||||
|
||||
/// This is the context for the output file that we are streaming. This owns
|
||||
/// all of the global MC-related objects for the generated translation unit.
|
||||
MCContext &OutContext;
|
||||
|
||||
/// This is the MCStreamer object for the file we are generating. This
|
||||
/// contains the transient state for the current translation unit that we are
|
||||
/// generating (such as the current section etc).
|
||||
std::unique_ptr<MCStreamer> OutStreamer;
|
||||
|
||||
/// The current machine function.
|
||||
MachineFunction *MF = nullptr;
|
||||
|
||||
/// This is a pointer to the current MachineModuleInfo.
|
||||
MachineModuleInfo *MMI = nullptr;
|
||||
|
||||
/// This is a pointer to the current MachineDominatorTree.
|
||||
MachineDominatorTree *MDT = nullptr;
|
||||
|
||||
/// This is a pointer to the current MachineLoopInfo.
|
||||
MachineLoopInfo *MLI = nullptr;
|
||||
|
||||
/// Optimization remark emitter.
|
||||
MachineOptimizationRemarkEmitter *ORE;
|
||||
|
||||
/// The symbol for the entry in __patchable_function_entires.
|
||||
MCSymbol *CurrentPatchableFunctionEntrySym = nullptr;
|
||||
|
||||
/// The symbol for the current function. This is recalculated at the beginning
|
||||
/// of each call to runOnMachineFunction().
|
||||
MCSymbol *CurrentFnSym = nullptr;
|
||||
|
||||
/// The symbol for the current function descriptor on AIX. This is created
|
||||
/// at the beginning of each call to SetupMachineFunction().
|
||||
MCSymbol *CurrentFnDescSym = nullptr;
|
||||
|
||||
/// The symbol used to represent the start of the current function for the
|
||||
/// purpose of calculating its size (e.g. using the .size directive). By
|
||||
/// default, this is equal to CurrentFnSym.
|
||||
MCSymbol *CurrentFnSymForSize = nullptr;
|
||||
|
||||
/// Map a basic block section ID to the begin and end symbols of that section
|
||||
/// which determine the section's range.
|
||||
struct MBBSectionRange {
|
||||
MCSymbol *BeginLabel, *EndLabel;
|
||||
};
|
||||
|
||||
MapVector<unsigned, MBBSectionRange> MBBSectionRanges;
|
||||
|
||||
/// Map global GOT equivalent MCSymbols to GlobalVariables and keep track of
|
||||
/// its number of uses by other globals.
|
||||
using GOTEquivUsePair = std::pair<const GlobalVariable *, unsigned>;
|
||||
MapVector<const MCSymbol *, GOTEquivUsePair> GlobalGOTEquivs;
|
||||
|
||||
/// struct HandlerInfo and Handlers permit users or target extended
|
||||
/// AsmPrinter to add their own handlers.
|
||||
struct HandlerInfo {
|
||||
std::unique_ptr<AsmPrinterHandler> Handler;
|
||||
StringRef TimerName;
|
||||
StringRef TimerDescription;
|
||||
StringRef TimerGroupName;
|
||||
StringRef TimerGroupDescription;
|
||||
|
||||
HandlerInfo(std::unique_ptr<AsmPrinterHandler> Handler, StringRef TimerName,
|
||||
StringRef TimerDescription, StringRef TimerGroupName,
|
||||
StringRef TimerGroupDescription)
|
||||
: Handler(std::move(Handler)), TimerName(TimerName),
|
||||
TimerDescription(TimerDescription), TimerGroupName(TimerGroupName),
|
||||
TimerGroupDescription(TimerGroupDescription) {}
|
||||
};
|
||||
|
||||
// Flags representing which CFI section is required for a function/module.
|
||||
enum class CFISection : unsigned {
|
||||
None = 0, ///< Do not emit either .eh_frame or .debug_frame
|
||||
EH = 1, ///< Emit .eh_frame
|
||||
Debug = 2 ///< Emit .debug_frame
|
||||
};
|
||||
|
||||
private:
|
||||
MCSymbol *CurrentFnEnd = nullptr;
|
||||
|
||||
/// Map a basic block section ID to the exception symbol associated with that
|
||||
/// section. Map entries are assigned and looked up via
|
||||
/// AsmPrinter::getMBBExceptionSym.
|
||||
DenseMap<unsigned, MCSymbol *> MBBSectionExceptionSyms;
|
||||
|
||||
// The symbol used to represent the start of the current BB section of the
|
||||
// function. This is used to calculate the size of the BB section.
|
||||
MCSymbol *CurrentSectionBeginSym = nullptr;
|
||||
|
||||
// The garbage collection metadata printer table.
|
||||
void *GCMetadataPrinters = nullptr; // Really a DenseMap.
|
||||
|
||||
/// Emit comments in assembly output if this is true.
|
||||
bool VerboseAsm;
|
||||
|
||||
/// Output stream for the stack usage file (i.e., .su file).
|
||||
std::unique_ptr<raw_fd_ostream> StackUsageStream;
|
||||
|
||||
static char ID;
|
||||
|
||||
protected:
|
||||
MCSymbol *CurrentFnBegin = nullptr;
|
||||
|
||||
/// A vector of all debug/EH info emitters we should use. This vector
|
||||
/// maintains ownership of the emitters.
|
||||
std::vector<HandlerInfo> Handlers;
|
||||
size_t NumUserHandlers = 0;
|
||||
|
||||
private:
|
||||
/// If generated on the fly this own the instance.
|
||||
std::unique_ptr<MachineDominatorTree> OwnedMDT;
|
||||
|
||||
/// If generated on the fly this own the instance.
|
||||
std::unique_ptr<MachineLoopInfo> OwnedMLI;
|
||||
|
||||
/// If the target supports dwarf debug info, this pointer is non-null.
|
||||
DwarfDebug *DD = nullptr;
|
||||
|
||||
/// A handler that supports pseudo probe emission with embedded inline
|
||||
/// context.
|
||||
PseudoProbeHandler *PP = nullptr;
|
||||
|
||||
/// CFISection type the module needs i.e. either .eh_frame or .debug_frame.
|
||||
CFISection ModuleCFISection = CFISection::None;
|
||||
|
||||
protected:
|
||||
explicit AsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer);
|
||||
|
||||
public:
|
||||
~AsmPrinter() override;
|
||||
|
||||
DwarfDebug *getDwarfDebug() { return DD; }
|
||||
DwarfDebug *getDwarfDebug() const { return DD; }
|
||||
|
||||
uint16_t getDwarfVersion() const;
|
||||
void setDwarfVersion(uint16_t Version);
|
||||
|
||||
bool isDwarf64() const;
|
||||
|
||||
/// Returns 4 for DWARF32 and 8 for DWARF64.
|
||||
unsigned int getDwarfOffsetByteSize() const;
|
||||
|
||||
/// Returns 4 for DWARF32 and 12 for DWARF64.
|
||||
unsigned int getUnitLengthFieldByteSize() const;
|
||||
|
||||
/// Returns information about the byte size of DW_FORM values.
|
||||
dwarf::FormParams getDwarfFormParams() const;
|
||||
|
||||
bool isPositionIndependent() const;
|
||||
|
||||
/// Return true if assembly output should contain comments.
|
||||
bool isVerbose() const { return VerboseAsm; }
|
||||
|
||||
/// Return a unique ID for the current function.
|
||||
unsigned getFunctionNumber() const;
|
||||
|
||||
/// Return symbol for the function pseudo stack if the stack frame is not a
|
||||
/// register based.
|
||||
virtual const MCSymbol *getFunctionFrameSymbol() const { return nullptr; }
|
||||
|
||||
MCSymbol *getFunctionBegin() const { return CurrentFnBegin; }
|
||||
MCSymbol *getFunctionEnd() const { return CurrentFnEnd; }
|
||||
|
||||
// Return the exception symbol associated with the MBB section containing a
|
||||
// given basic block.
|
||||
MCSymbol *getMBBExceptionSym(const MachineBasicBlock &MBB);
|
||||
|
||||
/// Return information about object file lowering.
|
||||
const TargetLoweringObjectFile &getObjFileLowering() const;
|
||||
|
||||
/// Return information about data layout.
|
||||
const DataLayout &getDataLayout() const;
|
||||
|
||||
/// Return the pointer size from the TargetMachine
|
||||
unsigned getPointerSize() const;
|
||||
|
||||
/// Return information about subtarget.
|
||||
const MCSubtargetInfo &getSubtargetInfo() const;
|
||||
|
||||
void EmitToStreamer(MCStreamer &S, const MCInst &Inst);
|
||||
|
||||
/// Emits initial debug location directive.
|
||||
void emitInitialRawDwarfLocDirective(const MachineFunction &MF);
|
||||
|
||||
/// Return the current section we are emitting to.
|
||||
const MCSection *getCurrentSection() const;
|
||||
|
||||
void getNameWithPrefix(SmallVectorImpl<char> &Name,
|
||||
const GlobalValue *GV) const;
|
||||
|
||||
MCSymbol *getSymbol(const GlobalValue *GV) const;
|
||||
|
||||
/// Similar to getSymbol() but preferred for references. On ELF, this uses a
|
||||
/// local symbol if a reference to GV is guaranteed to be resolved to the
|
||||
/// definition in the same module.
|
||||
MCSymbol *getSymbolPreferLocal(const GlobalValue &GV) const;
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// XRay instrumentation implementation.
|
||||
//===------------------------------------------------------------------===//
|
||||
public:
|
||||
// This describes the kind of sled we're storing in the XRay table.
|
||||
enum class SledKind : uint8_t {
|
||||
FUNCTION_ENTER = 0,
|
||||
FUNCTION_EXIT = 1,
|
||||
TAIL_CALL = 2,
|
||||
LOG_ARGS_ENTER = 3,
|
||||
CUSTOM_EVENT = 4,
|
||||
TYPED_EVENT = 5,
|
||||
};
|
||||
|
||||
// The table will contain these structs that point to the sled, the function
|
||||
// containing the sled, and what kind of sled (and whether they should always
|
||||
// be instrumented). We also use a version identifier that the runtime can use
|
||||
// to decide what to do with the sled, depending on the version of the sled.
|
||||
struct XRayFunctionEntry {
|
||||
const MCSymbol *Sled;
|
||||
const MCSymbol *Function;
|
||||
SledKind Kind;
|
||||
bool AlwaysInstrument;
|
||||
const class Function *Fn;
|
||||
uint8_t Version;
|
||||
|
||||
void emit(int, MCStreamer *) const;
|
||||
};
|
||||
|
||||
// All the sleds to be emitted.
|
||||
SmallVector<XRayFunctionEntry, 4> Sleds;
|
||||
|
||||
// Helper function to record a given XRay sled.
|
||||
void recordSled(MCSymbol *Sled, const MachineInstr &MI, SledKind Kind,
|
||||
uint8_t Version = 0);
|
||||
|
||||
/// Emit a table with all XRay instrumentation points.
|
||||
void emitXRayTable();
|
||||
|
||||
void emitPatchableFunctionEntries();
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// MachineFunctionPass Implementation.
|
||||
//===------------------------------------------------------------------===//
|
||||
|
||||
/// Record analysis usage.
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
/// Set up the AsmPrinter when we are working on a new module. If your pass
|
||||
/// overrides this, it must make sure to explicitly call this implementation.
|
||||
bool doInitialization(Module &M) override;
|
||||
|
||||
/// Shut down the asmprinter. If you override this in your pass, you must make
|
||||
/// sure to call it explicitly.
|
||||
bool doFinalization(Module &M) override;
|
||||
|
||||
/// Emit the specified function out to the OutStreamer.
|
||||
bool runOnMachineFunction(MachineFunction &MF) override {
|
||||
SetupMachineFunction(MF);
|
||||
emitFunctionBody();
|
||||
return false;
|
||||
}
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Coarse grained IR lowering routines.
|
||||
//===------------------------------------------------------------------===//
|
||||
|
||||
/// This should be called when a new MachineFunction is being processed from
|
||||
/// runOnMachineFunction.
|
||||
virtual void SetupMachineFunction(MachineFunction &MF);
|
||||
|
||||
/// This method emits the body and trailer for a function.
|
||||
void emitFunctionBody();
|
||||
|
||||
void emitCFIInstruction(const MachineInstr &MI);
|
||||
|
||||
void emitFrameAlloc(const MachineInstr &MI);
|
||||
|
||||
void emitStackSizeSection(const MachineFunction &MF);
|
||||
|
||||
void emitStackUsage(const MachineFunction &MF);
|
||||
|
||||
void emitBBAddrMapSection(const MachineFunction &MF);
|
||||
|
||||
void emitPseudoProbe(const MachineInstr &MI);
|
||||
|
||||
void emitRemarksSection(remarks::RemarkStreamer &RS);
|
||||
|
||||
/// Get the CFISection type for a function.
|
||||
CFISection getFunctionCFISectionType(const Function &F) const;
|
||||
|
||||
/// Get the CFISection type for a function.
|
||||
CFISection getFunctionCFISectionType(const MachineFunction &MF) const;
|
||||
|
||||
/// Get the CFISection type for the module.
|
||||
CFISection getModuleCFISectionType() const { return ModuleCFISection; }
|
||||
|
||||
bool needsSEHMoves();
|
||||
|
||||
/// Since emitting CFI unwind information is entangled with supporting the
|
||||
/// exceptions, this returns true for platforms which use CFI unwind
|
||||
/// information for debugging purpose when
|
||||
/// `MCAsmInfo::ExceptionsType == ExceptionHandling::None`.
|
||||
bool needsCFIForDebug() const;
|
||||
|
||||
/// Print to the current output stream assembly representations of the
|
||||
/// constants in the constant pool MCP. This is used to print out constants
|
||||
/// which have been "spilled to memory" by the code generator.
|
||||
virtual void emitConstantPool();
|
||||
|
||||
/// Print assembly representations of the jump tables used by the current
|
||||
/// function to the current output stream.
|
||||
virtual void emitJumpTableInfo();
|
||||
|
||||
/// Emit the specified global variable to the .s file.
|
||||
virtual void emitGlobalVariable(const GlobalVariable *GV);
|
||||
|
||||
/// Check to see if the specified global is a special global used by LLVM. If
|
||||
/// so, emit it and return true, otherwise do nothing and return false.
|
||||
bool emitSpecialLLVMGlobal(const GlobalVariable *GV);
|
||||
|
||||
/// `llvm.global_ctors` and `llvm.global_dtors` are arrays of Structor
|
||||
/// structs.
|
||||
///
|
||||
/// Priority - init priority
|
||||
/// Func - global initialization or global clean-up function
|
||||
/// ComdatKey - associated data
|
||||
struct Structor {
|
||||
int Priority = 0;
|
||||
Constant *Func = nullptr;
|
||||
GlobalValue *ComdatKey = nullptr;
|
||||
|
||||
Structor() = default;
|
||||
};
|
||||
|
||||
/// This method gathers an array of Structors and then sorts them out by
|
||||
/// Priority.
|
||||
/// @param List The initializer of `llvm.global_ctors` or `llvm.global_dtors`
|
||||
/// array.
|
||||
/// @param[out] Structors Sorted Structor structs by Priority.
|
||||
void preprocessXXStructorList(const DataLayout &DL, const Constant *List,
|
||||
SmallVector<Structor, 8> &Structors);
|
||||
|
||||
/// This method emits `llvm.global_ctors` or `llvm.global_dtors` list.
|
||||
virtual void emitXXStructorList(const DataLayout &DL, const Constant *List,
|
||||
bool IsCtor);
|
||||
|
||||
/// Emit an alignment directive to the specified power of two boundary. If a
|
||||
/// global value is specified, and if that global has an explicit alignment
|
||||
/// requested, it will override the alignment request if required for
|
||||
/// correctness.
|
||||
void emitAlignment(Align Alignment, const GlobalObject *GV = nullptr,
|
||||
unsigned MaxBytesToEmit = 0) const;
|
||||
|
||||
/// Lower the specified LLVM Constant to an MCExpr.
|
||||
virtual const MCExpr *lowerConstant(const Constant *CV);
|
||||
|
||||
/// Print a general LLVM constant to the .s file.
|
||||
void emitGlobalConstant(const DataLayout &DL, const Constant *CV);
|
||||
|
||||
/// Unnamed constant global variables solely containing a pointer to
|
||||
/// another globals variable act like a global variable "proxy", or GOT
|
||||
/// equivalents, i.e., it's only used to hold the address of the latter. One
|
||||
/// optimization is to replace accesses to these proxies by using the GOT
|
||||
/// entry for the final global instead. Hence, we select GOT equivalent
|
||||
/// candidates among all the module global variables, avoid emitting them
|
||||
/// unnecessarily and finally replace references to them by pc relative
|
||||
/// accesses to GOT entries.
|
||||
void computeGlobalGOTEquivs(Module &M);
|
||||
|
||||
/// Constant expressions using GOT equivalent globals may not be
|
||||
/// eligible for PC relative GOT entry conversion, in such cases we need to
|
||||
/// emit the proxies we previously omitted in EmitGlobalVariable.
|
||||
void emitGlobalGOTEquivs();
|
||||
|
||||
/// Emit the stack maps.
|
||||
void emitStackMaps(StackMaps &SM);
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Overridable Hooks
|
||||
//===------------------------------------------------------------------===//
|
||||
|
||||
void addAsmPrinterHandler(HandlerInfo Handler) {
|
||||
Handlers.insert(Handlers.begin(), std::move(Handler));
|
||||
NumUserHandlers++;
|
||||
}
|
||||
|
||||
// Targets can, or in the case of EmitInstruction, must implement these to
|
||||
// customize output.
|
||||
|
||||
/// This virtual method can be overridden by targets that want to emit
|
||||
/// something at the start of their file.
|
||||
virtual void emitStartOfAsmFile(Module &) {}
|
||||
|
||||
/// This virtual method can be overridden by targets that want to emit
|
||||
/// something at the end of their file.
|
||||
virtual void emitEndOfAsmFile(Module &) {}
|
||||
|
||||
/// Targets can override this to emit stuff before the first basic block in
|
||||
/// the function.
|
||||
virtual void emitFunctionBodyStart() {}
|
||||
|
||||
/// Targets can override this to emit stuff after the last basic block in the
|
||||
/// function.
|
||||
virtual void emitFunctionBodyEnd() {}
|
||||
|
||||
/// Targets can override this to emit stuff at the start of a basic block.
|
||||
/// By default, this method prints the label for the specified
|
||||
/// MachineBasicBlock, an alignment (if present) and a comment describing it
|
||||
/// if appropriate.
|
||||
virtual void emitBasicBlockStart(const MachineBasicBlock &MBB);
|
||||
|
||||
/// Targets can override this to emit stuff at the end of a basic block.
|
||||
virtual void emitBasicBlockEnd(const MachineBasicBlock &MBB);
|
||||
|
||||
/// Targets should implement this to emit instructions.
|
||||
virtual void emitInstruction(const MachineInstr *) {
|
||||
llvm_unreachable("EmitInstruction not implemented");
|
||||
}
|
||||
|
||||
/// Return the symbol for the specified constant pool entry.
|
||||
virtual MCSymbol *GetCPISymbol(unsigned CPID) const;
|
||||
|
||||
virtual void emitFunctionEntryLabel();
|
||||
|
||||
virtual void emitFunctionDescriptor() {
|
||||
llvm_unreachable("Function descriptor is target-specific.");
|
||||
}
|
||||
|
||||
virtual void emitMachineConstantPoolValue(MachineConstantPoolValue *MCPV);
|
||||
|
||||
/// Targets can override this to change how global constants that are part of
|
||||
/// a C++ static/global constructor list are emitted.
|
||||
virtual void emitXXStructor(const DataLayout &DL, const Constant *CV) {
|
||||
emitGlobalConstant(DL, CV);
|
||||
}
|
||||
|
||||
/// Return true if the basic block has exactly one predecessor and the control
|
||||
/// transfer mechanism between the predecessor and this block is a
|
||||
/// fall-through.
|
||||
virtual bool
|
||||
isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) const;
|
||||
|
||||
/// Targets can override this to customize the output of IMPLICIT_DEF
|
||||
/// instructions in verbose mode.
|
||||
virtual void emitImplicitDef(const MachineInstr *MI) const;
|
||||
|
||||
/// Emit N NOP instructions.
|
||||
void emitNops(unsigned N);
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Symbol Lowering Routines.
|
||||
//===------------------------------------------------------------------===//
|
||||
|
||||
MCSymbol *createTempSymbol(const Twine &Name) const;
|
||||
|
||||
/// Return the MCSymbol for a private symbol with global value name as its
|
||||
/// base, with the specified suffix.
|
||||
MCSymbol *getSymbolWithGlobalValueBase(const GlobalValue *GV,
|
||||
StringRef Suffix) const;
|
||||
|
||||
/// Return the MCSymbol for the specified ExternalSymbol.
|
||||
MCSymbol *GetExternalSymbolSymbol(StringRef Sym) const;
|
||||
|
||||
/// Return the symbol for the specified jump table entry.
|
||||
MCSymbol *GetJTISymbol(unsigned JTID, bool isLinkerPrivate = false) const;
|
||||
|
||||
/// Return the symbol for the specified jump table .set
|
||||
/// FIXME: privatize to AsmPrinter.
|
||||
MCSymbol *GetJTSetSymbol(unsigned UID, unsigned MBBID) const;
|
||||
|
||||
/// Return the MCSymbol used to satisfy BlockAddress uses of the specified
|
||||
/// basic block.
|
||||
MCSymbol *GetBlockAddressSymbol(const BlockAddress *BA) const;
|
||||
MCSymbol *GetBlockAddressSymbol(const BasicBlock *BB) const;
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Emission Helper Routines.
|
||||
//===------------------------------------------------------------------===//
|
||||
|
||||
/// This is just convenient handler for printing offsets.
|
||||
void printOffset(int64_t Offset, raw_ostream &OS) const;
|
||||
|
||||
/// Emit a byte directive and value.
|
||||
void emitInt8(int Value) const;
|
||||
|
||||
/// Emit a short directive and value.
|
||||
void emitInt16(int Value) const;
|
||||
|
||||
/// Emit a long directive and value.
|
||||
void emitInt32(int Value) const;
|
||||
|
||||
/// Emit a long long directive and value.
|
||||
void emitInt64(uint64_t Value) const;
|
||||
|
||||
/// Emit something like ".long Hi-Lo" where the size in bytes of the directive
|
||||
/// is specified by Size and Hi/Lo specify the labels. This implicitly uses
|
||||
/// .set if it is available.
|
||||
void emitLabelDifference(const MCSymbol *Hi, const MCSymbol *Lo,
|
||||
unsigned Size) const;
|
||||
|
||||
/// Emit something like ".uleb128 Hi-Lo".
|
||||
void emitLabelDifferenceAsULEB128(const MCSymbol *Hi,
|
||||
const MCSymbol *Lo) const;
|
||||
|
||||
/// Emit something like ".long Label+Offset" where the size in bytes of the
|
||||
/// directive is specified by Size and Label specifies the label. This
|
||||
/// implicitly uses .set if it is available.
|
||||
void emitLabelPlusOffset(const MCSymbol *Label, uint64_t Offset,
|
||||
unsigned Size, bool IsSectionRelative = false) const;
|
||||
|
||||
/// Emit something like ".long Label" where the size in bytes of the directive
|
||||
/// is specified by Size and Label specifies the label.
|
||||
void emitLabelReference(const MCSymbol *Label, unsigned Size,
|
||||
bool IsSectionRelative = false) const {
|
||||
emitLabelPlusOffset(Label, 0, Size, IsSectionRelative);
|
||||
}
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Dwarf Emission Helper Routines
|
||||
//===------------------------------------------------------------------===//
|
||||
|
||||
/// Emit the specified signed leb128 value.
|
||||
void emitSLEB128(int64_t Value, const char *Desc = nullptr) const;
|
||||
|
||||
/// Emit the specified unsigned leb128 value.
|
||||
void emitULEB128(uint64_t Value, const char *Desc = nullptr,
|
||||
unsigned PadTo = 0) const;
|
||||
|
||||
/// Emit a .byte 42 directive that corresponds to an encoding. If verbose
|
||||
/// assembly output is enabled, we output comments describing the encoding.
|
||||
/// Desc is a string saying what the encoding is specifying (e.g. "LSDA").
|
||||
void emitEncodingByte(unsigned Val, const char *Desc = nullptr) const;
|
||||
|
||||
/// Return the size of the encoding in bytes.
|
||||
unsigned GetSizeOfEncodedValue(unsigned Encoding) const;
|
||||
|
||||
/// Emit reference to a ttype global with a specified encoding.
|
||||
virtual void emitTTypeReference(const GlobalValue *GV, unsigned Encoding);
|
||||
|
||||
/// Emit a reference to a symbol for use in dwarf. Different object formats
|
||||
/// represent this in different ways. Some use a relocation others encode
|
||||
/// the label offset in its section.
|
||||
void emitDwarfSymbolReference(const MCSymbol *Label,
|
||||
bool ForceOffset = false) const;
|
||||
|
||||
/// Emit the 4- or 8-byte offset of a string from the start of its section.
|
||||
///
|
||||
/// When possible, emit a DwarfStringPool section offset without any
|
||||
/// relocations, and without using the symbol. Otherwise, defers to \a
|
||||
/// emitDwarfSymbolReference().
|
||||
///
|
||||
/// The length of the emitted value depends on the DWARF format.
|
||||
void emitDwarfStringOffset(DwarfStringPoolEntry S) const;
|
||||
|
||||
/// Emit the 4-or 8-byte offset of a string from the start of its section.
|
||||
void emitDwarfStringOffset(DwarfStringPoolEntryRef S) const {
|
||||
emitDwarfStringOffset(S.getEntry());
|
||||
}
|
||||
|
||||
/// Emit something like ".long Label + Offset" or ".quad Label + Offset"
|
||||
/// depending on the DWARF format.
|
||||
void emitDwarfOffset(const MCSymbol *Label, uint64_t Offset) const;
|
||||
|
||||
/// Emit 32- or 64-bit value depending on the DWARF format.
|
||||
void emitDwarfLengthOrOffset(uint64_t Value) const;
|
||||
|
||||
/// Emit a unit length field. The actual format, DWARF32 or DWARF64, is chosen
|
||||
/// according to the settings.
|
||||
void emitDwarfUnitLength(uint64_t Length, const Twine &Comment) const;
|
||||
|
||||
/// Emit a unit length field. The actual format, DWARF32 or DWARF64, is chosen
|
||||
/// according to the settings.
|
||||
/// Return the end symbol generated inside, the caller needs to emit it.
|
||||
MCSymbol *emitDwarfUnitLength(const Twine &Prefix,
|
||||
const Twine &Comment) const;
|
||||
|
||||
/// Emit reference to a call site with a specified encoding
|
||||
void emitCallSiteOffset(const MCSymbol *Hi, const MCSymbol *Lo,
|
||||
unsigned Encoding) const;
|
||||
/// Emit an integer value corresponding to the call site encoding
|
||||
void emitCallSiteValue(uint64_t Value, unsigned Encoding) const;
|
||||
|
||||
/// Get the value for DW_AT_APPLE_isa. Zero if no isa encoding specified.
|
||||
virtual unsigned getISAEncoding() { return 0; }
|
||||
|
||||
/// Emit the directive and value for debug thread local expression
|
||||
///
|
||||
/// \p Value - The value to emit.
|
||||
/// \p Size - The size of the integer (in bytes) to emit.
|
||||
virtual void emitDebugValue(const MCExpr *Value, unsigned Size) const;
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Dwarf Lowering Routines
|
||||
//===------------------------------------------------------------------===//
|
||||
|
||||
/// Emit frame instruction to describe the layout of the frame.
|
||||
void emitCFIInstruction(const MCCFIInstruction &Inst) const;
|
||||
|
||||
/// Emit Dwarf abbreviation table.
|
||||
template <typename T> void emitDwarfAbbrevs(const T &Abbrevs) const {
|
||||
// For each abbreviation.
|
||||
for (const auto &Abbrev : Abbrevs)
|
||||
emitDwarfAbbrev(*Abbrev);
|
||||
|
||||
// Mark end of abbreviations.
|
||||
emitULEB128(0, "EOM(3)");
|
||||
}
|
||||
|
||||
void emitDwarfAbbrev(const DIEAbbrev &Abbrev) const;
|
||||
|
||||
/// Recursively emit Dwarf DIE tree.
|
||||
void emitDwarfDIE(const DIE &Die) const;
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Inline Asm Support
|
||||
//===------------------------------------------------------------------===//
|
||||
|
||||
// These are hooks that targets can override to implement inline asm
|
||||
// support. These should probably be moved out of AsmPrinter someday.
|
||||
|
||||
/// Print information related to the specified machine instr that is
|
||||
/// independent of the operand, and may be independent of the instr itself.
|
||||
/// This can be useful for portably encoding the comment character or other
|
||||
/// bits of target-specific knowledge into the asmstrings. The syntax used is
|
||||
/// ${:comment}. Targets can override this to add support for their own
|
||||
/// strange codes.
|
||||
virtual void PrintSpecial(const MachineInstr *MI, raw_ostream &OS,
|
||||
StringRef Code) const;
|
||||
|
||||
/// Print the MachineOperand as a symbol. Targets with complex handling of
|
||||
/// symbol references should override the base implementation.
|
||||
virtual void PrintSymbolOperand(const MachineOperand &MO, raw_ostream &OS);
|
||||
|
||||
/// Print the specified operand of MI, an INLINEASM instruction, using the
|
||||
/// specified assembler variant. Targets should override this to format as
|
||||
/// appropriate. This method can return true if the operand is erroneous.
|
||||
virtual bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
|
||||
const char *ExtraCode, raw_ostream &OS);
|
||||
|
||||
/// Print the specified operand of MI, an INLINEASM instruction, using the
|
||||
/// specified assembler variant as an address. Targets should override this to
|
||||
/// format as appropriate. This method can return true if the operand is
|
||||
/// erroneous.
|
||||
virtual bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
|
||||
const char *ExtraCode, raw_ostream &OS);
|
||||
|
||||
/// Let the target do anything it needs to do before emitting inlineasm.
|
||||
/// \p StartInfo - the subtarget info before parsing inline asm
|
||||
virtual void emitInlineAsmStart() const;
|
||||
|
||||
/// Let the target do anything it needs to do after emitting inlineasm.
|
||||
/// This callback can be used restore the original mode in case the
|
||||
/// inlineasm contains directives to switch modes.
|
||||
/// \p StartInfo - the original subtarget info before inline asm
|
||||
/// \p EndInfo - the final subtarget info after parsing the inline asm,
|
||||
/// or NULL if the value is unknown.
|
||||
virtual void emitInlineAsmEnd(const MCSubtargetInfo &StartInfo,
|
||||
const MCSubtargetInfo *EndInfo) const;
|
||||
|
||||
/// This emits visibility information about symbol, if this is supported by
|
||||
/// the target.
|
||||
void emitVisibility(MCSymbol *Sym, unsigned Visibility,
|
||||
bool IsDefinition = true) const;
|
||||
|
||||
/// This emits linkage information about \p GVSym based on \p GV, if this is
|
||||
/// supported by the target.
|
||||
virtual void emitLinkage(const GlobalValue *GV, MCSymbol *GVSym) const;
|
||||
|
||||
/// Return the alignment for the specified \p GV.
|
||||
static Align getGVAlignment(const GlobalObject *GV, const DataLayout &DL,
|
||||
Align InAlign = Align(1));
|
||||
|
||||
private:
|
||||
/// Private state for PrintSpecial()
|
||||
// Assign a unique ID to this machine instruction.
|
||||
mutable const MachineInstr *LastMI = nullptr;
|
||||
mutable unsigned LastFn = 0;
|
||||
mutable unsigned Counter = ~0U;
|
||||
|
||||
/// This method emits the header for the current function.
|
||||
virtual void emitFunctionHeader();
|
||||
|
||||
/// This method emits a comment next to header for the current function.
|
||||
virtual void emitFunctionHeaderComment();
|
||||
|
||||
/// Emit a blob of inline asm to the output streamer.
|
||||
void
|
||||
emitInlineAsm(StringRef Str, const MCSubtargetInfo &STI,
|
||||
const MCTargetOptions &MCOptions,
|
||||
const MDNode *LocMDNode = nullptr,
|
||||
InlineAsm::AsmDialect AsmDialect = InlineAsm::AD_ATT) const;
|
||||
|
||||
/// This method formats and emits the specified machine instruction that is an
|
||||
/// inline asm.
|
||||
void emitInlineAsm(const MachineInstr *MI) const;
|
||||
|
||||
/// Add inline assembly info to the diagnostics machinery, so we can
|
||||
/// emit file and position info. Returns SrcMgr memory buffer position.
|
||||
unsigned addInlineAsmDiagBuffer(StringRef AsmStr,
|
||||
const MDNode *LocMDNode) const;
|
||||
|
||||
//===------------------------------------------------------------------===//
|
||||
// Internal Implementation Details
|
||||
//===------------------------------------------------------------------===//
|
||||
|
||||
void emitJumpTableEntry(const MachineJumpTableInfo *MJTI,
|
||||
const MachineBasicBlock *MBB, unsigned uid) const;
|
||||
void emitLLVMUsedList(const ConstantArray *InitList);
|
||||
/// Emit llvm.ident metadata in an '.ident' directive.
|
||||
void emitModuleIdents(Module &M);
|
||||
/// Emit bytes for llvm.commandline metadata.
|
||||
void emitModuleCommandLines(Module &M);
|
||||
|
||||
GCMetadataPrinter *GetOrCreateGCPrinter(GCStrategy &S);
|
||||
void emitGlobalAlias(Module &M, const GlobalAlias &GA);
|
||||
void emitGlobalIFunc(Module &M, const GlobalIFunc &GI);
|
||||
|
||||
/// This method decides whether the specified basic block requires a label.
|
||||
bool shouldEmitLabelForBasicBlock(const MachineBasicBlock &MBB) const;
|
||||
|
||||
protected:
|
||||
virtual bool shouldEmitWeakSwiftAsyncExtendedFramePointerFlags() const {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_ASMPRINTER_H
|
||||
84
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/AsmPrinterHandler.h
vendored
Normal file
84
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/AsmPrinterHandler.h
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
//===-- llvm/CodeGen/AsmPrinterHandler.h -----------------------*- 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 file contains a generic interface for AsmPrinter handlers,
|
||||
// like debug and EH info emitters.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_ASMPRINTERHANDLER_H
|
||||
#define LLVM_CODEGEN_ASMPRINTERHANDLER_H
|
||||
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class AsmPrinter;
|
||||
class MachineBasicBlock;
|
||||
class MachineFunction;
|
||||
class MachineInstr;
|
||||
class MCSymbol;
|
||||
class Module;
|
||||
|
||||
typedef MCSymbol *ExceptionSymbolProvider(AsmPrinter *Asm,
|
||||
const MachineBasicBlock *MBB);
|
||||
|
||||
/// Collects and handles AsmPrinter objects required to build debug
|
||||
/// or EH information.
|
||||
class AsmPrinterHandler {
|
||||
public:
|
||||
virtual ~AsmPrinterHandler();
|
||||
|
||||
/// For symbols that have a size designated (e.g. common symbols),
|
||||
/// this tracks that size.
|
||||
virtual void setSymbolSize(const MCSymbol *Sym, uint64_t Size) = 0;
|
||||
|
||||
virtual void beginModule(Module *M) {}
|
||||
|
||||
/// Emit all sections that should come after the content.
|
||||
virtual void endModule() = 0;
|
||||
|
||||
/// Gather pre-function debug information.
|
||||
/// Every beginFunction(MF) call should be followed by an endFunction(MF)
|
||||
/// call.
|
||||
virtual void beginFunction(const MachineFunction *MF) = 0;
|
||||
|
||||
// Emit any of function marker (like .cfi_endproc). This is called
|
||||
// before endFunction and cannot switch sections.
|
||||
virtual void markFunctionEnd();
|
||||
|
||||
/// Gather post-function debug information.
|
||||
/// Please note that some AsmPrinter implementations may not call
|
||||
/// beginFunction at all.
|
||||
virtual void endFunction(const MachineFunction *MF) = 0;
|
||||
|
||||
virtual void beginFragment(const MachineBasicBlock *MBB,
|
||||
ExceptionSymbolProvider ESP) {}
|
||||
virtual void endFragment() {}
|
||||
|
||||
/// Emit target-specific EH funclet machinery.
|
||||
virtual void beginFunclet(const MachineBasicBlock &MBB,
|
||||
MCSymbol *Sym = nullptr) {}
|
||||
virtual void endFunclet() {}
|
||||
|
||||
/// Process beginning of an instruction.
|
||||
virtual void beginInstruction(const MachineInstr *MI) = 0;
|
||||
|
||||
/// Process end of an instruction.
|
||||
virtual void endInstruction() = 0;
|
||||
|
||||
/// Process beginning of a basic block during basic block sections.
|
||||
virtual void beginBasicBlock(const MachineBasicBlock &MBB) {}
|
||||
|
||||
/// Process end of a basic block during basic block sections.
|
||||
virtual void endBasicBlock(const MachineBasicBlock &MBB) {}
|
||||
};
|
||||
|
||||
} // End of namespace llvm
|
||||
|
||||
#endif
|
||||
64
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/AtomicExpandUtils.h
vendored
Normal file
64
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/AtomicExpandUtils.h
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
//===- AtomicExpandUtils.h - Utilities for expanding atomic instructions --===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_ATOMICEXPANDUTILS_H
|
||||
#define LLVM_CODEGEN_ATOMICEXPANDUTILS_H
|
||||
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/Support/AtomicOrdering.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class AtomicRMWInst;
|
||||
class Value;
|
||||
|
||||
/// Parameters (see the expansion example below):
|
||||
/// (the builder, %addr, %loaded, %new_val, ordering,
|
||||
/// /* OUT */ %success, /* OUT */ %new_loaded)
|
||||
using CreateCmpXchgInstFun =
|
||||
function_ref<void(IRBuilder<> &, Value *, Value *, Value *, Align,
|
||||
AtomicOrdering, SyncScope::ID, Value *&, Value *&)>;
|
||||
|
||||
/// Expand an atomic RMW instruction into a loop utilizing
|
||||
/// cmpxchg. You'll want to make sure your target machine likes cmpxchg
|
||||
/// instructions in the first place and that there isn't another, better,
|
||||
/// transformation available (for example AArch32/AArch64 have linked loads).
|
||||
///
|
||||
/// This is useful in passes which can't rewrite the more exotic RMW
|
||||
/// instructions directly into a platform specific intrinsics (because, say,
|
||||
/// those intrinsics don't exist). If such a pass is able to expand cmpxchg
|
||||
/// instructions directly however, then, with this function, it could avoid two
|
||||
/// extra module passes (avoiding passes by `-atomic-expand` and itself). A
|
||||
/// specific example would be PNaCl's `RewriteAtomics` pass.
|
||||
///
|
||||
/// Given: atomicrmw some_op iN* %addr, iN %incr ordering
|
||||
///
|
||||
/// The standard expansion we produce is:
|
||||
/// [...]
|
||||
/// %init_loaded = load atomic iN* %addr
|
||||
/// br label %loop
|
||||
/// loop:
|
||||
/// %loaded = phi iN [ %init_loaded, %entry ], [ %new_loaded, %loop ]
|
||||
/// %new = some_op iN %loaded, %incr
|
||||
/// ; This is what -atomic-expand will produce using this function on i686
|
||||
/// targets:
|
||||
/// %pair = cmpxchg iN* %addr, iN %loaded, iN %new_val
|
||||
/// %new_loaded = extractvalue { iN, i1 } %pair, 0
|
||||
/// %success = extractvalue { iN, i1 } %pair, 1
|
||||
/// ; End callback produced IR
|
||||
/// br i1 %success, label %atomicrmw.end, label %loop
|
||||
/// atomicrmw.end:
|
||||
/// [...]
|
||||
///
|
||||
/// Returns true if the containing function was modified.
|
||||
bool expandAtomicRMWToCmpXchg(AtomicRMWInst *AI, CreateCmpXchgInstFun CreateCmpXchg);
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_ATOMICEXPANDUTILS_H
|
||||
30
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/BasicBlockSectionUtils.h
vendored
Normal file
30
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/BasicBlockSectionUtils.h
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
//===- BasicBlockSectionUtils.h - Utilities for basic block sections --===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_BASICBLOCKSECTIONUTILS_H
|
||||
#define LLVM_CODEGEN_BASICBLOCKSECTIONUTILS_H
|
||||
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
extern cl::opt<std::string> BBSectionsColdTextPrefix;
|
||||
|
||||
class MachineFunction;
|
||||
class MachineBasicBlock;
|
||||
|
||||
using MachineBasicBlockComparator =
|
||||
function_ref<bool(const MachineBasicBlock &, const MachineBasicBlock &)>;
|
||||
|
||||
void sortBasicBlocksAndUpdateBranches(MachineFunction &MF,
|
||||
MachineBasicBlockComparator MBBCmp);
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_BASICBLOCKSECTIONUTILS_H
|
||||
2262
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/BasicTTIImpl.h
vendored
Normal file
2262
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/BasicTTIImpl.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
28
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/CSEConfigBase.h
vendored
Normal file
28
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/CSEConfigBase.h
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
//===- CSEConfigBase.h - A CSEConfig interface ------------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_CSECONFIGBASE_H
|
||||
#define LLVM_CODEGEN_CSECONFIGBASE_H
|
||||
|
||||
namespace llvm {
|
||||
// Class representing some configuration that can be done during GlobalISel's
|
||||
// CSEInfo analysis. We define it here because TargetPassConfig can't depend on
|
||||
// the GlobalISel library, and so we use this in the interface between them
|
||||
// so that the derived classes in GISel can reference generic opcodes.
|
||||
class CSEConfigBase {
|
||||
public:
|
||||
virtual ~CSEConfigBase() = default;
|
||||
// Hook for defining which Generic instructions should be CSEd.
|
||||
// GISelCSEInfo currently only calls this hook when dealing with generic
|
||||
// opcodes.
|
||||
virtual bool shouldCSEOpc(unsigned Opc) { return false; }
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_CSECONFIGBASE_H
|
||||
119
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/CalcSpillWeights.h
vendored
Normal file
119
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/CalcSpillWeights.h
vendored
Normal file
@@ -0,0 +1,119 @@
|
||||
//===- lib/CodeGen/CalcSpillWeights.h ---------------------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_CALCSPILLWEIGHTS_H
|
||||
#define LLVM_CODEGEN_CALCSPILLWEIGHTS_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/CodeGen/SlotIndexes.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class LiveInterval;
|
||||
class LiveIntervals;
|
||||
class MachineBlockFrequencyInfo;
|
||||
class MachineFunction;
|
||||
class MachineLoopInfo;
|
||||
class VirtRegMap;
|
||||
|
||||
/// Normalize the spill weight of a live interval
|
||||
///
|
||||
/// The spill weight of a live interval is computed as:
|
||||
///
|
||||
/// (sum(use freq) + sum(def freq)) / (K + size)
|
||||
///
|
||||
/// @param UseDefFreq Expected number of executed use and def instructions
|
||||
/// per function call. Derived from block frequencies.
|
||||
/// @param Size Size of live interval as returnexd by getSize()
|
||||
/// @param NumInstr Number of instructions using this live interval
|
||||
static inline float normalizeSpillWeight(float UseDefFreq, unsigned Size,
|
||||
unsigned NumInstr) {
|
||||
// The constant 25 instructions is added to avoid depending too much on
|
||||
// accidental SlotIndex gaps for small intervals. The effect is that small
|
||||
// intervals have a spill weight that is mostly proportional to the number
|
||||
// of uses, while large intervals get a spill weight that is closer to a use
|
||||
// density.
|
||||
return UseDefFreq / (Size + 25*SlotIndex::InstrDist);
|
||||
}
|
||||
|
||||
/// Calculate auxiliary information for a virtual register such as its
|
||||
/// spill weight and allocation hint.
|
||||
class VirtRegAuxInfo {
|
||||
MachineFunction &MF;
|
||||
LiveIntervals &LIS;
|
||||
const VirtRegMap &VRM;
|
||||
const MachineLoopInfo &Loops;
|
||||
const MachineBlockFrequencyInfo &MBFI;
|
||||
|
||||
/// Returns true if Reg of live interval LI is used in instruction with many
|
||||
/// operands like STATEPOINT.
|
||||
bool isLiveAtStatepointVarArg(LiveInterval &LI);
|
||||
|
||||
public:
|
||||
VirtRegAuxInfo(MachineFunction &MF, LiveIntervals &LIS,
|
||||
const VirtRegMap &VRM, const MachineLoopInfo &Loops,
|
||||
const MachineBlockFrequencyInfo &MBFI)
|
||||
: MF(MF), LIS(LIS), VRM(VRM), Loops(Loops), MBFI(MBFI) {}
|
||||
|
||||
virtual ~VirtRegAuxInfo() = default;
|
||||
|
||||
/// (re)compute li's spill weight and allocation hint.
|
||||
void calculateSpillWeightAndHint(LiveInterval &LI);
|
||||
|
||||
/// Compute future expected spill weight of a split artifact of LI
|
||||
/// that will span between start and end slot indexes.
|
||||
/// \param LI The live interval to be split.
|
||||
/// \param Start The expected beginning of the split artifact. Instructions
|
||||
/// before start will not affect the weight.
|
||||
/// \param End The expected end of the split artifact. Instructions
|
||||
/// after end will not affect the weight.
|
||||
/// \return The expected spill weight of the split artifact. Returns
|
||||
/// negative weight for unspillable LI.
|
||||
float futureWeight(LiveInterval &LI, SlotIndex Start, SlotIndex End);
|
||||
|
||||
/// Compute spill weights and allocation hints for all virtual register
|
||||
/// live intervals.
|
||||
void calculateSpillWeightsAndHints();
|
||||
|
||||
/// Return the preferred allocation register for reg, given a COPY
|
||||
/// instruction.
|
||||
static Register copyHint(const MachineInstr *MI, unsigned Reg,
|
||||
const TargetRegisterInfo &TRI,
|
||||
const MachineRegisterInfo &MRI);
|
||||
|
||||
/// Determine if all values in LI are rematerializable.
|
||||
static bool isRematerializable(const LiveInterval &LI,
|
||||
const LiveIntervals &LIS,
|
||||
const VirtRegMap &VRM,
|
||||
const TargetInstrInfo &TII);
|
||||
|
||||
protected:
|
||||
/// Helper function for weight calculations.
|
||||
/// (Re)compute LI's spill weight and allocation hint, or, for non null
|
||||
/// start and end - compute future expected spill weight of a split
|
||||
/// artifact of LI that will span between start and end slot indexes.
|
||||
/// \param LI The live interval for which to compute the weight.
|
||||
/// \param Start The expected beginning of the split artifact. Instructions
|
||||
/// before start will not affect the weight. Relevant for
|
||||
/// weight calculation of future split artifact.
|
||||
/// \param End The expected end of the split artifact. Instructions
|
||||
/// after end will not affect the weight. Relevant for
|
||||
/// weight calculation of future split artifact.
|
||||
/// \return The spill weight. Returns negative weight for unspillable LI.
|
||||
float weightCalcHelper(LiveInterval &LI, SlotIndex *Start = nullptr,
|
||||
SlotIndex *End = nullptr);
|
||||
|
||||
/// Weight normalization function.
|
||||
virtual float normalize(float UseDefFreq, unsigned Size,
|
||||
unsigned NumInstr) {
|
||||
return normalizeSpillWeight(UseDefFreq, Size, NumInstr);
|
||||
}
|
||||
};
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_CALCSPILLWEIGHTS_H
|
||||
568
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/CallingConvLower.h
vendored
Normal file
568
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/CallingConvLower.h
vendored
Normal file
@@ -0,0 +1,568 @@
|
||||
//===- llvm/CallingConvLower.h - Calling Conventions ------------*- 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 file declares the CCState and CCValAssign classes, used for lowering
|
||||
// and implementing calling conventions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_CALLINGCONVLOWER_H
|
||||
#define LLVM_CODEGEN_CALLINGCONVLOWER_H
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/Register.h"
|
||||
#include "llvm/CodeGen/TargetCallingConv.h"
|
||||
#include "llvm/IR/CallingConv.h"
|
||||
#include "llvm/MC/MCRegisterInfo.h"
|
||||
#include "llvm/Support/Alignment.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class CCState;
|
||||
class MachineFunction;
|
||||
class MVT;
|
||||
class TargetRegisterInfo;
|
||||
|
||||
/// CCValAssign - Represent assignment of one arg/retval to a location.
|
||||
class CCValAssign {
|
||||
public:
|
||||
enum LocInfo {
|
||||
Full, // The value fills the full location.
|
||||
SExt, // The value is sign extended in the location.
|
||||
ZExt, // The value is zero extended in the location.
|
||||
AExt, // The value is extended with undefined upper bits.
|
||||
SExtUpper, // The value is in the upper bits of the location and should be
|
||||
// sign extended when retrieved.
|
||||
ZExtUpper, // The value is in the upper bits of the location and should be
|
||||
// zero extended when retrieved.
|
||||
AExtUpper, // The value is in the upper bits of the location and should be
|
||||
// extended with undefined upper bits when retrieved.
|
||||
BCvt, // The value is bit-converted in the location.
|
||||
Trunc, // The value is truncated in the location.
|
||||
VExt, // The value is vector-widened in the location.
|
||||
// FIXME: Not implemented yet. Code that uses AExt to mean
|
||||
// vector-widen should be fixed to use VExt instead.
|
||||
FPExt, // The floating-point value is fp-extended in the location.
|
||||
Indirect // The location contains pointer to the value.
|
||||
// TODO: a subset of the value is in the location.
|
||||
};
|
||||
|
||||
private:
|
||||
/// ValNo - This is the value number being assigned (e.g. an argument number).
|
||||
unsigned ValNo;
|
||||
|
||||
/// Loc is either a stack offset or a register number.
|
||||
unsigned Loc;
|
||||
|
||||
/// isMem - True if this is a memory loc, false if it is a register loc.
|
||||
unsigned isMem : 1;
|
||||
|
||||
/// isCustom - True if this arg/retval requires special handling.
|
||||
unsigned isCustom : 1;
|
||||
|
||||
/// Information about how the value is assigned.
|
||||
LocInfo HTP : 6;
|
||||
|
||||
/// ValVT - The type of the value being assigned.
|
||||
MVT ValVT;
|
||||
|
||||
/// LocVT - The type of the location being assigned to.
|
||||
MVT LocVT;
|
||||
public:
|
||||
|
||||
static CCValAssign getReg(unsigned ValNo, MVT ValVT,
|
||||
unsigned RegNo, MVT LocVT,
|
||||
LocInfo HTP) {
|
||||
CCValAssign Ret;
|
||||
Ret.ValNo = ValNo;
|
||||
Ret.Loc = RegNo;
|
||||
Ret.isMem = false;
|
||||
Ret.isCustom = false;
|
||||
Ret.HTP = HTP;
|
||||
Ret.ValVT = ValVT;
|
||||
Ret.LocVT = LocVT;
|
||||
return Ret;
|
||||
}
|
||||
|
||||
static CCValAssign getCustomReg(unsigned ValNo, MVT ValVT,
|
||||
unsigned RegNo, MVT LocVT,
|
||||
LocInfo HTP) {
|
||||
CCValAssign Ret;
|
||||
Ret = getReg(ValNo, ValVT, RegNo, LocVT, HTP);
|
||||
Ret.isCustom = true;
|
||||
return Ret;
|
||||
}
|
||||
|
||||
static CCValAssign getMem(unsigned ValNo, MVT ValVT,
|
||||
unsigned Offset, MVT LocVT,
|
||||
LocInfo HTP) {
|
||||
CCValAssign Ret;
|
||||
Ret.ValNo = ValNo;
|
||||
Ret.Loc = Offset;
|
||||
Ret.isMem = true;
|
||||
Ret.isCustom = false;
|
||||
Ret.HTP = HTP;
|
||||
Ret.ValVT = ValVT;
|
||||
Ret.LocVT = LocVT;
|
||||
return Ret;
|
||||
}
|
||||
|
||||
static CCValAssign getCustomMem(unsigned ValNo, MVT ValVT,
|
||||
unsigned Offset, MVT LocVT,
|
||||
LocInfo HTP) {
|
||||
CCValAssign Ret;
|
||||
Ret = getMem(ValNo, ValVT, Offset, LocVT, HTP);
|
||||
Ret.isCustom = true;
|
||||
return Ret;
|
||||
}
|
||||
|
||||
// There is no need to differentiate between a pending CCValAssign and other
|
||||
// kinds, as they are stored in a different list.
|
||||
static CCValAssign getPending(unsigned ValNo, MVT ValVT, MVT LocVT,
|
||||
LocInfo HTP, unsigned ExtraInfo = 0) {
|
||||
return getReg(ValNo, ValVT, ExtraInfo, LocVT, HTP);
|
||||
}
|
||||
|
||||
void convertToReg(unsigned RegNo) {
|
||||
Loc = RegNo;
|
||||
isMem = false;
|
||||
}
|
||||
|
||||
void convertToMem(unsigned Offset) {
|
||||
Loc = Offset;
|
||||
isMem = true;
|
||||
}
|
||||
|
||||
unsigned getValNo() const { return ValNo; }
|
||||
MVT getValVT() const { return ValVT; }
|
||||
|
||||
bool isRegLoc() const { return !isMem; }
|
||||
bool isMemLoc() const { return isMem; }
|
||||
|
||||
bool needsCustom() const { return isCustom; }
|
||||
|
||||
Register getLocReg() const { assert(isRegLoc()); return Loc; }
|
||||
unsigned getLocMemOffset() const { assert(isMemLoc()); return Loc; }
|
||||
unsigned getExtraInfo() const { return Loc; }
|
||||
MVT getLocVT() const { return LocVT; }
|
||||
|
||||
LocInfo getLocInfo() const { return HTP; }
|
||||
bool isExtInLoc() const {
|
||||
return (HTP == AExt || HTP == SExt || HTP == ZExt);
|
||||
}
|
||||
|
||||
bool isUpperBitsInLoc() const {
|
||||
return HTP == AExtUpper || HTP == SExtUpper || HTP == ZExtUpper;
|
||||
}
|
||||
};
|
||||
|
||||
/// Describes a register that needs to be forwarded from the prologue to a
|
||||
/// musttail call.
|
||||
struct ForwardedRegister {
|
||||
ForwardedRegister(Register VReg, MCPhysReg PReg, MVT VT)
|
||||
: VReg(VReg), PReg(PReg), VT(VT) {}
|
||||
Register VReg;
|
||||
MCPhysReg PReg;
|
||||
MVT VT;
|
||||
};
|
||||
|
||||
/// CCAssignFn - This function assigns a location for Val, updating State to
|
||||
/// reflect the change. It returns 'true' if it failed to handle Val.
|
||||
typedef bool CCAssignFn(unsigned ValNo, MVT ValVT,
|
||||
MVT LocVT, CCValAssign::LocInfo LocInfo,
|
||||
ISD::ArgFlagsTy ArgFlags, CCState &State);
|
||||
|
||||
/// CCCustomFn - This function assigns a location for Val, possibly updating
|
||||
/// all args to reflect changes and indicates if it handled it. It must set
|
||||
/// isCustom if it handles the arg and returns true.
|
||||
typedef bool CCCustomFn(unsigned &ValNo, MVT &ValVT,
|
||||
MVT &LocVT, CCValAssign::LocInfo &LocInfo,
|
||||
ISD::ArgFlagsTy &ArgFlags, CCState &State);
|
||||
|
||||
/// CCState - This class holds information needed while lowering arguments and
|
||||
/// return values. It captures which registers are already assigned and which
|
||||
/// stack slots are used. It provides accessors to allocate these values.
|
||||
class CCState {
|
||||
private:
|
||||
CallingConv::ID CallingConv;
|
||||
bool IsVarArg;
|
||||
bool AnalyzingMustTailForwardedRegs = false;
|
||||
MachineFunction &MF;
|
||||
const TargetRegisterInfo &TRI;
|
||||
SmallVectorImpl<CCValAssign> &Locs;
|
||||
LLVMContext &Context;
|
||||
|
||||
unsigned StackOffset;
|
||||
Align MaxStackArgAlign;
|
||||
SmallVector<uint32_t, 16> UsedRegs;
|
||||
SmallVector<CCValAssign, 4> PendingLocs;
|
||||
SmallVector<ISD::ArgFlagsTy, 4> PendingArgFlags;
|
||||
|
||||
// ByValInfo and SmallVector<ByValInfo, 4> ByValRegs:
|
||||
//
|
||||
// Vector of ByValInfo instances (ByValRegs) is introduced for byval registers
|
||||
// tracking.
|
||||
// Or, in another words it tracks byval parameters that are stored in
|
||||
// general purpose registers.
|
||||
//
|
||||
// For 4 byte stack alignment,
|
||||
// instance index means byval parameter number in formal
|
||||
// arguments set. Assume, we have some "struct_type" with size = 4 bytes,
|
||||
// then, for function "foo":
|
||||
//
|
||||
// i32 foo(i32 %p, %struct_type* %r, i32 %s, %struct_type* %t)
|
||||
//
|
||||
// ByValRegs[0] describes how "%r" is stored (Begin == r1, End == r2)
|
||||
// ByValRegs[1] describes how "%t" is stored (Begin == r3, End == r4).
|
||||
//
|
||||
// In case of 8 bytes stack alignment,
|
||||
// In function shown above, r3 would be wasted according to AAPCS rules.
|
||||
// ByValRegs vector size still would be 2,
|
||||
// while "%t" goes to the stack: it wouldn't be described in ByValRegs.
|
||||
//
|
||||
// Supposed use-case for this collection:
|
||||
// 1. Initially ByValRegs is empty, InRegsParamsProcessed is 0.
|
||||
// 2. HandleByVal fills up ByValRegs.
|
||||
// 3. Argument analysis (LowerFormatArguments, for example). After
|
||||
// some byval argument was analyzed, InRegsParamsProcessed is increased.
|
||||
struct ByValInfo {
|
||||
ByValInfo(unsigned B, unsigned E) : Begin(B), End(E) {}
|
||||
|
||||
// First register allocated for current parameter.
|
||||
unsigned Begin;
|
||||
|
||||
// First after last register allocated for current parameter.
|
||||
unsigned End;
|
||||
};
|
||||
SmallVector<ByValInfo, 4 > ByValRegs;
|
||||
|
||||
// InRegsParamsProcessed - shows how many instances of ByValRegs was proceed
|
||||
// during argument analysis.
|
||||
unsigned InRegsParamsProcessed;
|
||||
|
||||
public:
|
||||
CCState(CallingConv::ID CC, bool isVarArg, MachineFunction &MF,
|
||||
SmallVectorImpl<CCValAssign> &locs, LLVMContext &C);
|
||||
|
||||
void addLoc(const CCValAssign &V) {
|
||||
Locs.push_back(V);
|
||||
}
|
||||
|
||||
LLVMContext &getContext() const { return Context; }
|
||||
MachineFunction &getMachineFunction() const { return MF; }
|
||||
CallingConv::ID getCallingConv() const { return CallingConv; }
|
||||
bool isVarArg() const { return IsVarArg; }
|
||||
|
||||
/// getNextStackOffset - Return the next stack offset such that all stack
|
||||
/// slots satisfy their alignment requirements.
|
||||
unsigned getNextStackOffset() const {
|
||||
return StackOffset;
|
||||
}
|
||||
|
||||
/// getAlignedCallFrameSize - Return the size of the call frame needed to
|
||||
/// be able to store all arguments and such that the alignment requirement
|
||||
/// of each of the arguments is satisfied.
|
||||
unsigned getAlignedCallFrameSize() const {
|
||||
return alignTo(StackOffset, MaxStackArgAlign);
|
||||
}
|
||||
|
||||
/// isAllocated - Return true if the specified register (or an alias) is
|
||||
/// allocated.
|
||||
bool isAllocated(MCRegister Reg) const {
|
||||
return UsedRegs[Reg / 32] & (1 << (Reg & 31));
|
||||
}
|
||||
|
||||
/// AnalyzeFormalArguments - Analyze an array of argument values,
|
||||
/// incorporating info about the formals into this state.
|
||||
void AnalyzeFormalArguments(const SmallVectorImpl<ISD::InputArg> &Ins,
|
||||
CCAssignFn Fn);
|
||||
|
||||
/// The function will invoke AnalyzeFormalArguments.
|
||||
void AnalyzeArguments(const SmallVectorImpl<ISD::InputArg> &Ins,
|
||||
CCAssignFn Fn) {
|
||||
AnalyzeFormalArguments(Ins, Fn);
|
||||
}
|
||||
|
||||
/// AnalyzeReturn - Analyze the returned values of a return,
|
||||
/// incorporating info about the result values into this state.
|
||||
void AnalyzeReturn(const SmallVectorImpl<ISD::OutputArg> &Outs,
|
||||
CCAssignFn Fn);
|
||||
|
||||
/// CheckReturn - Analyze the return values of a function, returning
|
||||
/// true if the return can be performed without sret-demotion, and
|
||||
/// false otherwise.
|
||||
bool CheckReturn(const SmallVectorImpl<ISD::OutputArg> &Outs,
|
||||
CCAssignFn Fn);
|
||||
|
||||
/// AnalyzeCallOperands - Analyze the outgoing arguments to a call,
|
||||
/// incorporating info about the passed values into this state.
|
||||
void AnalyzeCallOperands(const SmallVectorImpl<ISD::OutputArg> &Outs,
|
||||
CCAssignFn Fn);
|
||||
|
||||
/// AnalyzeCallOperands - Same as above except it takes vectors of types
|
||||
/// and argument flags.
|
||||
void AnalyzeCallOperands(SmallVectorImpl<MVT> &ArgVTs,
|
||||
SmallVectorImpl<ISD::ArgFlagsTy> &Flags,
|
||||
CCAssignFn Fn);
|
||||
|
||||
/// The function will invoke AnalyzeCallOperands.
|
||||
void AnalyzeArguments(const SmallVectorImpl<ISD::OutputArg> &Outs,
|
||||
CCAssignFn Fn) {
|
||||
AnalyzeCallOperands(Outs, Fn);
|
||||
}
|
||||
|
||||
/// AnalyzeCallResult - Analyze the return values of a call,
|
||||
/// incorporating info about the passed values into this state.
|
||||
void AnalyzeCallResult(const SmallVectorImpl<ISD::InputArg> &Ins,
|
||||
CCAssignFn Fn);
|
||||
|
||||
/// A shadow allocated register is a register that was allocated
|
||||
/// but wasn't added to the location list (Locs).
|
||||
/// \returns true if the register was allocated as shadow or false otherwise.
|
||||
bool IsShadowAllocatedReg(MCRegister Reg) const;
|
||||
|
||||
/// AnalyzeCallResult - Same as above except it's specialized for calls which
|
||||
/// produce a single value.
|
||||
void AnalyzeCallResult(MVT VT, CCAssignFn Fn);
|
||||
|
||||
/// getFirstUnallocated - Return the index of the first unallocated register
|
||||
/// in the set, or Regs.size() if they are all allocated.
|
||||
unsigned getFirstUnallocated(ArrayRef<MCPhysReg> Regs) const {
|
||||
for (unsigned i = 0; i < Regs.size(); ++i)
|
||||
if (!isAllocated(Regs[i]))
|
||||
return i;
|
||||
return Regs.size();
|
||||
}
|
||||
|
||||
void DeallocateReg(MCPhysReg Reg) {
|
||||
assert(isAllocated(Reg) && "Trying to deallocate an unallocated register");
|
||||
MarkUnallocated(Reg);
|
||||
}
|
||||
|
||||
/// AllocateReg - Attempt to allocate one register. If it is not available,
|
||||
/// return zero. Otherwise, return the register, marking it and any aliases
|
||||
/// as allocated.
|
||||
MCRegister AllocateReg(MCPhysReg Reg) {
|
||||
if (isAllocated(Reg))
|
||||
return MCRegister();
|
||||
MarkAllocated(Reg);
|
||||
return Reg;
|
||||
}
|
||||
|
||||
/// Version of AllocateReg with extra register to be shadowed.
|
||||
MCRegister AllocateReg(MCPhysReg Reg, MCPhysReg ShadowReg) {
|
||||
if (isAllocated(Reg))
|
||||
return MCRegister();
|
||||
MarkAllocated(Reg);
|
||||
MarkAllocated(ShadowReg);
|
||||
return Reg;
|
||||
}
|
||||
|
||||
/// AllocateReg - Attempt to allocate one of the specified registers. If none
|
||||
/// are available, return zero. Otherwise, return the first one available,
|
||||
/// marking it and any aliases as allocated.
|
||||
MCPhysReg AllocateReg(ArrayRef<MCPhysReg> Regs) {
|
||||
unsigned FirstUnalloc = getFirstUnallocated(Regs);
|
||||
if (FirstUnalloc == Regs.size())
|
||||
return MCRegister(); // Didn't find the reg.
|
||||
|
||||
// Mark the register and any aliases as allocated.
|
||||
MCPhysReg Reg = Regs[FirstUnalloc];
|
||||
MarkAllocated(Reg);
|
||||
return Reg;
|
||||
}
|
||||
|
||||
/// AllocateRegBlock - Attempt to allocate a block of RegsRequired consecutive
|
||||
/// registers. If this is not possible, return zero. Otherwise, return the first
|
||||
/// register of the block that were allocated, marking the entire block as allocated.
|
||||
MCPhysReg AllocateRegBlock(ArrayRef<MCPhysReg> Regs, unsigned RegsRequired) {
|
||||
if (RegsRequired > Regs.size())
|
||||
return 0;
|
||||
|
||||
for (unsigned StartIdx = 0; StartIdx <= Regs.size() - RegsRequired;
|
||||
++StartIdx) {
|
||||
bool BlockAvailable = true;
|
||||
// Check for already-allocated regs in this block
|
||||
for (unsigned BlockIdx = 0; BlockIdx < RegsRequired; ++BlockIdx) {
|
||||
if (isAllocated(Regs[StartIdx + BlockIdx])) {
|
||||
BlockAvailable = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (BlockAvailable) {
|
||||
// Mark the entire block as allocated
|
||||
for (unsigned BlockIdx = 0; BlockIdx < RegsRequired; ++BlockIdx) {
|
||||
MarkAllocated(Regs[StartIdx + BlockIdx]);
|
||||
}
|
||||
return Regs[StartIdx];
|
||||
}
|
||||
}
|
||||
// No block was available
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Version of AllocateReg with list of registers to be shadowed.
|
||||
MCRegister AllocateReg(ArrayRef<MCPhysReg> Regs, const MCPhysReg *ShadowRegs) {
|
||||
unsigned FirstUnalloc = getFirstUnallocated(Regs);
|
||||
if (FirstUnalloc == Regs.size())
|
||||
return MCRegister(); // Didn't find the reg.
|
||||
|
||||
// Mark the register and any aliases as allocated.
|
||||
MCRegister Reg = Regs[FirstUnalloc], ShadowReg = ShadowRegs[FirstUnalloc];
|
||||
MarkAllocated(Reg);
|
||||
MarkAllocated(ShadowReg);
|
||||
return Reg;
|
||||
}
|
||||
|
||||
/// AllocateStack - Allocate a chunk of stack space with the specified size
|
||||
/// and alignment.
|
||||
unsigned AllocateStack(unsigned Size, Align Alignment) {
|
||||
StackOffset = alignTo(StackOffset, Alignment);
|
||||
unsigned Result = StackOffset;
|
||||
StackOffset += Size;
|
||||
MaxStackArgAlign = std::max(Alignment, MaxStackArgAlign);
|
||||
ensureMaxAlignment(Alignment);
|
||||
return Result;
|
||||
}
|
||||
|
||||
void ensureMaxAlignment(Align Alignment);
|
||||
|
||||
/// Version of AllocateStack with list of extra registers to be shadowed.
|
||||
/// Note that, unlike AllocateReg, this shadows ALL of the shadow registers.
|
||||
unsigned AllocateStack(unsigned Size, Align Alignment,
|
||||
ArrayRef<MCPhysReg> ShadowRegs) {
|
||||
for (unsigned i = 0; i < ShadowRegs.size(); ++i)
|
||||
MarkAllocated(ShadowRegs[i]);
|
||||
return AllocateStack(Size, Alignment);
|
||||
}
|
||||
|
||||
// HandleByVal - Allocate a stack slot large enough to pass an argument by
|
||||
// value. The size and alignment information of the argument is encoded in its
|
||||
// parameter attribute.
|
||||
void HandleByVal(unsigned ValNo, MVT ValVT, MVT LocVT,
|
||||
CCValAssign::LocInfo LocInfo, int MinSize, Align MinAlign,
|
||||
ISD::ArgFlagsTy ArgFlags);
|
||||
|
||||
// Returns count of byval arguments that are to be stored (even partly)
|
||||
// in registers.
|
||||
unsigned getInRegsParamsCount() const { return ByValRegs.size(); }
|
||||
|
||||
// Returns count of byval in-regs arguments processed.
|
||||
unsigned getInRegsParamsProcessed() const { return InRegsParamsProcessed; }
|
||||
|
||||
// Get information about N-th byval parameter that is stored in registers.
|
||||
// Here "ByValParamIndex" is N.
|
||||
void getInRegsParamInfo(unsigned InRegsParamRecordIndex,
|
||||
unsigned& BeginReg, unsigned& EndReg) const {
|
||||
assert(InRegsParamRecordIndex < ByValRegs.size() &&
|
||||
"Wrong ByVal parameter index");
|
||||
|
||||
const ByValInfo& info = ByValRegs[InRegsParamRecordIndex];
|
||||
BeginReg = info.Begin;
|
||||
EndReg = info.End;
|
||||
}
|
||||
|
||||
// Add information about parameter that is kept in registers.
|
||||
void addInRegsParamInfo(unsigned RegBegin, unsigned RegEnd) {
|
||||
ByValRegs.push_back(ByValInfo(RegBegin, RegEnd));
|
||||
}
|
||||
|
||||
// Goes either to next byval parameter (excluding "waste" record), or
|
||||
// to the end of collection.
|
||||
// Returns false, if end is reached.
|
||||
bool nextInRegsParam() {
|
||||
unsigned e = ByValRegs.size();
|
||||
if (InRegsParamsProcessed < e)
|
||||
++InRegsParamsProcessed;
|
||||
return InRegsParamsProcessed < e;
|
||||
}
|
||||
|
||||
// Clear byval registers tracking info.
|
||||
void clearByValRegsInfo() {
|
||||
InRegsParamsProcessed = 0;
|
||||
ByValRegs.clear();
|
||||
}
|
||||
|
||||
// Rewind byval registers tracking info.
|
||||
void rewindByValRegsInfo() {
|
||||
InRegsParamsProcessed = 0;
|
||||
}
|
||||
|
||||
// Get list of pending assignments
|
||||
SmallVectorImpl<CCValAssign> &getPendingLocs() {
|
||||
return PendingLocs;
|
||||
}
|
||||
|
||||
// Get a list of argflags for pending assignments.
|
||||
SmallVectorImpl<ISD::ArgFlagsTy> &getPendingArgFlags() {
|
||||
return PendingArgFlags;
|
||||
}
|
||||
|
||||
/// Compute the remaining unused register parameters that would be used for
|
||||
/// the given value type. This is useful when varargs are passed in the
|
||||
/// registers that normal prototyped parameters would be passed in, or for
|
||||
/// implementing perfect forwarding.
|
||||
void getRemainingRegParmsForType(SmallVectorImpl<MCPhysReg> &Regs, MVT VT,
|
||||
CCAssignFn Fn);
|
||||
|
||||
/// Compute the set of registers that need to be preserved and forwarded to
|
||||
/// any musttail calls.
|
||||
void analyzeMustTailForwardedRegisters(
|
||||
SmallVectorImpl<ForwardedRegister> &Forwards, ArrayRef<MVT> RegParmTypes,
|
||||
CCAssignFn Fn);
|
||||
|
||||
/// Returns true if the results of the two calling conventions are compatible.
|
||||
/// This is usually part of the check for tailcall eligibility.
|
||||
static bool resultsCompatible(CallingConv::ID CalleeCC,
|
||||
CallingConv::ID CallerCC, MachineFunction &MF,
|
||||
LLVMContext &C,
|
||||
const SmallVectorImpl<ISD::InputArg> &Ins,
|
||||
CCAssignFn CalleeFn, CCAssignFn CallerFn);
|
||||
|
||||
/// The function runs an additional analysis pass over function arguments.
|
||||
/// It will mark each argument with the attribute flag SecArgPass.
|
||||
/// After running, it will sort the locs list.
|
||||
template <class T>
|
||||
void AnalyzeArgumentsSecondPass(const SmallVectorImpl<T> &Args,
|
||||
CCAssignFn Fn) {
|
||||
unsigned NumFirstPassLocs = Locs.size();
|
||||
|
||||
/// Creates similar argument list to \p Args in which each argument is
|
||||
/// marked using SecArgPass flag.
|
||||
SmallVector<T, 16> SecPassArg;
|
||||
// SmallVector<ISD::InputArg, 16> SecPassArg;
|
||||
for (auto Arg : Args) {
|
||||
Arg.Flags.setSecArgPass();
|
||||
SecPassArg.push_back(Arg);
|
||||
}
|
||||
|
||||
// Run the second argument pass
|
||||
AnalyzeArguments(SecPassArg, Fn);
|
||||
|
||||
// Sort the locations of the arguments according to their original position.
|
||||
SmallVector<CCValAssign, 16> TmpArgLocs;
|
||||
TmpArgLocs.swap(Locs);
|
||||
auto B = TmpArgLocs.begin(), E = TmpArgLocs.end();
|
||||
std::merge(B, B + NumFirstPassLocs, B + NumFirstPassLocs, E,
|
||||
std::back_inserter(Locs),
|
||||
[](const CCValAssign &A, const CCValAssign &B) -> bool {
|
||||
return A.getValNo() < B.getValNo();
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
/// MarkAllocated - Mark a register and all of its aliases as allocated.
|
||||
void MarkAllocated(MCPhysReg Reg);
|
||||
|
||||
void MarkUnallocated(MCPhysReg Reg);
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_CALLINGCONVLOWER_H
|
||||
219
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/CodeGenCommonISel.h
vendored
Normal file
219
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/CodeGenCommonISel.h
vendored
Normal file
@@ -0,0 +1,219 @@
|
||||
//===- CodeGenCommonISel.h - Common code between ISels ---------*- 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 file declares common utilities that are shared between SelectionDAG and
|
||||
// GlobalISel frameworks.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_CODEGENCOMMONISEL_H
|
||||
#define LLVM_CODEGEN_CODEGENCOMMONISEL_H
|
||||
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include <cassert>
|
||||
namespace llvm {
|
||||
|
||||
class BasicBlock;
|
||||
class MachineBasicBlock;
|
||||
/// Encapsulates all of the information needed to generate a stack protector
|
||||
/// check, and signals to isel when initialized that one needs to be generated.
|
||||
///
|
||||
/// *NOTE* The following is a high level documentation of SelectionDAG Stack
|
||||
/// Protector Generation. This is now also ported be shared with GlobalISel,
|
||||
/// but without any significant changes.
|
||||
///
|
||||
/// High Level Overview of ISel Stack Protector Generation:
|
||||
///
|
||||
/// Previously, the "stack protector" IR pass handled stack protector
|
||||
/// generation. This necessitated splitting basic blocks at the IR level to
|
||||
/// create the success/failure basic blocks in the tail of the basic block in
|
||||
/// question. As a result of this, calls that would have qualified for the
|
||||
/// sibling call optimization were no longer eligible for optimization since
|
||||
/// said calls were no longer right in the "tail position" (i.e. the immediate
|
||||
/// predecessor of a ReturnInst instruction).
|
||||
///
|
||||
/// Since the sibling call optimization causes the callee to reuse the caller's
|
||||
/// stack, if we could delay the generation of the stack protector check until
|
||||
/// later in CodeGen after the sibling call decision was made, we get both the
|
||||
/// tail call optimization and the stack protector check!
|
||||
///
|
||||
/// A few goals in solving this problem were:
|
||||
///
|
||||
/// 1. Preserve the architecture independence of stack protector generation.
|
||||
///
|
||||
/// 2. Preserve the normal IR level stack protector check for platforms like
|
||||
/// OpenBSD for which we support platform-specific stack protector
|
||||
/// generation.
|
||||
///
|
||||
/// The main problem that guided the present solution is that one can not
|
||||
/// solve this problem in an architecture independent manner at the IR level
|
||||
/// only. This is because:
|
||||
///
|
||||
/// 1. The decision on whether or not to perform a sibling call on certain
|
||||
/// platforms (for instance i386) requires lower level information
|
||||
/// related to available registers that can not be known at the IR level.
|
||||
///
|
||||
/// 2. Even if the previous point were not true, the decision on whether to
|
||||
/// perform a tail call is done in LowerCallTo in SelectionDAG (or
|
||||
/// CallLowering in GlobalISel) which occurs after the Stack Protector
|
||||
/// Pass. As a result, one would need to put the relevant callinst into the
|
||||
/// stack protector check success basic block (where the return inst is
|
||||
/// placed) and then move it back later at ISel/MI time before the
|
||||
/// stack protector check if the tail call optimization failed. The MI
|
||||
/// level option was nixed immediately since it would require
|
||||
/// platform-specific pattern matching. The ISel level option was
|
||||
/// nixed because SelectionDAG only processes one IR level basic block at a
|
||||
/// time implying one could not create a DAG Combine to move the callinst.
|
||||
///
|
||||
/// To get around this problem:
|
||||
///
|
||||
/// 1. SelectionDAG can only process one block at a time, we can generate
|
||||
/// multiple machine basic blocks for one IR level basic block.
|
||||
/// This is how we handle bit tests and switches.
|
||||
///
|
||||
/// 2. At the MI level, tail calls are represented via a special return
|
||||
/// MIInst called "tcreturn". Thus if we know the basic block in which we
|
||||
/// wish to insert the stack protector check, we get the correct behavior
|
||||
/// by always inserting the stack protector check right before the return
|
||||
/// statement. This is a "magical transformation" since no matter where
|
||||
/// the stack protector check intrinsic is, we always insert the stack
|
||||
/// protector check code at the end of the BB.
|
||||
///
|
||||
/// Given the aforementioned constraints, the following solution was devised:
|
||||
///
|
||||
/// 1. On platforms that do not support ISel stack protector check
|
||||
/// generation, allow for the normal IR level stack protector check
|
||||
/// generation to continue.
|
||||
///
|
||||
/// 2. On platforms that do support ISel stack protector check
|
||||
/// generation:
|
||||
///
|
||||
/// a. Use the IR level stack protector pass to decide if a stack
|
||||
/// protector is required/which BB we insert the stack protector check
|
||||
/// in by reusing the logic already therein.
|
||||
///
|
||||
/// b. After we finish selecting the basic block, we produce the validation
|
||||
/// code with one of these techniques:
|
||||
/// 1) with a call to a guard check function
|
||||
/// 2) with inlined instrumentation
|
||||
///
|
||||
/// 1) We insert a call to the check function before the terminator.
|
||||
///
|
||||
/// 2) We first find a splice point in the parent basic block
|
||||
/// before the terminator and then splice the terminator of said basic
|
||||
/// block into the success basic block. Then we code-gen a new tail for
|
||||
/// the parent basic block consisting of the two loads, the comparison,
|
||||
/// and finally two branches to the success/failure basic blocks. We
|
||||
/// conclude by code-gening the failure basic block if we have not
|
||||
/// code-gened it already (all stack protector checks we generate in
|
||||
/// the same function, use the same failure basic block).
|
||||
class StackProtectorDescriptor {
|
||||
public:
|
||||
StackProtectorDescriptor() = default;
|
||||
|
||||
/// Returns true if all fields of the stack protector descriptor are
|
||||
/// initialized implying that we should/are ready to emit a stack protector.
|
||||
bool shouldEmitStackProtector() const {
|
||||
return ParentMBB && SuccessMBB && FailureMBB;
|
||||
}
|
||||
|
||||
bool shouldEmitFunctionBasedCheckStackProtector() const {
|
||||
return ParentMBB && !SuccessMBB && !FailureMBB;
|
||||
}
|
||||
|
||||
/// Initialize the stack protector descriptor structure for a new basic
|
||||
/// block.
|
||||
void initialize(const BasicBlock *BB, MachineBasicBlock *MBB,
|
||||
bool FunctionBasedInstrumentation) {
|
||||
// Make sure we are not initialized yet.
|
||||
assert(!shouldEmitStackProtector() && "Stack Protector Descriptor is "
|
||||
"already initialized!");
|
||||
ParentMBB = MBB;
|
||||
if (!FunctionBasedInstrumentation) {
|
||||
SuccessMBB = addSuccessorMBB(BB, MBB, /* IsLikely */ true);
|
||||
FailureMBB = addSuccessorMBB(BB, MBB, /* IsLikely */ false, FailureMBB);
|
||||
}
|
||||
}
|
||||
|
||||
/// Reset state that changes when we handle different basic blocks.
|
||||
///
|
||||
/// This currently includes:
|
||||
///
|
||||
/// 1. The specific basic block we are generating a
|
||||
/// stack protector for (ParentMBB).
|
||||
///
|
||||
/// 2. The successor machine basic block that will contain the tail of
|
||||
/// parent mbb after we create the stack protector check (SuccessMBB). This
|
||||
/// BB is visited only on stack protector check success.
|
||||
void resetPerBBState() {
|
||||
ParentMBB = nullptr;
|
||||
SuccessMBB = nullptr;
|
||||
}
|
||||
|
||||
/// Reset state that only changes when we switch functions.
|
||||
///
|
||||
/// This currently includes:
|
||||
///
|
||||
/// 1. FailureMBB since we reuse the failure code path for all stack
|
||||
/// protector checks created in an individual function.
|
||||
///
|
||||
/// 2.The guard variable since the guard variable we are checking against is
|
||||
/// always the same.
|
||||
void resetPerFunctionState() { FailureMBB = nullptr; }
|
||||
|
||||
MachineBasicBlock *getParentMBB() { return ParentMBB; }
|
||||
MachineBasicBlock *getSuccessMBB() { return SuccessMBB; }
|
||||
MachineBasicBlock *getFailureMBB() { return FailureMBB; }
|
||||
|
||||
private:
|
||||
/// The basic block for which we are generating the stack protector.
|
||||
///
|
||||
/// As a result of stack protector generation, we will splice the
|
||||
/// terminators of this basic block into the successor mbb SuccessMBB and
|
||||
/// replace it with a compare/branch to the successor mbbs
|
||||
/// SuccessMBB/FailureMBB depending on whether or not the stack protector
|
||||
/// was violated.
|
||||
MachineBasicBlock *ParentMBB = nullptr;
|
||||
|
||||
/// A basic block visited on stack protector check success that contains the
|
||||
/// terminators of ParentMBB.
|
||||
MachineBasicBlock *SuccessMBB = nullptr;
|
||||
|
||||
/// This basic block visited on stack protector check failure that will
|
||||
/// contain a call to __stack_chk_fail().
|
||||
MachineBasicBlock *FailureMBB = nullptr;
|
||||
|
||||
/// Add a successor machine basic block to ParentMBB. If the successor mbb
|
||||
/// has not been created yet (i.e. if SuccMBB = 0), then the machine basic
|
||||
/// block will be created. Assign a large weight if IsLikely is true.
|
||||
MachineBasicBlock *addSuccessorMBB(const BasicBlock *BB,
|
||||
MachineBasicBlock *ParentMBB,
|
||||
bool IsLikely,
|
||||
MachineBasicBlock *SuccMBB = nullptr);
|
||||
};
|
||||
|
||||
/// Find the split point at which to splice the end of BB into its success stack
|
||||
/// protector check machine basic block.
|
||||
///
|
||||
/// On many platforms, due to ABI constraints, terminators, even before register
|
||||
/// allocation, use physical registers. This creates an issue for us since
|
||||
/// physical registers at this point can not travel across basic
|
||||
/// blocks. Luckily, selectiondag always moves physical registers into vregs
|
||||
/// when they enter functions and moves them through a sequence of copies back
|
||||
/// into the physical registers right before the terminator creating a
|
||||
/// ``Terminator Sequence''. This function is searching for the beginning of the
|
||||
/// terminator sequence so that we can ensure that we splice off not just the
|
||||
/// terminator, but additionally the copies that move the vregs into the
|
||||
/// physical registers.
|
||||
MachineBasicBlock::iterator
|
||||
findSplitPointForStackProtector(MachineBasicBlock *BB,
|
||||
const TargetInstrInfo &TII);
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_CODEGENCOMMONISEL_H
|
||||
1150
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/CodeGenPassBuilder.h
vendored
Normal file
1150
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/CodeGenPassBuilder.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
181
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/CommandFlags.h
vendored
Normal file
181
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/CommandFlags.h
vendored
Normal file
@@ -0,0 +1,181 @@
|
||||
//===-- CommandFlags.h - Command Line Flags Interface -----------*- 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 file contains codegen-specific flags that are shared between different
|
||||
// command line tools. The tools "llc" and "opt" both use this file to prevent
|
||||
// flag duplication.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_COMMANDFLAGS_H
|
||||
#define LLVM_CODEGEN_COMMANDFLAGS_H
|
||||
|
||||
#include "llvm/ADT/FloatingPointMode.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/Intrinsics.h"
|
||||
#include "llvm/MC/MCTargetOptionsCommandFlags.h"
|
||||
#include "llvm/Support/CodeGen.h"
|
||||
#include "llvm/Target/TargetOptions.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Module;
|
||||
|
||||
namespace codegen {
|
||||
|
||||
std::string getMArch();
|
||||
|
||||
std::string getMCPU();
|
||||
|
||||
std::vector<std::string> getMAttrs();
|
||||
|
||||
Reloc::Model getRelocModel();
|
||||
Optional<Reloc::Model> getExplicitRelocModel();
|
||||
|
||||
ThreadModel::Model getThreadModel();
|
||||
|
||||
CodeModel::Model getCodeModel();
|
||||
Optional<CodeModel::Model> getExplicitCodeModel();
|
||||
|
||||
llvm::ExceptionHandling getExceptionModel();
|
||||
|
||||
Optional<CodeGenFileType> getExplicitFileType();
|
||||
|
||||
CodeGenFileType getFileType();
|
||||
|
||||
FramePointerKind getFramePointerUsage();
|
||||
|
||||
bool getEnableUnsafeFPMath();
|
||||
|
||||
bool getEnableNoInfsFPMath();
|
||||
|
||||
bool getEnableNoNaNsFPMath();
|
||||
|
||||
bool getEnableNoSignedZerosFPMath();
|
||||
|
||||
bool getEnableNoTrappingFPMath();
|
||||
|
||||
DenormalMode::DenormalModeKind getDenormalFPMath();
|
||||
DenormalMode::DenormalModeKind getDenormalFP32Math();
|
||||
|
||||
bool getEnableHonorSignDependentRoundingFPMath();
|
||||
|
||||
llvm::FloatABI::ABIType getFloatABIForCalls();
|
||||
|
||||
llvm::FPOpFusion::FPOpFusionMode getFuseFPOps();
|
||||
|
||||
SwiftAsyncFramePointerMode getSwiftAsyncFramePointer();
|
||||
|
||||
bool getDontPlaceZerosInBSS();
|
||||
|
||||
bool getEnableGuaranteedTailCallOpt();
|
||||
|
||||
bool getEnableAIXExtendedAltivecABI();
|
||||
|
||||
bool getDisableTailCalls();
|
||||
|
||||
bool getStackSymbolOrdering();
|
||||
|
||||
unsigned getOverrideStackAlignment();
|
||||
|
||||
bool getStackRealign();
|
||||
|
||||
std::string getTrapFuncName();
|
||||
|
||||
bool getUseCtors();
|
||||
|
||||
bool getRelaxELFRelocations();
|
||||
|
||||
bool getDataSections();
|
||||
Optional<bool> getExplicitDataSections();
|
||||
|
||||
bool getFunctionSections();
|
||||
Optional<bool> getExplicitFunctionSections();
|
||||
|
||||
bool getIgnoreXCOFFVisibility();
|
||||
|
||||
bool getXCOFFTracebackTable();
|
||||
|
||||
std::string getBBSections();
|
||||
|
||||
unsigned getTLSSize();
|
||||
|
||||
bool getEmulatedTLS();
|
||||
|
||||
bool getUniqueSectionNames();
|
||||
|
||||
bool getUniqueBasicBlockSectionNames();
|
||||
|
||||
llvm::EABI getEABIVersion();
|
||||
|
||||
llvm::DebuggerKind getDebuggerTuningOpt();
|
||||
|
||||
bool getEnableStackSizeSection();
|
||||
|
||||
bool getEnableAddrsig();
|
||||
|
||||
bool getEmitCallSiteInfo();
|
||||
|
||||
bool getEnableMachineFunctionSplitter();
|
||||
|
||||
bool getEnableDebugEntryValues();
|
||||
|
||||
bool getValueTrackingVariableLocations();
|
||||
Optional<bool> getExplicitValueTrackingVariableLocations();
|
||||
|
||||
bool getForceDwarfFrameSection();
|
||||
|
||||
bool getXRayOmitFunctionIndex();
|
||||
|
||||
bool getDebugStrictDwarf();
|
||||
|
||||
unsigned getAlignLoops();
|
||||
|
||||
/// Create this object with static storage to register codegen-related command
|
||||
/// line options.
|
||||
struct RegisterCodeGenFlags {
|
||||
RegisterCodeGenFlags();
|
||||
};
|
||||
|
||||
llvm::BasicBlockSection getBBSectionsMode(llvm::TargetOptions &Options);
|
||||
|
||||
/// Common utility function tightly tied to the options listed here. Initializes
|
||||
/// a TargetOptions object with CodeGen flags and returns it.
|
||||
/// \p TheTriple is used to determine the default value for options if
|
||||
/// options are not explicitly specified. If those triple dependant options
|
||||
/// value do not have effect for your component, a default Triple() could be
|
||||
/// passed in.
|
||||
TargetOptions InitTargetOptionsFromCodeGenFlags(const llvm::Triple &TheTriple);
|
||||
|
||||
std::string getCPUStr();
|
||||
|
||||
std::string getFeaturesStr();
|
||||
|
||||
std::vector<std::string> getFeatureList();
|
||||
|
||||
void renderBoolStringAttr(AttrBuilder &B, StringRef Name, bool Val);
|
||||
|
||||
/// Set function attributes of function \p F based on CPU, Features, and command
|
||||
/// line flags.
|
||||
void setFunctionAttributes(StringRef CPU, StringRef Features, Function &F);
|
||||
|
||||
/// Set function attributes of functions in Module M based on CPU,
|
||||
/// Features, and command line flags.
|
||||
void setFunctionAttributes(StringRef CPU, StringRef Features, Module &M);
|
||||
|
||||
/// Should value-tracking variable locations / instruction referencing be
|
||||
/// enabled by default for this triple?
|
||||
bool getDefaultValueTrackingVariableLocations(const llvm::Triple &T);
|
||||
} // namespace codegen
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_COMMANDFLAGS_H
|
||||
89
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/CostTable.h
vendored
Normal file
89
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/CostTable.h
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
//===-- CostTable.h - Instruction Cost Table handling -----------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// Cost tables and simple lookup functions
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_COSTTABLE_H_
|
||||
#define LLVM_CODEGEN_COSTTABLE_H_
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/Support/MachineValueType.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// Cost Table Entry
|
||||
template <typename CostType>
|
||||
struct CostTblEntryT {
|
||||
int ISD;
|
||||
MVT::SimpleValueType Type;
|
||||
CostType Cost;
|
||||
};
|
||||
using CostTblEntry = CostTblEntryT<unsigned>;
|
||||
|
||||
/// Find in cost table.
|
||||
template <class CostType>
|
||||
inline const CostTblEntryT<CostType> *
|
||||
CostTableLookup(ArrayRef<CostTblEntryT<CostType>> Tbl, int ISD, MVT Ty) {
|
||||
auto I = find_if(Tbl, [=](const CostTblEntryT<CostType> &Entry) {
|
||||
return ISD == Entry.ISD && Ty == Entry.Type;
|
||||
});
|
||||
if (I != Tbl.end())
|
||||
return I;
|
||||
|
||||
// Could not find an entry.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <size_t N, class CostType>
|
||||
inline const CostTblEntryT<CostType> *
|
||||
CostTableLookup(const CostTblEntryT<CostType> (&Table)[N], int ISD, MVT Ty) {
|
||||
// Wrapper to fix template argument deduction failures.
|
||||
return CostTableLookup<CostType>(makeArrayRef(Table), ISD, Ty);
|
||||
}
|
||||
|
||||
/// Type Conversion Cost Table
|
||||
template <typename CostType>
|
||||
struct TypeConversionCostTblEntryT {
|
||||
int ISD;
|
||||
MVT::SimpleValueType Dst;
|
||||
MVT::SimpleValueType Src;
|
||||
CostType Cost;
|
||||
};
|
||||
using TypeConversionCostTblEntry = TypeConversionCostTblEntryT<unsigned>;
|
||||
|
||||
/// Find in type conversion cost table.
|
||||
template <class CostType>
|
||||
inline const TypeConversionCostTblEntryT<CostType> *
|
||||
ConvertCostTableLookup(ArrayRef<TypeConversionCostTblEntryT<CostType>> Tbl,
|
||||
int ISD, MVT Dst, MVT Src) {
|
||||
auto I =
|
||||
find_if(Tbl, [=](const TypeConversionCostTblEntryT<CostType> &Entry) {
|
||||
return ISD == Entry.ISD && Src == Entry.Src && Dst == Entry.Dst;
|
||||
});
|
||||
if (I != Tbl.end())
|
||||
return I;
|
||||
|
||||
// Could not find an entry.
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <size_t N, class CostType>
|
||||
inline const TypeConversionCostTblEntryT<CostType> *
|
||||
ConvertCostTableLookup(const TypeConversionCostTblEntryT<CostType> (&Table)[N],
|
||||
int ISD, MVT Dst, MVT Src) {
|
||||
// Wrapper to fix template argument deduction failures.
|
||||
return ConvertCostTableLookup<CostType>(makeArrayRef(Table), ISD, Dst, Src);
|
||||
}
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif /* LLVM_CODEGEN_COSTTABLE_H_ */
|
||||
24
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/DAGCombine.h
vendored
Normal file
24
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/DAGCombine.h
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
//===-- llvm/CodeGen/DAGCombine.h ------- SelectionDAG Nodes ---*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
|
||||
#ifndef LLVM_CODEGEN_DAGCOMBINE_H
|
||||
#define LLVM_CODEGEN_DAGCOMBINE_H
|
||||
|
||||
namespace llvm {
|
||||
|
||||
enum CombineLevel {
|
||||
BeforeLegalizeTypes,
|
||||
AfterLegalizeTypes,
|
||||
AfterLegalizeVectorOps,
|
||||
AfterLegalizeDAG
|
||||
};
|
||||
|
||||
} // end llvm namespace
|
||||
|
||||
#endif
|
||||
200
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/DFAPacketizer.h
vendored
Normal file
200
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/DFAPacketizer.h
vendored
Normal file
@@ -0,0 +1,200 @@
|
||||
//===- llvm/CodeGen/DFAPacketizer.h - DFA Packetizer for VLIW ---*- 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 class implements a deterministic finite automaton (DFA) based
|
||||
// packetizing mechanism for VLIW architectures. It provides APIs to
|
||||
// determine whether there exists a legal mapping of instructions to
|
||||
// functional unit assignments in a packet. The DFA is auto-generated from
|
||||
// the target's Schedule.td file.
|
||||
//
|
||||
// A DFA consists of 3 major elements: states, inputs, and transitions. For
|
||||
// the packetizing mechanism, the input is the set of instruction classes for
|
||||
// a target. The state models all possible combinations of functional unit
|
||||
// consumption for a given set of instructions in a packet. A transition
|
||||
// models the addition of an instruction to a packet. In the DFA constructed
|
||||
// by this class, if an instruction can be added to a packet, then a valid
|
||||
// transition exists from the corresponding state. Invalid transitions
|
||||
// indicate that the instruction cannot be added to the current packet.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_DFAPACKETIZER_H
|
||||
#define LLVM_CODEGEN_DFAPACKETIZER_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/ScheduleDAGMutation.h"
|
||||
#include "llvm/Support/Automaton.h"
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class DefaultVLIWScheduler;
|
||||
class InstrItineraryData;
|
||||
class MachineFunction;
|
||||
class MachineInstr;
|
||||
class MachineLoopInfo;
|
||||
class MCInstrDesc;
|
||||
class SUnit;
|
||||
class TargetInstrInfo;
|
||||
|
||||
class DFAPacketizer {
|
||||
private:
|
||||
const InstrItineraryData *InstrItins;
|
||||
Automaton<uint64_t> A;
|
||||
/// For every itinerary, an "action" to apply to the automaton. This removes
|
||||
/// the redundancy in actions between itinerary classes.
|
||||
ArrayRef<unsigned> ItinActions;
|
||||
|
||||
public:
|
||||
DFAPacketizer(const InstrItineraryData *InstrItins, Automaton<uint64_t> a,
|
||||
ArrayRef<unsigned> ItinActions)
|
||||
: InstrItins(InstrItins), A(std::move(a)), ItinActions(ItinActions) {
|
||||
// Start off with resource tracking disabled.
|
||||
A.enableTranscription(false);
|
||||
}
|
||||
|
||||
// Reset the current state to make all resources available.
|
||||
void clearResources() {
|
||||
A.reset();
|
||||
}
|
||||
|
||||
// Set whether this packetizer should track not just whether instructions
|
||||
// can be packetized, but also which functional units each instruction ends up
|
||||
// using after packetization.
|
||||
void setTrackResources(bool Track) {
|
||||
A.enableTranscription(Track);
|
||||
}
|
||||
|
||||
// Check if the resources occupied by a MCInstrDesc are available in
|
||||
// the current state.
|
||||
bool canReserveResources(const MCInstrDesc *MID);
|
||||
|
||||
// Reserve the resources occupied by a MCInstrDesc and change the current
|
||||
// state to reflect that change.
|
||||
void reserveResources(const MCInstrDesc *MID);
|
||||
|
||||
// Check if the resources occupied by a machine instruction are available
|
||||
// in the current state.
|
||||
bool canReserveResources(MachineInstr &MI);
|
||||
|
||||
// Reserve the resources occupied by a machine instruction and change the
|
||||
// current state to reflect that change.
|
||||
void reserveResources(MachineInstr &MI);
|
||||
|
||||
// Return the resources used by the InstIdx'th instruction added to this
|
||||
// packet. The resources are returned as a bitvector of functional units.
|
||||
//
|
||||
// Note that a bundle may be packed in multiple valid ways. This function
|
||||
// returns one arbitrary valid packing.
|
||||
//
|
||||
// Requires setTrackResources(true) to have been called.
|
||||
unsigned getUsedResources(unsigned InstIdx);
|
||||
|
||||
const InstrItineraryData *getInstrItins() const { return InstrItins; }
|
||||
};
|
||||
|
||||
// VLIWPacketizerList implements a simple VLIW packetizer using DFA. The
|
||||
// packetizer works on machine basic blocks. For each instruction I in BB,
|
||||
// the packetizer consults the DFA to see if machine resources are available
|
||||
// to execute I. If so, the packetizer checks if I depends on any instruction
|
||||
// in the current packet. If no dependency is found, I is added to current
|
||||
// packet and the machine resource is marked as taken. If any dependency is
|
||||
// found, a target API call is made to prune the dependence.
|
||||
class VLIWPacketizerList {
|
||||
protected:
|
||||
MachineFunction &MF;
|
||||
const TargetInstrInfo *TII;
|
||||
AAResults *AA;
|
||||
|
||||
// The VLIW Scheduler.
|
||||
DefaultVLIWScheduler *VLIWScheduler;
|
||||
// Vector of instructions assigned to the current packet.
|
||||
std::vector<MachineInstr*> CurrentPacketMIs;
|
||||
// DFA resource tracker.
|
||||
DFAPacketizer *ResourceTracker;
|
||||
// Map: MI -> SU.
|
||||
std::map<MachineInstr*, SUnit*> MIToSUnit;
|
||||
|
||||
public:
|
||||
// The AAResults parameter can be nullptr.
|
||||
VLIWPacketizerList(MachineFunction &MF, MachineLoopInfo &MLI,
|
||||
AAResults *AA);
|
||||
|
||||
virtual ~VLIWPacketizerList();
|
||||
|
||||
// Implement this API in the backend to bundle instructions.
|
||||
void PacketizeMIs(MachineBasicBlock *MBB,
|
||||
MachineBasicBlock::iterator BeginItr,
|
||||
MachineBasicBlock::iterator EndItr);
|
||||
|
||||
// Return the ResourceTracker.
|
||||
DFAPacketizer *getResourceTracker() {return ResourceTracker;}
|
||||
|
||||
// addToPacket - Add MI to the current packet.
|
||||
virtual MachineBasicBlock::iterator addToPacket(MachineInstr &MI) {
|
||||
CurrentPacketMIs.push_back(&MI);
|
||||
ResourceTracker->reserveResources(MI);
|
||||
return MI;
|
||||
}
|
||||
|
||||
// End the current packet and reset the state of the packetizer.
|
||||
// Overriding this function allows the target-specific packetizer
|
||||
// to perform custom finalization.
|
||||
virtual void endPacket(MachineBasicBlock *MBB,
|
||||
MachineBasicBlock::iterator MI);
|
||||
|
||||
// Perform initialization before packetizing an instruction. This
|
||||
// function is supposed to be overrided by the target dependent packetizer.
|
||||
virtual void initPacketizerState() {}
|
||||
|
||||
// Check if the given instruction I should be ignored by the packetizer.
|
||||
virtual bool ignorePseudoInstruction(const MachineInstr &I,
|
||||
const MachineBasicBlock *MBB) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return true if instruction MI can not be packetized with any other
|
||||
// instruction, which means that MI itself is a packet.
|
||||
virtual bool isSoloInstruction(const MachineInstr &MI) { return true; }
|
||||
|
||||
// Check if the packetizer should try to add the given instruction to
|
||||
// the current packet. One reasons for which it may not be desirable
|
||||
// to include an instruction in the current packet could be that it
|
||||
// would cause a stall.
|
||||
// If this function returns "false", the current packet will be ended,
|
||||
// and the instruction will be added to the next packet.
|
||||
virtual bool shouldAddToPacket(const MachineInstr &MI) { return true; }
|
||||
|
||||
// Check if it is legal to packetize SUI and SUJ together.
|
||||
virtual bool isLegalToPacketizeTogether(SUnit *SUI, SUnit *SUJ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if it is legal to prune dependence between SUI and SUJ.
|
||||
virtual bool isLegalToPruneDependencies(SUnit *SUI, SUnit *SUJ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Add a DAG mutation to be done before the packetization begins.
|
||||
void addMutation(std::unique_ptr<ScheduleDAGMutation> Mutation);
|
||||
|
||||
bool alias(const MachineInstr &MI1, const MachineInstr &MI2,
|
||||
bool UseTBAA = true) const;
|
||||
|
||||
private:
|
||||
bool alias(const MachineMemOperand &Op1, const MachineMemOperand &Op2,
|
||||
bool UseTBAA = true) const;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_DFAPACKETIZER_H
|
||||
998
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/DIE.h
vendored
Normal file
998
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/DIE.h
vendored
Normal file
@@ -0,0 +1,998 @@
|
||||
//===- lib/CodeGen/DIE.h - DWARF Info Entries -------------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Data structures for DWARF info entries.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_DIE_H
|
||||
#define LLVM_CODEGEN_DIE_H
|
||||
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/ADT/PointerUnion.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/iterator.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/BinaryFormat/Dwarf.h"
|
||||
#include "llvm/CodeGen/DwarfStringPoolEntry.h"
|
||||
#include "llvm/Support/AlignOf.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <iterator>
|
||||
#include <new>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class AsmPrinter;
|
||||
class DIE;
|
||||
class DIEUnit;
|
||||
class DwarfCompileUnit;
|
||||
class MCExpr;
|
||||
class MCSection;
|
||||
class MCSymbol;
|
||||
class raw_ostream;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// Dwarf abbreviation data, describes one attribute of a Dwarf abbreviation.
|
||||
class DIEAbbrevData {
|
||||
/// Dwarf attribute code.
|
||||
dwarf::Attribute Attribute;
|
||||
|
||||
/// Dwarf form code.
|
||||
dwarf::Form Form;
|
||||
|
||||
/// Dwarf attribute value for DW_FORM_implicit_const
|
||||
int64_t Value = 0;
|
||||
|
||||
public:
|
||||
DIEAbbrevData(dwarf::Attribute A, dwarf::Form F)
|
||||
: Attribute(A), Form(F) {}
|
||||
DIEAbbrevData(dwarf::Attribute A, int64_t V)
|
||||
: Attribute(A), Form(dwarf::DW_FORM_implicit_const), Value(V) {}
|
||||
|
||||
/// Accessors.
|
||||
/// @{
|
||||
dwarf::Attribute getAttribute() const { return Attribute; }
|
||||
dwarf::Form getForm() const { return Form; }
|
||||
int64_t getValue() const { return Value; }
|
||||
/// @}
|
||||
|
||||
/// Used to gather unique data for the abbreviation folding set.
|
||||
void Profile(FoldingSetNodeID &ID) const;
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// Dwarf abbreviation, describes the organization of a debug information
|
||||
/// object.
|
||||
class DIEAbbrev : public FoldingSetNode {
|
||||
/// Unique number for node.
|
||||
unsigned Number = 0;
|
||||
|
||||
/// Dwarf tag code.
|
||||
dwarf::Tag Tag;
|
||||
|
||||
/// Whether or not this node has children.
|
||||
///
|
||||
/// This cheats a bit in all of the uses since the values in the standard
|
||||
/// are 0 and 1 for no children and children respectively.
|
||||
bool Children;
|
||||
|
||||
/// Raw data bytes for abbreviation.
|
||||
SmallVector<DIEAbbrevData, 12> Data;
|
||||
|
||||
public:
|
||||
DIEAbbrev(dwarf::Tag T, bool C) : Tag(T), Children(C) {}
|
||||
|
||||
/// Accessors.
|
||||
/// @{
|
||||
dwarf::Tag getTag() const { return Tag; }
|
||||
unsigned getNumber() const { return Number; }
|
||||
bool hasChildren() const { return Children; }
|
||||
const SmallVectorImpl<DIEAbbrevData> &getData() const { return Data; }
|
||||
void setChildrenFlag(bool hasChild) { Children = hasChild; }
|
||||
void setNumber(unsigned N) { Number = N; }
|
||||
/// @}
|
||||
|
||||
/// Adds another set of attribute information to the abbreviation.
|
||||
void AddAttribute(dwarf::Attribute Attribute, dwarf::Form Form) {
|
||||
Data.push_back(DIEAbbrevData(Attribute, Form));
|
||||
}
|
||||
|
||||
/// Adds attribute with DW_FORM_implicit_const value
|
||||
void AddImplicitConstAttribute(dwarf::Attribute Attribute, int64_t Value) {
|
||||
Data.push_back(DIEAbbrevData(Attribute, Value));
|
||||
}
|
||||
|
||||
/// Used to gather unique data for the abbreviation folding set.
|
||||
void Profile(FoldingSetNodeID &ID) const;
|
||||
|
||||
/// Print the abbreviation using the specified asm printer.
|
||||
void Emit(const AsmPrinter *AP) const;
|
||||
|
||||
void print(raw_ostream &O) const;
|
||||
void dump() const;
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// Helps unique DIEAbbrev objects and assigns abbreviation numbers.
|
||||
///
|
||||
/// This class will unique the DIE abbreviations for a llvm::DIE object and
|
||||
/// assign a unique abbreviation number to each unique DIEAbbrev object it
|
||||
/// finds. The resulting collection of DIEAbbrev objects can then be emitted
|
||||
/// into the .debug_abbrev section.
|
||||
class DIEAbbrevSet {
|
||||
/// The bump allocator to use when creating DIEAbbrev objects in the uniqued
|
||||
/// storage container.
|
||||
BumpPtrAllocator &Alloc;
|
||||
/// FoldingSet that uniques the abbreviations.
|
||||
FoldingSet<DIEAbbrev> AbbreviationsSet;
|
||||
/// A list of all the unique abbreviations in use.
|
||||
std::vector<DIEAbbrev *> Abbreviations;
|
||||
|
||||
public:
|
||||
DIEAbbrevSet(BumpPtrAllocator &A) : Alloc(A) {}
|
||||
~DIEAbbrevSet();
|
||||
|
||||
/// Generate the abbreviation declaration for a DIE and return a pointer to
|
||||
/// the generated abbreviation.
|
||||
///
|
||||
/// \param Die the debug info entry to generate the abbreviation for.
|
||||
/// \returns A reference to the uniqued abbreviation declaration that is
|
||||
/// owned by this class.
|
||||
DIEAbbrev &uniqueAbbreviation(DIE &Die);
|
||||
|
||||
/// Print all abbreviations using the specified asm printer.
|
||||
void Emit(const AsmPrinter *AP, MCSection *Section) const;
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// An integer value DIE.
|
||||
///
|
||||
class DIEInteger {
|
||||
uint64_t Integer;
|
||||
|
||||
public:
|
||||
explicit DIEInteger(uint64_t I) : Integer(I) {}
|
||||
|
||||
/// Choose the best form for integer.
|
||||
static dwarf::Form BestForm(bool IsSigned, uint64_t Int) {
|
||||
if (IsSigned) {
|
||||
const int64_t SignedInt = Int;
|
||||
if ((char)Int == SignedInt)
|
||||
return dwarf::DW_FORM_data1;
|
||||
if ((short)Int == SignedInt)
|
||||
return dwarf::DW_FORM_data2;
|
||||
if ((int)Int == SignedInt)
|
||||
return dwarf::DW_FORM_data4;
|
||||
} else {
|
||||
if ((unsigned char)Int == Int)
|
||||
return dwarf::DW_FORM_data1;
|
||||
if ((unsigned short)Int == Int)
|
||||
return dwarf::DW_FORM_data2;
|
||||
if ((unsigned int)Int == Int)
|
||||
return dwarf::DW_FORM_data4;
|
||||
}
|
||||
return dwarf::DW_FORM_data8;
|
||||
}
|
||||
|
||||
uint64_t getValue() const { return Integer; }
|
||||
void setValue(uint64_t Val) { Integer = Val; }
|
||||
|
||||
void emitValue(const AsmPrinter *Asm, dwarf::Form Form) const;
|
||||
unsigned sizeOf(const dwarf::FormParams &FormParams, dwarf::Form Form) const;
|
||||
|
||||
void print(raw_ostream &O) const;
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// An expression DIE.
|
||||
class DIEExpr {
|
||||
const MCExpr *Expr;
|
||||
|
||||
public:
|
||||
explicit DIEExpr(const MCExpr *E) : Expr(E) {}
|
||||
|
||||
/// Get MCExpr.
|
||||
const MCExpr *getValue() const { return Expr; }
|
||||
|
||||
void emitValue(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
unsigned sizeOf(const dwarf::FormParams &FormParams, dwarf::Form Form) const;
|
||||
|
||||
void print(raw_ostream &O) const;
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// A label DIE.
|
||||
class DIELabel {
|
||||
const MCSymbol *Label;
|
||||
|
||||
public:
|
||||
explicit DIELabel(const MCSymbol *L) : Label(L) {}
|
||||
|
||||
/// Get MCSymbol.
|
||||
const MCSymbol *getValue() const { return Label; }
|
||||
|
||||
void emitValue(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
unsigned sizeOf(const dwarf::FormParams &FormParams, dwarf::Form Form) const;
|
||||
|
||||
void print(raw_ostream &O) const;
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// A BaseTypeRef DIE.
|
||||
class DIEBaseTypeRef {
|
||||
const DwarfCompileUnit *CU;
|
||||
const uint64_t Index;
|
||||
static constexpr unsigned ULEB128PadSize = 4;
|
||||
|
||||
public:
|
||||
explicit DIEBaseTypeRef(const DwarfCompileUnit *TheCU, uint64_t Idx)
|
||||
: CU(TheCU), Index(Idx) {}
|
||||
|
||||
/// EmitValue - Emit base type reference.
|
||||
void emitValue(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
/// sizeOf - Determine size of the base type reference in bytes.
|
||||
unsigned sizeOf(const dwarf::FormParams &, dwarf::Form) const;
|
||||
|
||||
void print(raw_ostream &O) const;
|
||||
uint64_t getIndex() const { return Index; }
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// A simple label difference DIE.
|
||||
///
|
||||
class DIEDelta {
|
||||
const MCSymbol *LabelHi;
|
||||
const MCSymbol *LabelLo;
|
||||
|
||||
public:
|
||||
DIEDelta(const MCSymbol *Hi, const MCSymbol *Lo) : LabelHi(Hi), LabelLo(Lo) {}
|
||||
|
||||
void emitValue(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
unsigned sizeOf(const dwarf::FormParams &FormParams, dwarf::Form Form) const;
|
||||
|
||||
void print(raw_ostream &O) const;
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// A container for string pool string values.
|
||||
///
|
||||
/// This class is used with the DW_FORM_strp and DW_FORM_GNU_str_index forms.
|
||||
class DIEString {
|
||||
DwarfStringPoolEntryRef S;
|
||||
|
||||
public:
|
||||
DIEString(DwarfStringPoolEntryRef S) : S(S) {}
|
||||
|
||||
/// Grab the string out of the object.
|
||||
StringRef getString() const { return S.getString(); }
|
||||
|
||||
void emitValue(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
unsigned sizeOf(const dwarf::FormParams &FormParams, dwarf::Form Form) const;
|
||||
|
||||
void print(raw_ostream &O) const;
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// A container for inline string values.
|
||||
///
|
||||
/// This class is used with the DW_FORM_string form.
|
||||
class DIEInlineString {
|
||||
StringRef S;
|
||||
|
||||
public:
|
||||
template <typename Allocator>
|
||||
explicit DIEInlineString(StringRef Str, Allocator &A) : S(Str.copy(A)) {}
|
||||
|
||||
~DIEInlineString() = default;
|
||||
|
||||
/// Grab the string out of the object.
|
||||
StringRef getString() const { return S; }
|
||||
|
||||
void emitValue(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
unsigned sizeOf(const dwarf::FormParams &, dwarf::Form) const;
|
||||
|
||||
void print(raw_ostream &O) const;
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// A pointer to another debug information entry. An instance of this class can
|
||||
/// also be used as a proxy for a debug information entry not yet defined
|
||||
/// (ie. types.)
|
||||
class DIEEntry {
|
||||
DIE *Entry;
|
||||
|
||||
public:
|
||||
DIEEntry() = delete;
|
||||
explicit DIEEntry(DIE &E) : Entry(&E) {}
|
||||
|
||||
DIE &getEntry() const { return *Entry; }
|
||||
|
||||
void emitValue(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
unsigned sizeOf(const dwarf::FormParams &FormParams, dwarf::Form Form) const;
|
||||
|
||||
void print(raw_ostream &O) const;
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// Represents a pointer to a location list in the debug_loc
|
||||
/// section.
|
||||
class DIELocList {
|
||||
/// Index into the .debug_loc vector.
|
||||
size_t Index;
|
||||
|
||||
public:
|
||||
DIELocList(size_t I) : Index(I) {}
|
||||
|
||||
/// Grab the current index out.
|
||||
size_t getValue() const { return Index; }
|
||||
|
||||
void emitValue(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
unsigned sizeOf(const dwarf::FormParams &FormParams, dwarf::Form Form) const;
|
||||
|
||||
void print(raw_ostream &O) const;
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// A BaseTypeRef DIE.
|
||||
class DIEAddrOffset {
|
||||
DIEInteger Addr;
|
||||
DIEDelta Offset;
|
||||
|
||||
public:
|
||||
explicit DIEAddrOffset(uint64_t Idx, const MCSymbol *Hi, const MCSymbol *Lo)
|
||||
: Addr(Idx), Offset(Hi, Lo) {}
|
||||
|
||||
void emitValue(const AsmPrinter *AP, dwarf::Form Form) const;
|
||||
unsigned sizeOf(const dwarf::FormParams &FormParams, dwarf::Form Form) const;
|
||||
|
||||
void print(raw_ostream &O) const;
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// A debug information entry value. Some of these roughly correlate
|
||||
/// to DWARF attribute classes.
|
||||
class DIEBlock;
|
||||
class DIELoc;
|
||||
class DIEValue {
|
||||
public:
|
||||
enum Type {
|
||||
isNone,
|
||||
#define HANDLE_DIEVALUE(T) is##T,
|
||||
#include "llvm/CodeGen/DIEValue.def"
|
||||
};
|
||||
|
||||
private:
|
||||
/// Type of data stored in the value.
|
||||
Type Ty = isNone;
|
||||
dwarf::Attribute Attribute = (dwarf::Attribute)0;
|
||||
dwarf::Form Form = (dwarf::Form)0;
|
||||
|
||||
/// Storage for the value.
|
||||
///
|
||||
/// All values that aren't standard layout (or are larger than 8 bytes)
|
||||
/// should be stored by reference instead of by value.
|
||||
using ValTy =
|
||||
AlignedCharArrayUnion<DIEInteger, DIEString, DIEExpr, DIELabel,
|
||||
DIEDelta *, DIEEntry, DIEBlock *, DIELoc *,
|
||||
DIELocList, DIEBaseTypeRef *, DIEAddrOffset *>;
|
||||
|
||||
static_assert(sizeof(ValTy) <= sizeof(uint64_t) ||
|
||||
sizeof(ValTy) <= sizeof(void *),
|
||||
"Expected all large types to be stored via pointer");
|
||||
|
||||
/// Underlying stored value.
|
||||
ValTy Val;
|
||||
|
||||
template <class T> void construct(T V) {
|
||||
static_assert(std::is_standard_layout<T>::value ||
|
||||
std::is_pointer<T>::value,
|
||||
"Expected standard layout or pointer");
|
||||
new (reinterpret_cast<void *>(&Val)) T(V);
|
||||
}
|
||||
|
||||
template <class T> T *get() { return reinterpret_cast<T *>(&Val); }
|
||||
template <class T> const T *get() const {
|
||||
return reinterpret_cast<const T *>(&Val);
|
||||
}
|
||||
template <class T> void destruct() { get<T>()->~T(); }
|
||||
|
||||
/// Destroy the underlying value.
|
||||
///
|
||||
/// This should get optimized down to a no-op. We could skip it if we could
|
||||
/// add a static assert on \a std::is_trivially_copyable(), but we currently
|
||||
/// support versions of GCC that don't understand that.
|
||||
void destroyVal() {
|
||||
switch (Ty) {
|
||||
case isNone:
|
||||
return;
|
||||
#define HANDLE_DIEVALUE_SMALL(T) \
|
||||
case is##T: \
|
||||
destruct<DIE##T>(); \
|
||||
return;
|
||||
#define HANDLE_DIEVALUE_LARGE(T) \
|
||||
case is##T: \
|
||||
destruct<const DIE##T *>(); \
|
||||
return;
|
||||
#include "llvm/CodeGen/DIEValue.def"
|
||||
}
|
||||
}
|
||||
|
||||
/// Copy the underlying value.
|
||||
///
|
||||
/// This should get optimized down to a simple copy. We need to actually
|
||||
/// construct the value, rather than calling memcpy, to satisfy strict
|
||||
/// aliasing rules.
|
||||
void copyVal(const DIEValue &X) {
|
||||
switch (Ty) {
|
||||
case isNone:
|
||||
return;
|
||||
#define HANDLE_DIEVALUE_SMALL(T) \
|
||||
case is##T: \
|
||||
construct<DIE##T>(*X.get<DIE##T>()); \
|
||||
return;
|
||||
#define HANDLE_DIEVALUE_LARGE(T) \
|
||||
case is##T: \
|
||||
construct<const DIE##T *>(*X.get<const DIE##T *>()); \
|
||||
return;
|
||||
#include "llvm/CodeGen/DIEValue.def"
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
DIEValue() = default;
|
||||
|
||||
DIEValue(const DIEValue &X) : Ty(X.Ty), Attribute(X.Attribute), Form(X.Form) {
|
||||
copyVal(X);
|
||||
}
|
||||
|
||||
DIEValue &operator=(const DIEValue &X) {
|
||||
destroyVal();
|
||||
Ty = X.Ty;
|
||||
Attribute = X.Attribute;
|
||||
Form = X.Form;
|
||||
copyVal(X);
|
||||
return *this;
|
||||
}
|
||||
|
||||
~DIEValue() { destroyVal(); }
|
||||
|
||||
#define HANDLE_DIEVALUE_SMALL(T) \
|
||||
DIEValue(dwarf::Attribute Attribute, dwarf::Form Form, const DIE##T &V) \
|
||||
: Ty(is##T), Attribute(Attribute), Form(Form) { \
|
||||
construct<DIE##T>(V); \
|
||||
}
|
||||
#define HANDLE_DIEVALUE_LARGE(T) \
|
||||
DIEValue(dwarf::Attribute Attribute, dwarf::Form Form, const DIE##T *V) \
|
||||
: Ty(is##T), Attribute(Attribute), Form(Form) { \
|
||||
assert(V && "Expected valid value"); \
|
||||
construct<const DIE##T *>(V); \
|
||||
}
|
||||
#include "llvm/CodeGen/DIEValue.def"
|
||||
|
||||
/// Accessors.
|
||||
/// @{
|
||||
Type getType() const { return Ty; }
|
||||
dwarf::Attribute getAttribute() const { return Attribute; }
|
||||
dwarf::Form getForm() const { return Form; }
|
||||
explicit operator bool() const { return Ty; }
|
||||
/// @}
|
||||
|
||||
#define HANDLE_DIEVALUE_SMALL(T) \
|
||||
const DIE##T &getDIE##T() const { \
|
||||
assert(getType() == is##T && "Expected " #T); \
|
||||
return *get<DIE##T>(); \
|
||||
}
|
||||
#define HANDLE_DIEVALUE_LARGE(T) \
|
||||
const DIE##T &getDIE##T() const { \
|
||||
assert(getType() == is##T && "Expected " #T); \
|
||||
return **get<const DIE##T *>(); \
|
||||
}
|
||||
#include "llvm/CodeGen/DIEValue.def"
|
||||
|
||||
/// Emit value via the Dwarf writer.
|
||||
void emitValue(const AsmPrinter *AP) const;
|
||||
|
||||
/// Return the size of a value in bytes.
|
||||
unsigned sizeOf(const dwarf::FormParams &FormParams) const;
|
||||
|
||||
void print(raw_ostream &O) const;
|
||||
void dump() const;
|
||||
};
|
||||
|
||||
struct IntrusiveBackListNode {
|
||||
PointerIntPair<IntrusiveBackListNode *, 1> Next;
|
||||
|
||||
IntrusiveBackListNode() : Next(this, true) {}
|
||||
|
||||
IntrusiveBackListNode *getNext() const {
|
||||
return Next.getInt() ? nullptr : Next.getPointer();
|
||||
}
|
||||
};
|
||||
|
||||
struct IntrusiveBackListBase {
|
||||
using Node = IntrusiveBackListNode;
|
||||
|
||||
Node *Last = nullptr;
|
||||
|
||||
bool empty() const { return !Last; }
|
||||
|
||||
void push_back(Node &N) {
|
||||
assert(N.Next.getPointer() == &N && "Expected unlinked node");
|
||||
assert(N.Next.getInt() == true && "Expected unlinked node");
|
||||
|
||||
if (Last) {
|
||||
N.Next = Last->Next;
|
||||
Last->Next.setPointerAndInt(&N, false);
|
||||
}
|
||||
Last = &N;
|
||||
}
|
||||
|
||||
void push_front(Node &N) {
|
||||
assert(N.Next.getPointer() == &N && "Expected unlinked node");
|
||||
assert(N.Next.getInt() == true && "Expected unlinked node");
|
||||
|
||||
if (Last) {
|
||||
N.Next.setPointerAndInt(Last->Next.getPointer(), false);
|
||||
Last->Next.setPointerAndInt(&N, true);
|
||||
} else {
|
||||
Last = &N;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class T> class IntrusiveBackList : IntrusiveBackListBase {
|
||||
public:
|
||||
using IntrusiveBackListBase::empty;
|
||||
|
||||
void push_back(T &N) { IntrusiveBackListBase::push_back(N); }
|
||||
void push_front(T &N) { IntrusiveBackListBase::push_front(N); }
|
||||
T &back() { return *static_cast<T *>(Last); }
|
||||
const T &back() const { return *static_cast<T *>(Last); }
|
||||
T &front() {
|
||||
return *static_cast<T *>(Last ? Last->Next.getPointer() : nullptr);
|
||||
}
|
||||
const T &front() const {
|
||||
return *static_cast<T *>(Last ? Last->Next.getPointer() : nullptr);
|
||||
}
|
||||
|
||||
void takeNodes(IntrusiveBackList<T> &Other) {
|
||||
if (Other.empty())
|
||||
return;
|
||||
|
||||
T *FirstNode = static_cast<T *>(Other.Last->Next.getPointer());
|
||||
T *IterNode = FirstNode;
|
||||
do {
|
||||
// Keep a pointer to the node and increment the iterator.
|
||||
T *TmpNode = IterNode;
|
||||
IterNode = static_cast<T *>(IterNode->Next.getPointer());
|
||||
|
||||
// Unlink the node and push it back to this list.
|
||||
TmpNode->Next.setPointerAndInt(TmpNode, true);
|
||||
push_back(*TmpNode);
|
||||
} while (IterNode != FirstNode);
|
||||
|
||||
Other.Last = nullptr;
|
||||
}
|
||||
|
||||
class const_iterator;
|
||||
class iterator
|
||||
: public iterator_facade_base<iterator, std::forward_iterator_tag, T> {
|
||||
friend class const_iterator;
|
||||
|
||||
Node *N = nullptr;
|
||||
|
||||
public:
|
||||
iterator() = default;
|
||||
explicit iterator(T *N) : N(N) {}
|
||||
|
||||
iterator &operator++() {
|
||||
N = N->getNext();
|
||||
return *this;
|
||||
}
|
||||
|
||||
explicit operator bool() const { return N; }
|
||||
T &operator*() const { return *static_cast<T *>(N); }
|
||||
|
||||
bool operator==(const iterator &X) const { return N == X.N; }
|
||||
};
|
||||
|
||||
class const_iterator
|
||||
: public iterator_facade_base<const_iterator, std::forward_iterator_tag,
|
||||
const T> {
|
||||
const Node *N = nullptr;
|
||||
|
||||
public:
|
||||
const_iterator() = default;
|
||||
// Placate MSVC by explicitly scoping 'iterator'.
|
||||
const_iterator(typename IntrusiveBackList<T>::iterator X) : N(X.N) {}
|
||||
explicit const_iterator(const T *N) : N(N) {}
|
||||
|
||||
const_iterator &operator++() {
|
||||
N = N->getNext();
|
||||
return *this;
|
||||
}
|
||||
|
||||
explicit operator bool() const { return N; }
|
||||
const T &operator*() const { return *static_cast<const T *>(N); }
|
||||
|
||||
bool operator==(const const_iterator &X) const { return N == X.N; }
|
||||
};
|
||||
|
||||
iterator begin() {
|
||||
return Last ? iterator(static_cast<T *>(Last->Next.getPointer())) : end();
|
||||
}
|
||||
const_iterator begin() const {
|
||||
return const_cast<IntrusiveBackList *>(this)->begin();
|
||||
}
|
||||
iterator end() { return iterator(); }
|
||||
const_iterator end() const { return const_iterator(); }
|
||||
|
||||
static iterator toIterator(T &N) { return iterator(&N); }
|
||||
static const_iterator toIterator(const T &N) { return const_iterator(&N); }
|
||||
};
|
||||
|
||||
/// A list of DIE values.
|
||||
///
|
||||
/// This is a singly-linked list, but instead of reversing the order of
|
||||
/// insertion, we keep a pointer to the back of the list so we can push in
|
||||
/// order.
|
||||
///
|
||||
/// There are two main reasons to choose a linked list over a customized
|
||||
/// vector-like data structure.
|
||||
///
|
||||
/// 1. For teardown efficiency, we want DIEs to be BumpPtrAllocated. Using a
|
||||
/// linked list here makes this way easier to accomplish.
|
||||
/// 2. Carrying an extra pointer per \a DIEValue isn't expensive. 45% of DIEs
|
||||
/// have 2 or fewer values, and 90% have 5 or fewer. A vector would be
|
||||
/// over-allocated by 50% on average anyway, the same cost as the
|
||||
/// linked-list node.
|
||||
class DIEValueList {
|
||||
struct Node : IntrusiveBackListNode {
|
||||
DIEValue V;
|
||||
|
||||
explicit Node(DIEValue V) : V(V) {}
|
||||
};
|
||||
|
||||
using ListTy = IntrusiveBackList<Node>;
|
||||
|
||||
ListTy List;
|
||||
|
||||
public:
|
||||
class const_value_iterator;
|
||||
class value_iterator
|
||||
: public iterator_adaptor_base<value_iterator, ListTy::iterator,
|
||||
std::forward_iterator_tag, DIEValue> {
|
||||
friend class const_value_iterator;
|
||||
|
||||
using iterator_adaptor =
|
||||
iterator_adaptor_base<value_iterator, ListTy::iterator,
|
||||
std::forward_iterator_tag, DIEValue>;
|
||||
|
||||
public:
|
||||
value_iterator() = default;
|
||||
explicit value_iterator(ListTy::iterator X) : iterator_adaptor(X) {}
|
||||
|
||||
explicit operator bool() const { return bool(wrapped()); }
|
||||
DIEValue &operator*() const { return wrapped()->V; }
|
||||
};
|
||||
|
||||
class const_value_iterator : public iterator_adaptor_base<
|
||||
const_value_iterator, ListTy::const_iterator,
|
||||
std::forward_iterator_tag, const DIEValue> {
|
||||
using iterator_adaptor =
|
||||
iterator_adaptor_base<const_value_iterator, ListTy::const_iterator,
|
||||
std::forward_iterator_tag, const DIEValue>;
|
||||
|
||||
public:
|
||||
const_value_iterator() = default;
|
||||
const_value_iterator(DIEValueList::value_iterator X)
|
||||
: iterator_adaptor(X.wrapped()) {}
|
||||
explicit const_value_iterator(ListTy::const_iterator X)
|
||||
: iterator_adaptor(X) {}
|
||||
|
||||
explicit operator bool() const { return bool(wrapped()); }
|
||||
const DIEValue &operator*() const { return wrapped()->V; }
|
||||
};
|
||||
|
||||
using value_range = iterator_range<value_iterator>;
|
||||
using const_value_range = iterator_range<const_value_iterator>;
|
||||
|
||||
value_iterator addValue(BumpPtrAllocator &Alloc, const DIEValue &V) {
|
||||
List.push_back(*new (Alloc) Node(V));
|
||||
return value_iterator(ListTy::toIterator(List.back()));
|
||||
}
|
||||
template <class T>
|
||||
value_iterator addValue(BumpPtrAllocator &Alloc, dwarf::Attribute Attribute,
|
||||
dwarf::Form Form, T &&Value) {
|
||||
return addValue(Alloc, DIEValue(Attribute, Form, std::forward<T>(Value)));
|
||||
}
|
||||
|
||||
/// Take ownership of the nodes in \p Other, and append them to the back of
|
||||
/// the list.
|
||||
void takeValues(DIEValueList &Other) { List.takeNodes(Other.List); }
|
||||
|
||||
value_range values() {
|
||||
return make_range(value_iterator(List.begin()), value_iterator(List.end()));
|
||||
}
|
||||
const_value_range values() const {
|
||||
return make_range(const_value_iterator(List.begin()),
|
||||
const_value_iterator(List.end()));
|
||||
}
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// A structured debug information entry. Has an abbreviation which
|
||||
/// describes its organization.
|
||||
class DIE : IntrusiveBackListNode, public DIEValueList {
|
||||
friend class IntrusiveBackList<DIE>;
|
||||
friend class DIEUnit;
|
||||
|
||||
/// Dwarf unit relative offset.
|
||||
unsigned Offset = 0;
|
||||
/// Size of instance + children.
|
||||
unsigned Size = 0;
|
||||
unsigned AbbrevNumber = ~0u;
|
||||
/// Dwarf tag code.
|
||||
dwarf::Tag Tag = (dwarf::Tag)0;
|
||||
/// Set to true to force a DIE to emit an abbreviation that says it has
|
||||
/// children even when it doesn't. This is used for unit testing purposes.
|
||||
bool ForceChildren = false;
|
||||
/// Children DIEs.
|
||||
IntrusiveBackList<DIE> Children;
|
||||
|
||||
/// The owner is either the parent DIE for children of other DIEs, or a
|
||||
/// DIEUnit which contains this DIE as its unit DIE.
|
||||
PointerUnion<DIE *, DIEUnit *> Owner;
|
||||
|
||||
explicit DIE(dwarf::Tag Tag) : Tag(Tag) {}
|
||||
|
||||
public:
|
||||
DIE() = delete;
|
||||
DIE(const DIE &RHS) = delete;
|
||||
DIE(DIE &&RHS) = delete;
|
||||
DIE &operator=(const DIE &RHS) = delete;
|
||||
DIE &operator=(const DIE &&RHS) = delete;
|
||||
|
||||
static DIE *get(BumpPtrAllocator &Alloc, dwarf::Tag Tag) {
|
||||
return new (Alloc) DIE(Tag);
|
||||
}
|
||||
|
||||
// Accessors.
|
||||
unsigned getAbbrevNumber() const { return AbbrevNumber; }
|
||||
dwarf::Tag getTag() const { return Tag; }
|
||||
/// Get the compile/type unit relative offset of this DIE.
|
||||
unsigned getOffset() const {
|
||||
// A real Offset can't be zero because the unit headers are at offset zero.
|
||||
assert(Offset && "Offset being queried before it's been computed.");
|
||||
return Offset;
|
||||
}
|
||||
unsigned getSize() const {
|
||||
// A real Size can't be zero because it includes the non-empty abbrev code.
|
||||
assert(Size && "Size being queried before it's been ocmputed.");
|
||||
return Size;
|
||||
}
|
||||
bool hasChildren() const { return ForceChildren || !Children.empty(); }
|
||||
void setForceChildren(bool B) { ForceChildren = B; }
|
||||
|
||||
using child_iterator = IntrusiveBackList<DIE>::iterator;
|
||||
using const_child_iterator = IntrusiveBackList<DIE>::const_iterator;
|
||||
using child_range = iterator_range<child_iterator>;
|
||||
using const_child_range = iterator_range<const_child_iterator>;
|
||||
|
||||
child_range children() {
|
||||
return make_range(Children.begin(), Children.end());
|
||||
}
|
||||
const_child_range children() const {
|
||||
return make_range(Children.begin(), Children.end());
|
||||
}
|
||||
|
||||
DIE *getParent() const;
|
||||
|
||||
/// Generate the abbreviation for this DIE.
|
||||
///
|
||||
/// Calculate the abbreviation for this, which should be uniqued and
|
||||
/// eventually used to call \a setAbbrevNumber().
|
||||
DIEAbbrev generateAbbrev() const;
|
||||
|
||||
/// Set the abbreviation number for this DIE.
|
||||
void setAbbrevNumber(unsigned I) { AbbrevNumber = I; }
|
||||
|
||||
/// Get the absolute offset within the .debug_info or .debug_types section
|
||||
/// for this DIE.
|
||||
uint64_t getDebugSectionOffset() const;
|
||||
|
||||
/// Compute the offset of this DIE and all its children.
|
||||
///
|
||||
/// This function gets called just before we are going to generate the debug
|
||||
/// information and gives each DIE a chance to figure out its CU relative DIE
|
||||
/// offset, unique its abbreviation and fill in the abbreviation code, and
|
||||
/// return the unit offset that points to where the next DIE will be emitted
|
||||
/// within the debug unit section. After this function has been called for all
|
||||
/// DIE objects, the DWARF can be generated since all DIEs will be able to
|
||||
/// properly refer to other DIE objects since all DIEs have calculated their
|
||||
/// offsets.
|
||||
///
|
||||
/// \param FormParams Used when calculating sizes.
|
||||
/// \param AbbrevSet the abbreviation used to unique DIE abbreviations.
|
||||
/// \param CUOffset the compile/type unit relative offset in bytes.
|
||||
/// \returns the offset for the DIE that follows this DIE within the
|
||||
/// current compile/type unit.
|
||||
unsigned computeOffsetsAndAbbrevs(const dwarf::FormParams &FormParams,
|
||||
DIEAbbrevSet &AbbrevSet, unsigned CUOffset);
|
||||
|
||||
/// Climb up the parent chain to get the compile unit or type unit DIE that
|
||||
/// this DIE belongs to.
|
||||
///
|
||||
/// \returns the compile or type unit DIE that owns this DIE, or NULL if
|
||||
/// this DIE hasn't been added to a unit DIE.
|
||||
const DIE *getUnitDie() const;
|
||||
|
||||
/// Climb up the parent chain to get the compile unit or type unit that this
|
||||
/// DIE belongs to.
|
||||
///
|
||||
/// \returns the DIEUnit that represents the compile or type unit that owns
|
||||
/// this DIE, or NULL if this DIE hasn't been added to a unit DIE.
|
||||
DIEUnit *getUnit() const;
|
||||
|
||||
void setOffset(unsigned O) { Offset = O; }
|
||||
void setSize(unsigned S) { Size = S; }
|
||||
|
||||
/// Add a child to the DIE.
|
||||
DIE &addChild(DIE *Child) {
|
||||
assert(!Child->getParent() && "Child should be orphaned");
|
||||
Child->Owner = this;
|
||||
Children.push_back(*Child);
|
||||
return Children.back();
|
||||
}
|
||||
|
||||
DIE &addChildFront(DIE *Child) {
|
||||
assert(!Child->getParent() && "Child should be orphaned");
|
||||
Child->Owner = this;
|
||||
Children.push_front(*Child);
|
||||
return Children.front();
|
||||
}
|
||||
|
||||
/// Find a value in the DIE with the attribute given.
|
||||
///
|
||||
/// Returns a default-constructed DIEValue (where \a DIEValue::getType()
|
||||
/// gives \a DIEValue::isNone) if no such attribute exists.
|
||||
DIEValue findAttribute(dwarf::Attribute Attribute) const;
|
||||
|
||||
void print(raw_ostream &O, unsigned IndentCount = 0) const;
|
||||
void dump() const;
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// Represents a compile or type unit.
|
||||
class DIEUnit {
|
||||
/// The compile unit or type unit DIE. This variable must be an instance of
|
||||
/// DIE so that we can calculate the DIEUnit from any DIE by traversing the
|
||||
/// parent backchain and getting the Unit DIE, and then casting itself to a
|
||||
/// DIEUnit. This allows us to be able to find the DIEUnit for any DIE without
|
||||
/// having to store a pointer to the DIEUnit in each DIE instance.
|
||||
DIE Die;
|
||||
/// The section this unit will be emitted in. This may or may not be set to
|
||||
/// a valid section depending on the client that is emitting DWARF.
|
||||
MCSection *Section = nullptr;
|
||||
uint64_t Offset = 0; /// .debug_info or .debug_types absolute section offset.
|
||||
protected:
|
||||
virtual ~DIEUnit() = default;
|
||||
|
||||
public:
|
||||
explicit DIEUnit(dwarf::Tag UnitTag);
|
||||
DIEUnit(const DIEUnit &RHS) = delete;
|
||||
DIEUnit(DIEUnit &&RHS) = delete;
|
||||
void operator=(const DIEUnit &RHS) = delete;
|
||||
void operator=(const DIEUnit &&RHS) = delete;
|
||||
/// Set the section that this DIEUnit will be emitted into.
|
||||
///
|
||||
/// This function is used by some clients to set the section. Not all clients
|
||||
/// that emit DWARF use this section variable.
|
||||
void setSection(MCSection *Section) {
|
||||
assert(!this->Section);
|
||||
this->Section = Section;
|
||||
}
|
||||
|
||||
virtual const MCSymbol *getCrossSectionRelativeBaseAddress() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// Return the section that this DIEUnit will be emitted into.
|
||||
///
|
||||
/// \returns Section pointer which can be NULL.
|
||||
MCSection *getSection() const { return Section; }
|
||||
void setDebugSectionOffset(uint64_t O) { Offset = O; }
|
||||
uint64_t getDebugSectionOffset() const { return Offset; }
|
||||
DIE &getUnitDie() { return Die; }
|
||||
const DIE &getUnitDie() const { return Die; }
|
||||
};
|
||||
|
||||
struct BasicDIEUnit final : DIEUnit {
|
||||
explicit BasicDIEUnit(dwarf::Tag UnitTag) : DIEUnit(UnitTag) {}
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// DIELoc - Represents an expression location.
|
||||
//
|
||||
class DIELoc : public DIEValueList {
|
||||
mutable unsigned Size = 0; // Size in bytes excluding size header.
|
||||
|
||||
public:
|
||||
DIELoc() = default;
|
||||
|
||||
/// Calculate the size of the location expression.
|
||||
unsigned computeSize(const dwarf::FormParams &FormParams) const;
|
||||
|
||||
// TODO: move setSize() and Size to DIEValueList.
|
||||
void setSize(unsigned size) { Size = size; }
|
||||
|
||||
/// BestForm - Choose the best form for data.
|
||||
///
|
||||
dwarf::Form BestForm(unsigned DwarfVersion) const {
|
||||
if (DwarfVersion > 3)
|
||||
return dwarf::DW_FORM_exprloc;
|
||||
// Pre-DWARF4 location expressions were blocks and not exprloc.
|
||||
if ((unsigned char)Size == Size)
|
||||
return dwarf::DW_FORM_block1;
|
||||
if ((unsigned short)Size == Size)
|
||||
return dwarf::DW_FORM_block2;
|
||||
if ((unsigned int)Size == Size)
|
||||
return dwarf::DW_FORM_block4;
|
||||
return dwarf::DW_FORM_block;
|
||||
}
|
||||
|
||||
void emitValue(const AsmPrinter *Asm, dwarf::Form Form) const;
|
||||
unsigned sizeOf(const dwarf::FormParams &, dwarf::Form Form) const;
|
||||
|
||||
void print(raw_ostream &O) const;
|
||||
};
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// DIEBlock - Represents a block of values.
|
||||
//
|
||||
class DIEBlock : public DIEValueList {
|
||||
mutable unsigned Size = 0; // Size in bytes excluding size header.
|
||||
|
||||
public:
|
||||
DIEBlock() = default;
|
||||
|
||||
/// Calculate the size of the location expression.
|
||||
unsigned computeSize(const dwarf::FormParams &FormParams) const;
|
||||
|
||||
// TODO: move setSize() and Size to DIEValueList.
|
||||
void setSize(unsigned size) { Size = size; }
|
||||
|
||||
/// BestForm - Choose the best form for data.
|
||||
///
|
||||
dwarf::Form BestForm() const {
|
||||
if ((unsigned char)Size == Size)
|
||||
return dwarf::DW_FORM_block1;
|
||||
if ((unsigned short)Size == Size)
|
||||
return dwarf::DW_FORM_block2;
|
||||
if ((unsigned int)Size == Size)
|
||||
return dwarf::DW_FORM_block4;
|
||||
return dwarf::DW_FORM_block;
|
||||
}
|
||||
|
||||
void emitValue(const AsmPrinter *Asm, dwarf::Form Form) const;
|
||||
unsigned sizeOf(const dwarf::FormParams &, dwarf::Form Form) const;
|
||||
|
||||
void print(raw_ostream &O) const;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_DIE_H
|
||||
48
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/DIEValue.def
vendored
Normal file
48
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/DIEValue.def
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
//===- llvm/CodeGen/DIEValue.def - DIEValue types ---------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Macros for running through all types of DIEValue.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#if !(defined HANDLE_DIEVALUE || defined HANDLE_DIEVALUE_SMALL || \
|
||||
defined HANDLE_DIEVALUE_LARGE)
|
||||
#error "Missing macro definition of HANDLE_DIEVALUE"
|
||||
#endif
|
||||
|
||||
// Handler for all values.
|
||||
#ifndef HANDLE_DIEVALUE
|
||||
#define HANDLE_DIEVALUE(T)
|
||||
#endif
|
||||
|
||||
// Handler for small values.
|
||||
#ifndef HANDLE_DIEVALUE_SMALL
|
||||
#define HANDLE_DIEVALUE_SMALL(T) HANDLE_DIEVALUE(T)
|
||||
#endif
|
||||
|
||||
// Handler for large values.
|
||||
#ifndef HANDLE_DIEVALUE_LARGE
|
||||
#define HANDLE_DIEVALUE_LARGE(T) HANDLE_DIEVALUE(T)
|
||||
#endif
|
||||
|
||||
HANDLE_DIEVALUE_SMALL(Integer)
|
||||
HANDLE_DIEVALUE_SMALL(String)
|
||||
HANDLE_DIEVALUE_SMALL(Expr)
|
||||
HANDLE_DIEVALUE_SMALL(Label)
|
||||
HANDLE_DIEVALUE_LARGE(BaseTypeRef)
|
||||
HANDLE_DIEVALUE_LARGE(Delta)
|
||||
HANDLE_DIEVALUE_SMALL(Entry)
|
||||
HANDLE_DIEVALUE_LARGE(Block)
|
||||
HANDLE_DIEVALUE_LARGE(Loc)
|
||||
HANDLE_DIEVALUE_SMALL(LocList)
|
||||
HANDLE_DIEVALUE_LARGE(InlineString)
|
||||
HANDLE_DIEVALUE_LARGE(AddrOffset)
|
||||
|
||||
#undef HANDLE_DIEVALUE
|
||||
#undef HANDLE_DIEVALUE_SMALL
|
||||
#undef HANDLE_DIEVALUE_LARGE
|
||||
156
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/DbgEntityHistoryCalculator.h
vendored
Normal file
156
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/DbgEntityHistoryCalculator.h
vendored
Normal file
@@ -0,0 +1,156 @@
|
||||
//===- llvm/CodeGen/DbgEntityHistoryCalculator.h ----------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_DBGENTITYHISTORYCALCULATOR_H
|
||||
#define LLVM_CODEGEN_DBGENTITYHISTORYCALCULATOR_H
|
||||
|
||||
#include "llvm/ADT/MapVector.h"
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/CodeGen/LexicalScopes.h"
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class DILocation;
|
||||
class DINode;
|
||||
class MachineFunction;
|
||||
class MachineInstr;
|
||||
class TargetRegisterInfo;
|
||||
|
||||
/// Record instruction ordering so we can query their relative positions within
|
||||
/// a function. Meta instructions are given the same ordinal as the preceding
|
||||
/// non-meta instruction. Class state is invalid if MF is modified after
|
||||
/// calling initialize.
|
||||
class InstructionOrdering {
|
||||
public:
|
||||
void initialize(const MachineFunction &MF);
|
||||
void clear() { InstNumberMap.clear(); }
|
||||
|
||||
/// Check if instruction \p A comes before \p B, where \p A and \p B both
|
||||
/// belong to the MachineFunction passed to initialize().
|
||||
bool isBefore(const MachineInstr *A, const MachineInstr *B) const;
|
||||
|
||||
private:
|
||||
/// Each instruction is assigned an order number.
|
||||
DenseMap<const MachineInstr *, unsigned> InstNumberMap;
|
||||
};
|
||||
|
||||
/// For each user variable, keep a list of instruction ranges where this
|
||||
/// variable is accessible. The variables are listed in order of appearance.
|
||||
class DbgValueHistoryMap {
|
||||
public:
|
||||
/// Index in the entry vector.
|
||||
typedef size_t EntryIndex;
|
||||
|
||||
/// Special value to indicate that an entry is valid until the end of the
|
||||
/// function.
|
||||
static const EntryIndex NoEntry = std::numeric_limits<EntryIndex>::max();
|
||||
|
||||
/// Specifies a change in a variable's debug value history.
|
||||
///
|
||||
/// There exist two types of entries:
|
||||
///
|
||||
/// * Debug value entry:
|
||||
///
|
||||
/// A new debug value becomes live. If the entry's \p EndIndex is \p NoEntry,
|
||||
/// the value is valid until the end of the function. For other values, the
|
||||
/// index points to the entry in the entry vector that ends this debug
|
||||
/// value. The ending entry can either be an overlapping debug value, or
|
||||
/// an instruction that clobbers the value.
|
||||
///
|
||||
/// * Clobbering entry:
|
||||
///
|
||||
/// This entry's instruction clobbers one or more preceding
|
||||
/// register-described debug values that have their end index
|
||||
/// set to this entry's position in the entry vector.
|
||||
class Entry {
|
||||
friend DbgValueHistoryMap;
|
||||
|
||||
public:
|
||||
enum EntryKind { DbgValue, Clobber };
|
||||
|
||||
Entry(const MachineInstr *Instr, EntryKind Kind)
|
||||
: Instr(Instr, Kind), EndIndex(NoEntry) {}
|
||||
|
||||
const MachineInstr *getInstr() const { return Instr.getPointer(); }
|
||||
EntryIndex getEndIndex() const { return EndIndex; }
|
||||
EntryKind getEntryKind() const { return Instr.getInt(); }
|
||||
|
||||
bool isClobber() const { return getEntryKind() == Clobber; }
|
||||
bool isDbgValue() const { return getEntryKind() == DbgValue; }
|
||||
bool isClosed() const { return EndIndex != NoEntry; }
|
||||
|
||||
void endEntry(EntryIndex EndIndex);
|
||||
|
||||
private:
|
||||
PointerIntPair<const MachineInstr *, 1, EntryKind> Instr;
|
||||
EntryIndex EndIndex;
|
||||
};
|
||||
using Entries = SmallVector<Entry, 4>;
|
||||
using InlinedEntity = std::pair<const DINode *, const DILocation *>;
|
||||
using EntriesMap = MapVector<InlinedEntity, Entries>;
|
||||
|
||||
private:
|
||||
EntriesMap VarEntries;
|
||||
|
||||
public:
|
||||
bool startDbgValue(InlinedEntity Var, const MachineInstr &MI,
|
||||
EntryIndex &NewIndex);
|
||||
EntryIndex startClobber(InlinedEntity Var, const MachineInstr &MI);
|
||||
|
||||
Entry &getEntry(InlinedEntity Var, EntryIndex Index) {
|
||||
auto &Entries = VarEntries[Var];
|
||||
return Entries[Index];
|
||||
}
|
||||
|
||||
/// Test whether a vector of entries features any non-empty locations. It
|
||||
/// could have no entries, or only DBG_VALUE $noreg entries.
|
||||
bool hasNonEmptyLocation(const Entries &Entries) const;
|
||||
|
||||
/// Drop location ranges which exist entirely outside each variable's scope.
|
||||
void trimLocationRanges(const MachineFunction &MF, LexicalScopes &LScopes,
|
||||
const InstructionOrdering &Ordering);
|
||||
bool empty() const { return VarEntries.empty(); }
|
||||
void clear() { VarEntries.clear(); }
|
||||
EntriesMap::const_iterator begin() const { return VarEntries.begin(); }
|
||||
EntriesMap::const_iterator end() const { return VarEntries.end(); }
|
||||
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
LLVM_DUMP_METHOD void dump() const;
|
||||
#endif
|
||||
};
|
||||
|
||||
/// For each inlined instance of a source-level label, keep the corresponding
|
||||
/// DBG_LABEL instruction. The DBG_LABEL instruction could be used to generate
|
||||
/// a temporary (assembler) label before it.
|
||||
class DbgLabelInstrMap {
|
||||
public:
|
||||
using InlinedEntity = std::pair<const DINode *, const DILocation *>;
|
||||
using InstrMap = MapVector<InlinedEntity, const MachineInstr *>;
|
||||
|
||||
private:
|
||||
InstrMap LabelInstr;
|
||||
|
||||
public:
|
||||
void addInstr(InlinedEntity Label, const MachineInstr &MI);
|
||||
|
||||
bool empty() const { return LabelInstr.empty(); }
|
||||
void clear() { LabelInstr.clear(); }
|
||||
InstrMap::const_iterator begin() const { return LabelInstr.begin(); }
|
||||
InstrMap::const_iterator end() const { return LabelInstr.end(); }
|
||||
};
|
||||
|
||||
void calculateDbgEntityHistory(const MachineFunction *MF,
|
||||
const TargetRegisterInfo *TRI,
|
||||
DbgValueHistoryMap &DbgValues,
|
||||
DbgLabelInstrMap &DbgLabels);
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_DBGENTITYHISTORYCALCULATOR_H
|
||||
146
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/DebugHandlerBase.h
vendored
Normal file
146
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/DebugHandlerBase.h
vendored
Normal file
@@ -0,0 +1,146 @@
|
||||
//===-- llvm/CodeGen/DebugHandlerBase.h -----------------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Common functionality for different debug information format backends.
|
||||
// LLVM currently supports DWARF and CodeView.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_DEBUGHANDLERBASE_H
|
||||
#define LLVM_CODEGEN_DEBUGHANDLERBASE_H
|
||||
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/CodeGen/AsmPrinterHandler.h"
|
||||
#include "llvm/CodeGen/DbgEntityHistoryCalculator.h"
|
||||
#include "llvm/CodeGen/LexicalScopes.h"
|
||||
#include "llvm/IR/DebugInfoMetadata.h"
|
||||
#include "llvm/IR/DebugLoc.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class AsmPrinter;
|
||||
class MachineInstr;
|
||||
class MachineModuleInfo;
|
||||
|
||||
/// Represents the location at which a variable is stored.
|
||||
struct DbgVariableLocation {
|
||||
/// Base register.
|
||||
unsigned Register;
|
||||
|
||||
/// Chain of offsetted loads necessary to load the value if it lives in
|
||||
/// memory. Every load except for the last is pointer-sized.
|
||||
SmallVector<int64_t, 1> LoadChain;
|
||||
|
||||
/// Present if the location is part of a larger variable.
|
||||
llvm::Optional<llvm::DIExpression::FragmentInfo> FragmentInfo;
|
||||
|
||||
/// Extract a VariableLocation from a MachineInstr.
|
||||
/// This will only work if Instruction is a debug value instruction
|
||||
/// and the associated DIExpression is in one of the supported forms.
|
||||
/// If these requirements are not met, the returned Optional will not
|
||||
/// have a value.
|
||||
static Optional<DbgVariableLocation>
|
||||
extractFromMachineInstruction(const MachineInstr &Instruction);
|
||||
};
|
||||
|
||||
/// Base class for debug information backends. Common functionality related to
|
||||
/// tracking which variables and scopes are alive at a given PC live here.
|
||||
class DebugHandlerBase : public AsmPrinterHandler {
|
||||
protected:
|
||||
DebugHandlerBase(AsmPrinter *A);
|
||||
|
||||
/// Target of debug info emission.
|
||||
AsmPrinter *Asm;
|
||||
|
||||
/// Collected machine module information.
|
||||
MachineModuleInfo *MMI;
|
||||
|
||||
/// Previous instruction's location information. This is used to
|
||||
/// determine label location to indicate scope boundaries in debug info.
|
||||
/// We track the previous instruction's source location (if not line 0),
|
||||
/// whether it was a label, and its parent BB.
|
||||
DebugLoc PrevInstLoc;
|
||||
MCSymbol *PrevLabel = nullptr;
|
||||
const MachineBasicBlock *PrevInstBB = nullptr;
|
||||
|
||||
/// This location indicates end of function prologue and beginning of
|
||||
/// function body.
|
||||
DebugLoc PrologEndLoc;
|
||||
|
||||
/// If nonnull, stores the current machine instruction we're processing.
|
||||
const MachineInstr *CurMI = nullptr;
|
||||
|
||||
LexicalScopes LScopes;
|
||||
|
||||
/// History of DBG_VALUE and clobber instructions for each user
|
||||
/// variable. Variables are listed in order of appearance.
|
||||
DbgValueHistoryMap DbgValues;
|
||||
|
||||
/// Mapping of inlined labels and DBG_LABEL machine instruction.
|
||||
DbgLabelInstrMap DbgLabels;
|
||||
|
||||
/// Maps instruction with label emitted before instruction.
|
||||
/// FIXME: Make this private from DwarfDebug, we have the necessary accessors
|
||||
/// for it.
|
||||
DenseMap<const MachineInstr *, MCSymbol *> LabelsBeforeInsn;
|
||||
|
||||
/// Maps instruction with label emitted after instruction.
|
||||
DenseMap<const MachineInstr *, MCSymbol *> LabelsAfterInsn;
|
||||
|
||||
/// Identify instructions that are marking the beginning of or
|
||||
/// ending of a scope.
|
||||
void identifyScopeMarkers();
|
||||
|
||||
/// Ensure that a label will be emitted before MI.
|
||||
void requestLabelBeforeInsn(const MachineInstr *MI) {
|
||||
LabelsBeforeInsn.insert(std::make_pair(MI, nullptr));
|
||||
}
|
||||
|
||||
/// Ensure that a label will be emitted after MI.
|
||||
void requestLabelAfterInsn(const MachineInstr *MI) {
|
||||
LabelsAfterInsn.insert(std::make_pair(MI, nullptr));
|
||||
}
|
||||
|
||||
virtual void beginFunctionImpl(const MachineFunction *MF) = 0;
|
||||
virtual void endFunctionImpl(const MachineFunction *MF) = 0;
|
||||
virtual void skippedNonDebugFunction() {}
|
||||
|
||||
private:
|
||||
InstructionOrdering InstOrdering;
|
||||
|
||||
// AsmPrinterHandler overrides.
|
||||
public:
|
||||
void beginModule(Module *M) override;
|
||||
|
||||
void beginInstruction(const MachineInstr *MI) override;
|
||||
void endInstruction() override;
|
||||
|
||||
void beginFunction(const MachineFunction *MF) override;
|
||||
void endFunction(const MachineFunction *MF) override;
|
||||
|
||||
void beginBasicBlock(const MachineBasicBlock &MBB) override;
|
||||
void endBasicBlock(const MachineBasicBlock &MBB) override;
|
||||
|
||||
/// Return Label preceding the instruction.
|
||||
MCSymbol *getLabelBeforeInsn(const MachineInstr *MI);
|
||||
|
||||
/// Return Label immediately following the instruction.
|
||||
MCSymbol *getLabelAfterInsn(const MachineInstr *MI);
|
||||
|
||||
/// If this type is derived from a base type then return base type size.
|
||||
static uint64_t getBaseTypeSize(const DIType *Ty);
|
||||
|
||||
/// Return true if type encoding is unsigned.
|
||||
static bool isUnsignedDIType(const DIType *Ty);
|
||||
|
||||
const InstructionOrdering &getInstOrdering() const { return InstOrdering; }
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
71
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/DwarfStringPoolEntry.h
vendored
Normal file
71
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/DwarfStringPoolEntry.h
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
//===- llvm/CodeGen/DwarfStringPoolEntry.h - String pool entry --*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_DWARFSTRINGPOOLENTRY_H
|
||||
#define LLVM_CODEGEN_DWARFSTRINGPOOLENTRY_H
|
||||
|
||||
#include "llvm/ADT/PointerIntPair.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MCSymbol;
|
||||
|
||||
/// Data for a string pool entry.
|
||||
struct DwarfStringPoolEntry {
|
||||
static constexpr unsigned NotIndexed = -1;
|
||||
|
||||
MCSymbol *Symbol;
|
||||
uint64_t Offset;
|
||||
unsigned Index;
|
||||
|
||||
bool isIndexed() const { return Index != NotIndexed; }
|
||||
};
|
||||
|
||||
/// String pool entry reference.
|
||||
class DwarfStringPoolEntryRef {
|
||||
PointerIntPair<const StringMapEntry<DwarfStringPoolEntry> *, 1, bool>
|
||||
MapEntryAndIndexed;
|
||||
|
||||
const StringMapEntry<DwarfStringPoolEntry> *getMapEntry() const {
|
||||
return MapEntryAndIndexed.getPointer();
|
||||
}
|
||||
|
||||
public:
|
||||
DwarfStringPoolEntryRef() = default;
|
||||
DwarfStringPoolEntryRef(const StringMapEntry<DwarfStringPoolEntry> &Entry,
|
||||
bool Indexed)
|
||||
: MapEntryAndIndexed(&Entry, Indexed) {}
|
||||
|
||||
explicit operator bool() const { return getMapEntry(); }
|
||||
MCSymbol *getSymbol() const {
|
||||
assert(getMapEntry()->second.Symbol && "No symbol available!");
|
||||
return getMapEntry()->second.Symbol;
|
||||
}
|
||||
uint64_t getOffset() const { return getMapEntry()->second.Offset; }
|
||||
bool isIndexed() const { return MapEntryAndIndexed.getInt(); }
|
||||
unsigned getIndex() const {
|
||||
assert(isIndexed());
|
||||
assert(getMapEntry()->getValue().isIndexed());
|
||||
return getMapEntry()->second.Index;
|
||||
}
|
||||
StringRef getString() const { return getMapEntry()->first(); }
|
||||
/// Return the entire string pool entry for convenience.
|
||||
DwarfStringPoolEntry getEntry() const { return getMapEntry()->getValue(); }
|
||||
|
||||
bool operator==(const DwarfStringPoolEntryRef &X) const {
|
||||
return getMapEntry() == X.getMapEntry();
|
||||
}
|
||||
bool operator!=(const DwarfStringPoolEntryRef &X) const {
|
||||
return getMapEntry() != X.getMapEntry();
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
62
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/EdgeBundles.h
vendored
Normal file
62
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/EdgeBundles.h
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
//===-------- EdgeBundles.h - Bundles of CFG edges --------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The EdgeBundles analysis forms equivalence classes of CFG edges such that all
|
||||
// edges leaving a machine basic block are in the same bundle, and all edges
|
||||
// entering a machine basic block are in the same bundle.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_EDGEBUNDLES_H
|
||||
#define LLVM_CODEGEN_EDGEBUNDLES_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/IntEqClasses.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class EdgeBundles : public MachineFunctionPass {
|
||||
const MachineFunction *MF;
|
||||
|
||||
/// EC - Each edge bundle is an equivalence class. The keys are:
|
||||
/// 2*BB->getNumber() -> Ingoing bundle.
|
||||
/// 2*BB->getNumber()+1 -> Outgoing bundle.
|
||||
IntEqClasses EC;
|
||||
|
||||
/// Blocks - Map each bundle to a list of basic block numbers.
|
||||
SmallVector<SmallVector<unsigned, 8>, 4> Blocks;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
EdgeBundles() : MachineFunctionPass(ID) {}
|
||||
|
||||
/// getBundle - Return the ingoing (Out = false) or outgoing (Out = true)
|
||||
/// bundle number for basic block #N
|
||||
unsigned getBundle(unsigned N, bool Out) const { return EC[2 * N + Out]; }
|
||||
|
||||
/// getNumBundles - Return the total number of bundles in the CFG.
|
||||
unsigned getNumBundles() const { return EC.getNumClasses(); }
|
||||
|
||||
/// getBlocks - Return an array of blocks that are connected to Bundle.
|
||||
ArrayRef<unsigned> getBlocks(unsigned Bundle) const { return Blocks[Bundle]; }
|
||||
|
||||
/// getMachineFunction - Return the last machine function computed.
|
||||
const MachineFunction *getMachineFunction() const { return MF; }
|
||||
|
||||
/// view - Visualize the annotated bipartite CFG with Graphviz.
|
||||
void view() const;
|
||||
|
||||
private:
|
||||
bool runOnMachineFunction(MachineFunction&) override;
|
||||
void getAnalysisUsage(AnalysisUsage&) const override;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
221
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/ExecutionDomainFix.h
vendored
Normal file
221
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/ExecutionDomainFix.h
vendored
Normal file
@@ -0,0 +1,221 @@
|
||||
//==-- llvm/CodeGen/ExecutionDomainFix.h - Execution Domain Fix -*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
/// \file Execution Domain Fix pass.
|
||||
///
|
||||
/// Some X86 SSE instructions like mov, and, or, xor are available in different
|
||||
/// variants for different operand types. These variant instructions are
|
||||
/// equivalent, but on Nehalem and newer cpus there is extra latency
|
||||
/// transferring data between integer and floating point domains. ARM cores
|
||||
/// have similar issues when they are configured with both VFP and NEON
|
||||
/// pipelines.
|
||||
///
|
||||
/// This pass changes the variant instructions to minimize domain crossings.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_EXECUTIONDOMAINFIX_H
|
||||
#define LLVM_CODEGEN_EXECUTIONDOMAINFIX_H
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/CodeGen/LoopTraversal.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/ReachingDefAnalysis.h"
|
||||
#include "llvm/CodeGen/TargetRegisterInfo.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MachineInstr;
|
||||
class TargetInstrInfo;
|
||||
|
||||
/// A DomainValue is a bit like LiveIntervals' ValNo, but it also keeps track
|
||||
/// of execution domains.
|
||||
///
|
||||
/// An open DomainValue represents a set of instructions that can still switch
|
||||
/// execution domain. Multiple registers may refer to the same open
|
||||
/// DomainValue - they will eventually be collapsed to the same execution
|
||||
/// domain.
|
||||
///
|
||||
/// A collapsed DomainValue represents a single register that has been forced
|
||||
/// into one of more execution domains. There is a separate collapsed
|
||||
/// DomainValue for each register, but it may contain multiple execution
|
||||
/// domains. A register value is initially created in a single execution
|
||||
/// domain, but if we were forced to pay the penalty of a domain crossing, we
|
||||
/// keep track of the fact that the register is now available in multiple
|
||||
/// domains.
|
||||
struct DomainValue {
|
||||
/// Basic reference counting.
|
||||
unsigned Refs = 0;
|
||||
|
||||
/// Bitmask of available domains. For an open DomainValue, it is the still
|
||||
/// possible domains for collapsing. For a collapsed DomainValue it is the
|
||||
/// domains where the register is available for free.
|
||||
unsigned AvailableDomains;
|
||||
|
||||
/// Pointer to the next DomainValue in a chain. When two DomainValues are
|
||||
/// merged, Victim.Next is set to point to Victor, so old DomainValue
|
||||
/// references can be updated by following the chain.
|
||||
DomainValue *Next;
|
||||
|
||||
/// Twiddleable instructions using or defining these registers.
|
||||
SmallVector<MachineInstr *, 8> Instrs;
|
||||
|
||||
DomainValue() { clear(); }
|
||||
|
||||
/// A collapsed DomainValue has no instructions to twiddle - it simply keeps
|
||||
/// track of the domains where the registers are already available.
|
||||
bool isCollapsed() const { return Instrs.empty(); }
|
||||
|
||||
/// Is domain available?
|
||||
bool hasDomain(unsigned domain) const {
|
||||
assert(domain <
|
||||
static_cast<unsigned>(std::numeric_limits<unsigned>::digits) &&
|
||||
"undefined behavior");
|
||||
return AvailableDomains & (1u << domain);
|
||||
}
|
||||
|
||||
/// Mark domain as available.
|
||||
void addDomain(unsigned domain) {
|
||||
assert(domain <
|
||||
static_cast<unsigned>(std::numeric_limits<unsigned>::digits) &&
|
||||
"undefined behavior");
|
||||
AvailableDomains |= 1u << domain;
|
||||
}
|
||||
|
||||
// Restrict to a single domain available.
|
||||
void setSingleDomain(unsigned domain) {
|
||||
assert(domain <
|
||||
static_cast<unsigned>(std::numeric_limits<unsigned>::digits) &&
|
||||
"undefined behavior");
|
||||
AvailableDomains = 1u << domain;
|
||||
}
|
||||
|
||||
/// Return bitmask of domains that are available and in mask.
|
||||
unsigned getCommonDomains(unsigned mask) const {
|
||||
return AvailableDomains & mask;
|
||||
}
|
||||
|
||||
/// First domain available.
|
||||
unsigned getFirstDomain() const {
|
||||
return countTrailingZeros(AvailableDomains);
|
||||
}
|
||||
|
||||
/// Clear this DomainValue and point to next which has all its data.
|
||||
void clear() {
|
||||
AvailableDomains = 0;
|
||||
Next = nullptr;
|
||||
Instrs.clear();
|
||||
}
|
||||
};
|
||||
|
||||
class ExecutionDomainFix : public MachineFunctionPass {
|
||||
SpecificBumpPtrAllocator<DomainValue> Allocator;
|
||||
SmallVector<DomainValue *, 16> Avail;
|
||||
|
||||
const TargetRegisterClass *const RC;
|
||||
MachineFunction *MF;
|
||||
const TargetInstrInfo *TII;
|
||||
const TargetRegisterInfo *TRI;
|
||||
std::vector<SmallVector<int, 1>> AliasMap;
|
||||
const unsigned NumRegs;
|
||||
/// Value currently in each register, or NULL when no value is being tracked.
|
||||
/// This counts as a DomainValue reference.
|
||||
using LiveRegsDVInfo = std::vector<DomainValue *>;
|
||||
LiveRegsDVInfo LiveRegs;
|
||||
/// Keeps domain information for all registers. Note that this
|
||||
/// is different from the usual definition notion of liveness. The CPU
|
||||
/// doesn't care whether or not we consider a register killed.
|
||||
using OutRegsInfoMap = SmallVector<LiveRegsDVInfo, 4>;
|
||||
OutRegsInfoMap MBBOutRegsInfos;
|
||||
|
||||
ReachingDefAnalysis *RDA;
|
||||
|
||||
public:
|
||||
ExecutionDomainFix(char &PassID, const TargetRegisterClass &RC)
|
||||
: MachineFunctionPass(PassID), RC(&RC), NumRegs(RC.getNumRegs()) {}
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
AU.setPreservesAll();
|
||||
AU.addRequired<ReachingDefAnalysis>();
|
||||
MachineFunctionPass::getAnalysisUsage(AU);
|
||||
}
|
||||
|
||||
bool runOnMachineFunction(MachineFunction &MF) override;
|
||||
|
||||
MachineFunctionProperties getRequiredProperties() const override {
|
||||
return MachineFunctionProperties().set(
|
||||
MachineFunctionProperties::Property::NoVRegs);
|
||||
}
|
||||
|
||||
private:
|
||||
/// Translate TRI register number to a list of indices into our smaller tables
|
||||
/// of interesting registers.
|
||||
iterator_range<SmallVectorImpl<int>::const_iterator>
|
||||
regIndices(unsigned Reg) const;
|
||||
|
||||
/// DomainValue allocation.
|
||||
DomainValue *alloc(int domain = -1);
|
||||
|
||||
/// Add reference to DV.
|
||||
DomainValue *retain(DomainValue *DV) {
|
||||
if (DV)
|
||||
++DV->Refs;
|
||||
return DV;
|
||||
}
|
||||
|
||||
/// Release a reference to DV. When the last reference is released,
|
||||
/// collapse if needed.
|
||||
void release(DomainValue *);
|
||||
|
||||
/// Follow the chain of dead DomainValues until a live DomainValue is reached.
|
||||
/// Update the referenced pointer when necessary.
|
||||
DomainValue *resolve(DomainValue *&);
|
||||
|
||||
/// Set LiveRegs[rx] = dv, updating reference counts.
|
||||
void setLiveReg(int rx, DomainValue *DV);
|
||||
|
||||
/// Kill register rx, recycle or collapse any DomainValue.
|
||||
void kill(int rx);
|
||||
|
||||
/// Force register rx into domain.
|
||||
void force(int rx, unsigned domain);
|
||||
|
||||
/// Collapse open DomainValue into given domain. If there are multiple
|
||||
/// registers using dv, they each get a unique collapsed DomainValue.
|
||||
void collapse(DomainValue *dv, unsigned domain);
|
||||
|
||||
/// All instructions and registers in B are moved to A, and B is released.
|
||||
bool merge(DomainValue *A, DomainValue *B);
|
||||
|
||||
/// Set up LiveRegs by merging predecessor live-out values.
|
||||
void enterBasicBlock(const LoopTraversal::TraversedMBBInfo &TraversedMBB);
|
||||
|
||||
/// Update live-out values.
|
||||
void leaveBasicBlock(const LoopTraversal::TraversedMBBInfo &TraversedMBB);
|
||||
|
||||
/// Process he given basic block.
|
||||
void processBasicBlock(const LoopTraversal::TraversedMBBInfo &TraversedMBB);
|
||||
|
||||
/// Visit given insturcion.
|
||||
bool visitInstr(MachineInstr *);
|
||||
|
||||
/// Update def-ages for registers defined by MI.
|
||||
/// If Kill is set, also kill off DomainValues clobbered by the defs.
|
||||
void processDefs(MachineInstr *, bool Kill);
|
||||
|
||||
/// A soft instruction can be changed to work in other domains given by mask.
|
||||
void visitSoftInstr(MachineInstr *, unsigned mask);
|
||||
|
||||
/// A hard instruction only works in one domain. All input registers will be
|
||||
/// forced into that domain.
|
||||
void visitHardInstr(MachineInstr *, unsigned domain);
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_EXECUTIONDOMAINFIX_H
|
||||
23
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/ExpandReductions.h
vendored
Normal file
23
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/ExpandReductions.h
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
//===----- ExpandReductions.h - Expand experimental reduction intrinsics --===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_EXPANDREDUCTIONS_H
|
||||
#define LLVM_CODEGEN_EXPANDREDUCTIONS_H
|
||||
|
||||
#include "llvm/IR/PassManager.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class ExpandReductionsPass
|
||||
: public PassInfoMixin<ExpandReductionsPass> {
|
||||
public:
|
||||
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
|
||||
};
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_EXPANDREDUCTIONS_H
|
||||
23
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/ExpandVectorPredication.h
vendored
Normal file
23
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/ExpandVectorPredication.h
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
//===-- ExpandVectorPredication.h - Expand vector predication ---*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_EXPANDVECTORPREDICATION_H
|
||||
#define LLVM_CODEGEN_EXPANDVECTORPREDICATION_H
|
||||
|
||||
#include "llvm/IR/PassManager.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class ExpandVectorPredicationPass
|
||||
: public PassInfoMixin<ExpandVectorPredicationPass> {
|
||||
public:
|
||||
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
|
||||
};
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_EXPANDVECTORPREDICATION_H
|
||||
568
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/FastISel.h
vendored
Normal file
568
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/FastISel.h
vendored
Normal file
@@ -0,0 +1,568 @@
|
||||
//===- FastISel.h - Definition of the FastISel class ------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// This file defines the FastISel class.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_FASTISEL_H
|
||||
#define LLVM_CODEGEN_FASTISEL_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/TargetLowering.h"
|
||||
#include "llvm/IR/Attributes.h"
|
||||
#include "llvm/IR/CallingConv.h"
|
||||
#include "llvm/IR/DebugLoc.h"
|
||||
#include "llvm/IR/DerivedTypes.h"
|
||||
#include "llvm/IR/InstrTypes.h"
|
||||
#include "llvm/IR/IntrinsicInst.h"
|
||||
#include "llvm/Support/MachineValueType.h"
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class AllocaInst;
|
||||
class BasicBlock;
|
||||
class CallInst;
|
||||
class Constant;
|
||||
class ConstantFP;
|
||||
class DataLayout;
|
||||
class FunctionLoweringInfo;
|
||||
class LoadInst;
|
||||
class MachineConstantPool;
|
||||
class MachineFrameInfo;
|
||||
class MachineFunction;
|
||||
class MachineInstr;
|
||||
class MachineMemOperand;
|
||||
class MachineOperand;
|
||||
class MachineRegisterInfo;
|
||||
class MCContext;
|
||||
class MCInstrDesc;
|
||||
class MCSymbol;
|
||||
class TargetInstrInfo;
|
||||
class TargetLibraryInfo;
|
||||
class TargetMachine;
|
||||
class TargetRegisterClass;
|
||||
class TargetRegisterInfo;
|
||||
class Type;
|
||||
class User;
|
||||
class Value;
|
||||
|
||||
/// This is a fast-path instruction selection class that generates poor
|
||||
/// code and doesn't support illegal types or non-trivial lowering, but runs
|
||||
/// quickly.
|
||||
class FastISel {
|
||||
public:
|
||||
using ArgListEntry = TargetLoweringBase::ArgListEntry;
|
||||
using ArgListTy = TargetLoweringBase::ArgListTy;
|
||||
struct CallLoweringInfo {
|
||||
Type *RetTy = nullptr;
|
||||
bool RetSExt : 1;
|
||||
bool RetZExt : 1;
|
||||
bool IsVarArg : 1;
|
||||
bool IsInReg : 1;
|
||||
bool DoesNotReturn : 1;
|
||||
bool IsReturnValueUsed : 1;
|
||||
bool IsPatchPoint : 1;
|
||||
|
||||
// IsTailCall Should be modified by implementations of FastLowerCall
|
||||
// that perform tail call conversions.
|
||||
bool IsTailCall = false;
|
||||
|
||||
unsigned NumFixedArgs = -1;
|
||||
CallingConv::ID CallConv = CallingConv::C;
|
||||
const Value *Callee = nullptr;
|
||||
MCSymbol *Symbol = nullptr;
|
||||
ArgListTy Args;
|
||||
const CallBase *CB = nullptr;
|
||||
MachineInstr *Call = nullptr;
|
||||
Register ResultReg;
|
||||
unsigned NumResultRegs = 0;
|
||||
|
||||
SmallVector<Value *, 16> OutVals;
|
||||
SmallVector<ISD::ArgFlagsTy, 16> OutFlags;
|
||||
SmallVector<Register, 16> OutRegs;
|
||||
SmallVector<ISD::InputArg, 4> Ins;
|
||||
SmallVector<Register, 4> InRegs;
|
||||
|
||||
CallLoweringInfo()
|
||||
: RetSExt(false), RetZExt(false), IsVarArg(false), IsInReg(false),
|
||||
DoesNotReturn(false), IsReturnValueUsed(true), IsPatchPoint(false) {}
|
||||
|
||||
CallLoweringInfo &setCallee(Type *ResultTy, FunctionType *FuncTy,
|
||||
const Value *Target, ArgListTy &&ArgsList,
|
||||
const CallBase &Call) {
|
||||
RetTy = ResultTy;
|
||||
Callee = Target;
|
||||
|
||||
IsInReg = Call.hasRetAttr(Attribute::InReg);
|
||||
DoesNotReturn = Call.doesNotReturn();
|
||||
IsVarArg = FuncTy->isVarArg();
|
||||
IsReturnValueUsed = !Call.use_empty();
|
||||
RetSExt = Call.hasRetAttr(Attribute::SExt);
|
||||
RetZExt = Call.hasRetAttr(Attribute::ZExt);
|
||||
|
||||
CallConv = Call.getCallingConv();
|
||||
Args = std::move(ArgsList);
|
||||
NumFixedArgs = FuncTy->getNumParams();
|
||||
|
||||
CB = &Call;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CallLoweringInfo &setCallee(Type *ResultTy, FunctionType *FuncTy,
|
||||
MCSymbol *Target, ArgListTy &&ArgsList,
|
||||
const CallBase &Call,
|
||||
unsigned FixedArgs = ~0U) {
|
||||
RetTy = ResultTy;
|
||||
Callee = Call.getCalledOperand();
|
||||
Symbol = Target;
|
||||
|
||||
IsInReg = Call.hasRetAttr(Attribute::InReg);
|
||||
DoesNotReturn = Call.doesNotReturn();
|
||||
IsVarArg = FuncTy->isVarArg();
|
||||
IsReturnValueUsed = !Call.use_empty();
|
||||
RetSExt = Call.hasRetAttr(Attribute::SExt);
|
||||
RetZExt = Call.hasRetAttr(Attribute::ZExt);
|
||||
|
||||
CallConv = Call.getCallingConv();
|
||||
Args = std::move(ArgsList);
|
||||
NumFixedArgs = (FixedArgs == ~0U) ? FuncTy->getNumParams() : FixedArgs;
|
||||
|
||||
CB = &Call;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
CallLoweringInfo &setCallee(CallingConv::ID CC, Type *ResultTy,
|
||||
const Value *Target, ArgListTy &&ArgsList,
|
||||
unsigned FixedArgs = ~0U) {
|
||||
RetTy = ResultTy;
|
||||
Callee = Target;
|
||||
CallConv = CC;
|
||||
Args = std::move(ArgsList);
|
||||
NumFixedArgs = (FixedArgs == ~0U) ? Args.size() : FixedArgs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CallLoweringInfo &setCallee(const DataLayout &DL, MCContext &Ctx,
|
||||
CallingConv::ID CC, Type *ResultTy,
|
||||
StringRef Target, ArgListTy &&ArgsList,
|
||||
unsigned FixedArgs = ~0U);
|
||||
|
||||
CallLoweringInfo &setCallee(CallingConv::ID CC, Type *ResultTy,
|
||||
MCSymbol *Target, ArgListTy &&ArgsList,
|
||||
unsigned FixedArgs = ~0U) {
|
||||
RetTy = ResultTy;
|
||||
Symbol = Target;
|
||||
CallConv = CC;
|
||||
Args = std::move(ArgsList);
|
||||
NumFixedArgs = (FixedArgs == ~0U) ? Args.size() : FixedArgs;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CallLoweringInfo &setTailCall(bool Value = true) {
|
||||
IsTailCall = Value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
CallLoweringInfo &setIsPatchPoint(bool Value = true) {
|
||||
IsPatchPoint = Value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
ArgListTy &getArgs() { return Args; }
|
||||
|
||||
void clearOuts() {
|
||||
OutVals.clear();
|
||||
OutFlags.clear();
|
||||
OutRegs.clear();
|
||||
}
|
||||
|
||||
void clearIns() {
|
||||
Ins.clear();
|
||||
InRegs.clear();
|
||||
}
|
||||
};
|
||||
|
||||
protected:
|
||||
DenseMap<const Value *, Register> LocalValueMap;
|
||||
FunctionLoweringInfo &FuncInfo;
|
||||
MachineFunction *MF;
|
||||
MachineRegisterInfo &MRI;
|
||||
MachineFrameInfo &MFI;
|
||||
MachineConstantPool &MCP;
|
||||
DebugLoc DbgLoc;
|
||||
const TargetMachine &TM;
|
||||
const DataLayout &DL;
|
||||
const TargetInstrInfo &TII;
|
||||
const TargetLowering &TLI;
|
||||
const TargetRegisterInfo &TRI;
|
||||
const TargetLibraryInfo *LibInfo;
|
||||
bool SkipTargetIndependentISel;
|
||||
bool UseInstrRefDebugInfo = false;
|
||||
|
||||
/// The position of the last instruction for materializing constants
|
||||
/// for use in the current block. It resets to EmitStartPt when it makes sense
|
||||
/// (for example, it's usually profitable to avoid function calls between the
|
||||
/// definition and the use)
|
||||
MachineInstr *LastLocalValue = nullptr;
|
||||
|
||||
/// The top most instruction in the current block that is allowed for
|
||||
/// emitting local variables. LastLocalValue resets to EmitStartPt when it
|
||||
/// makes sense (for example, on function calls)
|
||||
MachineInstr *EmitStartPt = nullptr;
|
||||
|
||||
public:
|
||||
virtual ~FastISel();
|
||||
|
||||
/// Return the position of the last instruction emitted for
|
||||
/// materializing constants for use in the current block.
|
||||
MachineInstr *getLastLocalValue() { return LastLocalValue; }
|
||||
|
||||
/// Update the position of the last instruction emitted for
|
||||
/// materializing constants for use in the current block.
|
||||
void setLastLocalValue(MachineInstr *I) {
|
||||
EmitStartPt = I;
|
||||
LastLocalValue = I;
|
||||
}
|
||||
|
||||
/// Set the current block to which generated machine instructions will
|
||||
/// be appended.
|
||||
void startNewBlock();
|
||||
|
||||
/// Flush the local value map.
|
||||
void finishBasicBlock();
|
||||
|
||||
/// Return current debug location information.
|
||||
DebugLoc getCurDebugLoc() const { return DbgLoc; }
|
||||
|
||||
/// Do "fast" instruction selection for function arguments and append
|
||||
/// the machine instructions to the current block. Returns true when
|
||||
/// successful.
|
||||
bool lowerArguments();
|
||||
|
||||
/// Do "fast" instruction selection for the given LLVM IR instruction
|
||||
/// and append the generated machine instructions to the current block.
|
||||
/// Returns true if selection was successful.
|
||||
bool selectInstruction(const Instruction *I);
|
||||
|
||||
/// Do "fast" instruction selection for the given LLVM IR operator
|
||||
/// (Instruction or ConstantExpr), and append generated machine instructions
|
||||
/// to the current block. Return true if selection was successful.
|
||||
bool selectOperator(const User *I, unsigned Opcode);
|
||||
|
||||
/// Create a virtual register and arrange for it to be assigned the
|
||||
/// value for the given LLVM value.
|
||||
Register getRegForValue(const Value *V);
|
||||
|
||||
/// Look up the value to see if its value is already cached in a
|
||||
/// register. It may be defined by instructions across blocks or defined
|
||||
/// locally.
|
||||
Register lookUpRegForValue(const Value *V);
|
||||
|
||||
/// This is a wrapper around getRegForValue that also takes care of
|
||||
/// truncating or sign-extending the given getelementptr index value.
|
||||
Register getRegForGEPIndex(const Value *Idx);
|
||||
|
||||
/// We're checking to see if we can fold \p LI into \p FoldInst. Note
|
||||
/// that we could have a sequence where multiple LLVM IR instructions are
|
||||
/// folded into the same machineinstr. For example we could have:
|
||||
///
|
||||
/// A: x = load i32 *P
|
||||
/// B: y = icmp A, 42
|
||||
/// C: br y, ...
|
||||
///
|
||||
/// In this scenario, \p LI is "A", and \p FoldInst is "C". We know about "B"
|
||||
/// (and any other folded instructions) because it is between A and C.
|
||||
///
|
||||
/// If we succeed folding, return true.
|
||||
bool tryToFoldLoad(const LoadInst *LI, const Instruction *FoldInst);
|
||||
|
||||
/// The specified machine instr operand is a vreg, and that vreg is
|
||||
/// being provided by the specified load instruction. If possible, try to
|
||||
/// fold the load as an operand to the instruction, returning true if
|
||||
/// possible.
|
||||
///
|
||||
/// This method should be implemented by targets.
|
||||
virtual bool tryToFoldLoadIntoMI(MachineInstr * /*MI*/, unsigned /*OpNo*/,
|
||||
const LoadInst * /*LI*/) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Reset InsertPt to prepare for inserting instructions into the
|
||||
/// current block.
|
||||
void recomputeInsertPt();
|
||||
|
||||
/// Remove all dead instructions between the I and E.
|
||||
void removeDeadCode(MachineBasicBlock::iterator I,
|
||||
MachineBasicBlock::iterator E);
|
||||
|
||||
using SavePoint = MachineBasicBlock::iterator;
|
||||
|
||||
/// Prepare InsertPt to begin inserting instructions into the local
|
||||
/// value area and return the old insert position.
|
||||
SavePoint enterLocalValueArea();
|
||||
|
||||
/// Reset InsertPt to the given old insert position.
|
||||
void leaveLocalValueArea(SavePoint Old);
|
||||
|
||||
/// Signal whether instruction referencing variable locations are desired for
|
||||
/// this function's debug-info.
|
||||
void useInstrRefDebugInfo(bool Flag) {
|
||||
UseInstrRefDebugInfo = Flag;
|
||||
}
|
||||
|
||||
protected:
|
||||
explicit FastISel(FunctionLoweringInfo &FuncInfo,
|
||||
const TargetLibraryInfo *LibInfo,
|
||||
bool SkipTargetIndependentISel = false);
|
||||
|
||||
/// This method is called by target-independent code when the normal
|
||||
/// FastISel process fails to select an instruction. This gives targets a
|
||||
/// chance to emit code for anything that doesn't fit into FastISel's
|
||||
/// framework. It returns true if it was successful.
|
||||
virtual bool fastSelectInstruction(const Instruction *I) = 0;
|
||||
|
||||
/// This method is called by target-independent code to do target-
|
||||
/// specific argument lowering. It returns true if it was successful.
|
||||
virtual bool fastLowerArguments();
|
||||
|
||||
/// This method is called by target-independent code to do target-
|
||||
/// specific call lowering. It returns true if it was successful.
|
||||
virtual bool fastLowerCall(CallLoweringInfo &CLI);
|
||||
|
||||
/// This method is called by target-independent code to do target-
|
||||
/// specific intrinsic lowering. It returns true if it was successful.
|
||||
virtual bool fastLowerIntrinsicCall(const IntrinsicInst *II);
|
||||
|
||||
/// This method is called by target-independent code to request that an
|
||||
/// instruction with the given type and opcode be emitted.
|
||||
virtual unsigned fastEmit_(MVT VT, MVT RetVT, unsigned Opcode);
|
||||
|
||||
/// This method is called by target-independent code to request that an
|
||||
/// instruction with the given type, opcode, and register operand be emitted.
|
||||
virtual unsigned fastEmit_r(MVT VT, MVT RetVT, unsigned Opcode, unsigned Op0);
|
||||
|
||||
/// This method is called by target-independent code to request that an
|
||||
/// instruction with the given type, opcode, and register operands be emitted.
|
||||
virtual unsigned fastEmit_rr(MVT VT, MVT RetVT, unsigned Opcode, unsigned Op0,
|
||||
unsigned Op1);
|
||||
|
||||
/// This method is called by target-independent code to request that an
|
||||
/// instruction with the given type, opcode, and register and immediate
|
||||
/// operands be emitted.
|
||||
virtual unsigned fastEmit_ri(MVT VT, MVT RetVT, unsigned Opcode, unsigned Op0,
|
||||
uint64_t Imm);
|
||||
|
||||
/// This method is a wrapper of fastEmit_ri.
|
||||
///
|
||||
/// It first tries to emit an instruction with an immediate operand using
|
||||
/// fastEmit_ri. If that fails, it materializes the immediate into a register
|
||||
/// and try fastEmit_rr instead.
|
||||
Register fastEmit_ri_(MVT VT, unsigned Opcode, unsigned Op0, uint64_t Imm,
|
||||
MVT ImmType);
|
||||
|
||||
/// This method is called by target-independent code to request that an
|
||||
/// instruction with the given type, opcode, and immediate operand be emitted.
|
||||
virtual unsigned fastEmit_i(MVT VT, MVT RetVT, unsigned Opcode, uint64_t Imm);
|
||||
|
||||
/// This method is called by target-independent code to request that an
|
||||
/// instruction with the given type, opcode, and floating-point immediate
|
||||
/// operand be emitted.
|
||||
virtual unsigned fastEmit_f(MVT VT, MVT RetVT, unsigned Opcode,
|
||||
const ConstantFP *FPImm);
|
||||
|
||||
/// Emit a MachineInstr with no operands and a result register in the
|
||||
/// given register class.
|
||||
Register fastEmitInst_(unsigned MachineInstOpcode,
|
||||
const TargetRegisterClass *RC);
|
||||
|
||||
/// Emit a MachineInstr with one register operand and a result register
|
||||
/// in the given register class.
|
||||
Register fastEmitInst_r(unsigned MachineInstOpcode,
|
||||
const TargetRegisterClass *RC, unsigned Op0);
|
||||
|
||||
/// Emit a MachineInstr with two register operands and a result
|
||||
/// register in the given register class.
|
||||
Register fastEmitInst_rr(unsigned MachineInstOpcode,
|
||||
const TargetRegisterClass *RC, unsigned Op0,
|
||||
unsigned Op1);
|
||||
|
||||
/// Emit a MachineInstr with three register operands and a result
|
||||
/// register in the given register class.
|
||||
Register fastEmitInst_rrr(unsigned MachineInstOpcode,
|
||||
const TargetRegisterClass *RC, unsigned Op0,
|
||||
unsigned Op1, unsigned Op2);
|
||||
|
||||
/// Emit a MachineInstr with a register operand, an immediate, and a
|
||||
/// result register in the given register class.
|
||||
Register fastEmitInst_ri(unsigned MachineInstOpcode,
|
||||
const TargetRegisterClass *RC, unsigned Op0,
|
||||
uint64_t Imm);
|
||||
|
||||
/// Emit a MachineInstr with one register operand and two immediate
|
||||
/// operands.
|
||||
Register fastEmitInst_rii(unsigned MachineInstOpcode,
|
||||
const TargetRegisterClass *RC, unsigned Op0,
|
||||
uint64_t Imm1, uint64_t Imm2);
|
||||
|
||||
/// Emit a MachineInstr with a floating point immediate, and a result
|
||||
/// register in the given register class.
|
||||
Register fastEmitInst_f(unsigned MachineInstOpcode,
|
||||
const TargetRegisterClass *RC,
|
||||
const ConstantFP *FPImm);
|
||||
|
||||
/// Emit a MachineInstr with two register operands, an immediate, and a
|
||||
/// result register in the given register class.
|
||||
Register fastEmitInst_rri(unsigned MachineInstOpcode,
|
||||
const TargetRegisterClass *RC, unsigned Op0,
|
||||
unsigned Op1, uint64_t Imm);
|
||||
|
||||
/// Emit a MachineInstr with a single immediate operand, and a result
|
||||
/// register in the given register class.
|
||||
Register fastEmitInst_i(unsigned MachineInstOpcode,
|
||||
const TargetRegisterClass *RC, uint64_t Imm);
|
||||
|
||||
/// Emit a MachineInstr for an extract_subreg from a specified index of
|
||||
/// a superregister to a specified type.
|
||||
Register fastEmitInst_extractsubreg(MVT RetVT, unsigned Op0, uint32_t Idx);
|
||||
|
||||
/// Emit MachineInstrs to compute the value of Op with all but the
|
||||
/// least significant bit set to zero.
|
||||
Register fastEmitZExtFromI1(MVT VT, unsigned Op0);
|
||||
|
||||
/// Emit an unconditional branch to the given block, unless it is the
|
||||
/// immediate (fall-through) successor, and update the CFG.
|
||||
void fastEmitBranch(MachineBasicBlock *MSucc, const DebugLoc &DbgLoc);
|
||||
|
||||
/// Emit an unconditional branch to \p FalseMBB, obtains the branch weight
|
||||
/// and adds TrueMBB and FalseMBB to the successor list.
|
||||
void finishCondBranch(const BasicBlock *BranchBB, MachineBasicBlock *TrueMBB,
|
||||
MachineBasicBlock *FalseMBB);
|
||||
|
||||
/// Update the value map to include the new mapping for this
|
||||
/// instruction, or insert an extra copy to get the result in a previous
|
||||
/// determined register.
|
||||
///
|
||||
/// NOTE: This is only necessary because we might select a block that uses a
|
||||
/// value before we select the block that defines the value. It might be
|
||||
/// possible to fix this by selecting blocks in reverse postorder.
|
||||
void updateValueMap(const Value *I, Register Reg, unsigned NumRegs = 1);
|
||||
|
||||
Register createResultReg(const TargetRegisterClass *RC);
|
||||
|
||||
/// Try to constrain Op so that it is usable by argument OpNum of the
|
||||
/// provided MCInstrDesc. If this fails, create a new virtual register in the
|
||||
/// correct class and COPY the value there.
|
||||
Register constrainOperandRegClass(const MCInstrDesc &II, Register Op,
|
||||
unsigned OpNum);
|
||||
|
||||
/// Emit a constant in a register using target-specific logic, such as
|
||||
/// constant pool loads.
|
||||
virtual unsigned fastMaterializeConstant(const Constant *C) { return 0; }
|
||||
|
||||
/// Emit an alloca address in a register using target-specific logic.
|
||||
virtual unsigned fastMaterializeAlloca(const AllocaInst *C) { return 0; }
|
||||
|
||||
/// Emit the floating-point constant +0.0 in a register using target-
|
||||
/// specific logic.
|
||||
virtual unsigned fastMaterializeFloatZero(const ConstantFP *CF) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// Check if \c Add is an add that can be safely folded into \c GEP.
|
||||
///
|
||||
/// \c Add can be folded into \c GEP if:
|
||||
/// - \c Add is an add,
|
||||
/// - \c Add's size matches \c GEP's,
|
||||
/// - \c Add is in the same basic block as \c GEP, and
|
||||
/// - \c Add has a constant operand.
|
||||
bool canFoldAddIntoGEP(const User *GEP, const Value *Add);
|
||||
|
||||
/// Create a machine mem operand from the given instruction.
|
||||
MachineMemOperand *createMachineMemOperandFor(const Instruction *I) const;
|
||||
|
||||
CmpInst::Predicate optimizeCmpPredicate(const CmpInst *CI) const;
|
||||
|
||||
bool lowerCallTo(const CallInst *CI, MCSymbol *Symbol, unsigned NumArgs);
|
||||
bool lowerCallTo(const CallInst *CI, const char *SymName,
|
||||
unsigned NumArgs);
|
||||
bool lowerCallTo(CallLoweringInfo &CLI);
|
||||
|
||||
bool lowerCall(const CallInst *I);
|
||||
/// Select and emit code for a binary operator instruction, which has
|
||||
/// an opcode which directly corresponds to the given ISD opcode.
|
||||
bool selectBinaryOp(const User *I, unsigned ISDOpcode);
|
||||
bool selectFNeg(const User *I, const Value *In);
|
||||
bool selectGetElementPtr(const User *I);
|
||||
bool selectStackmap(const CallInst *I);
|
||||
bool selectPatchpoint(const CallInst *I);
|
||||
bool selectCall(const User *I);
|
||||
bool selectIntrinsicCall(const IntrinsicInst *II);
|
||||
bool selectBitCast(const User *I);
|
||||
bool selectFreeze(const User *I);
|
||||
bool selectCast(const User *I, unsigned Opcode);
|
||||
bool selectExtractValue(const User *U);
|
||||
bool selectXRayCustomEvent(const CallInst *II);
|
||||
bool selectXRayTypedEvent(const CallInst *II);
|
||||
|
||||
bool shouldOptForSize(const MachineFunction *MF) const {
|
||||
// TODO: Implement PGSO.
|
||||
return MF->getFunction().hasOptSize();
|
||||
}
|
||||
|
||||
private:
|
||||
/// Handle PHI nodes in successor blocks.
|
||||
///
|
||||
/// Emit code to ensure constants are copied into registers when needed.
|
||||
/// Remember the virtual registers that need to be added to the Machine PHI
|
||||
/// nodes as input. We cannot just directly add them, because expansion might
|
||||
/// result in multiple MBB's for one BB. As such, the start of the BB might
|
||||
/// correspond to a different MBB than the end.
|
||||
bool handlePHINodesInSuccessorBlocks(const BasicBlock *LLVMBB);
|
||||
|
||||
/// Helper for materializeRegForValue to materialize a constant in a
|
||||
/// target-independent way.
|
||||
Register materializeConstant(const Value *V, MVT VT);
|
||||
|
||||
/// Helper for getRegForVale. This function is called when the value
|
||||
/// isn't already available in a register and must be materialized with new
|
||||
/// instructions.
|
||||
Register materializeRegForValue(const Value *V, MVT VT);
|
||||
|
||||
/// Clears LocalValueMap and moves the area for the new local variables
|
||||
/// to the beginning of the block. It helps to avoid spilling cached variables
|
||||
/// across heavy instructions like calls.
|
||||
void flushLocalValueMap();
|
||||
|
||||
/// Removes dead local value instructions after SavedLastLocalvalue.
|
||||
void removeDeadLocalValueCode(MachineInstr *SavedLastLocalValue);
|
||||
|
||||
/// Insertion point before trying to select the current instruction.
|
||||
MachineBasicBlock::iterator SavedInsertPt;
|
||||
|
||||
/// Add a stackmap or patchpoint intrinsic call's live variable
|
||||
/// operands to a stackmap or patchpoint machine instruction.
|
||||
bool addStackMapLiveVars(SmallVectorImpl<MachineOperand> &Ops,
|
||||
const CallInst *CI, unsigned StartIdx);
|
||||
bool lowerCallOperands(const CallInst *CI, unsigned ArgIdx, unsigned NumArgs,
|
||||
const Value *Callee, bool ForceRetVoidTy,
|
||||
CallLoweringInfo &CLI);
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_FASTISEL_H
|
||||
77
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/FaultMaps.h
vendored
Normal file
77
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/FaultMaps.h
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
//===- FaultMaps.h - The "FaultMaps" section --------------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_FAULTMAPS_H
|
||||
#define LLVM_CODEGEN_FAULTMAPS_H
|
||||
|
||||
#include "llvm/MC/MCSymbol.h"
|
||||
#include "llvm/Support/Endian.h"
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class AsmPrinter;
|
||||
class MCExpr;
|
||||
|
||||
class FaultMaps {
|
||||
public:
|
||||
enum FaultKind {
|
||||
FaultingLoad = 1,
|
||||
FaultingLoadStore,
|
||||
FaultingStore,
|
||||
FaultKindMax
|
||||
};
|
||||
|
||||
explicit FaultMaps(AsmPrinter &AP);
|
||||
|
||||
static const char *faultTypeToString(FaultKind);
|
||||
|
||||
void recordFaultingOp(FaultKind FaultTy, const MCSymbol *FaultingLabel,
|
||||
const MCSymbol *HandlerLabel);
|
||||
void serializeToFaultMapSection();
|
||||
void reset() {
|
||||
FunctionInfos.clear();
|
||||
}
|
||||
|
||||
private:
|
||||
static const char *WFMP;
|
||||
|
||||
struct FaultInfo {
|
||||
FaultKind Kind = FaultKindMax;
|
||||
const MCExpr *FaultingOffsetExpr = nullptr;
|
||||
const MCExpr *HandlerOffsetExpr = nullptr;
|
||||
|
||||
FaultInfo() = default;
|
||||
|
||||
explicit FaultInfo(FaultMaps::FaultKind Kind, const MCExpr *FaultingOffset,
|
||||
const MCExpr *HandlerOffset)
|
||||
: Kind(Kind), FaultingOffsetExpr(FaultingOffset),
|
||||
HandlerOffsetExpr(HandlerOffset) {}
|
||||
};
|
||||
|
||||
using FunctionFaultInfos = std::vector<FaultInfo>;
|
||||
|
||||
// We'd like to keep a stable iteration order for FunctionInfos to help
|
||||
// FileCheck based testing.
|
||||
struct MCSymbolComparator {
|
||||
bool operator()(const MCSymbol *LHS, const MCSymbol *RHS) const {
|
||||
return LHS->getName() < RHS->getName();
|
||||
}
|
||||
};
|
||||
|
||||
std::map<const MCSymbol *, FunctionFaultInfos, MCSymbolComparator>
|
||||
FunctionInfos;
|
||||
AsmPrinter &AP;
|
||||
|
||||
void emitFunctionInfo(const MCSymbol *FnLabel, const FunctionFaultInfos &FFI);
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_FAULTMAPS_H
|
||||
285
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/FunctionLoweringInfo.h
vendored
Normal file
285
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/FunctionLoweringInfo.h
vendored
Normal file
@@ -0,0 +1,285 @@
|
||||
//===- FunctionLoweringInfo.h - Lower functions from LLVM IR ---*- 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 routines for translating functions from LLVM IR into
|
||||
// Machine IR.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_FUNCTIONLOWERINGINFO_H
|
||||
#define LLVM_CODEGEN_FUNCTIONLOWERINGINFO_H
|
||||
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/IndexedMap.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/CodeGen/ISDOpcodes.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/TargetRegisterInfo.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/IR/Type.h"
|
||||
#include "llvm/IR/Value.h"
|
||||
#include "llvm/Support/KnownBits.h"
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Argument;
|
||||
class BasicBlock;
|
||||
class BranchProbabilityInfo;
|
||||
class LegacyDivergenceAnalysis;
|
||||
class Function;
|
||||
class Instruction;
|
||||
class MachineFunction;
|
||||
class MachineInstr;
|
||||
class MachineRegisterInfo;
|
||||
class MVT;
|
||||
class SelectionDAG;
|
||||
class TargetLowering;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// FunctionLoweringInfo - This contains information that is global to a
|
||||
/// function that is used when lowering a region of the function.
|
||||
///
|
||||
class FunctionLoweringInfo {
|
||||
public:
|
||||
const Function *Fn;
|
||||
MachineFunction *MF;
|
||||
const TargetLowering *TLI;
|
||||
MachineRegisterInfo *RegInfo;
|
||||
BranchProbabilityInfo *BPI;
|
||||
const LegacyDivergenceAnalysis *DA;
|
||||
/// CanLowerReturn - true iff the function's return value can be lowered to
|
||||
/// registers.
|
||||
bool CanLowerReturn;
|
||||
|
||||
/// True if part of the CSRs will be handled via explicit copies.
|
||||
bool SplitCSR;
|
||||
|
||||
/// DemoteRegister - if CanLowerReturn is false, DemoteRegister is a vreg
|
||||
/// allocated to hold a pointer to the hidden sret parameter.
|
||||
Register DemoteRegister;
|
||||
|
||||
/// MBBMap - A mapping from LLVM basic blocks to their machine code entry.
|
||||
DenseMap<const BasicBlock*, MachineBasicBlock *> MBBMap;
|
||||
|
||||
/// ValueMap - Since we emit code for the function a basic block at a time,
|
||||
/// we must remember which virtual registers hold the values for
|
||||
/// cross-basic-block values.
|
||||
DenseMap<const Value *, Register> ValueMap;
|
||||
|
||||
/// VirtReg2Value map is needed by the Divergence Analysis driven
|
||||
/// instruction selection. It is reverted ValueMap. It is computed
|
||||
/// in lazy style - on demand. It is used to get the Value corresponding
|
||||
/// to the live in virtual register and is called from the
|
||||
/// TargetLowerinInfo::isSDNodeSourceOfDivergence.
|
||||
DenseMap<Register, const Value*> VirtReg2Value;
|
||||
|
||||
/// This method is called from TargetLowerinInfo::isSDNodeSourceOfDivergence
|
||||
/// to get the Value corresponding to the live-in virtual register.
|
||||
const Value *getValueFromVirtualReg(Register Vreg);
|
||||
|
||||
/// Track virtual registers created for exception pointers.
|
||||
DenseMap<const Value *, Register> CatchPadExceptionPointers;
|
||||
|
||||
/// Helper object to track which of three possible relocation mechanisms are
|
||||
/// used for a particular value being relocated over a statepoint.
|
||||
struct StatepointRelocationRecord {
|
||||
enum RelocType {
|
||||
// Value did not need to be relocated and can be used directly.
|
||||
NoRelocate,
|
||||
// Value was spilled to stack and needs filled at the gc.relocate.
|
||||
Spill,
|
||||
// Value was lowered to tied def and gc.relocate should be replaced with
|
||||
// copy from vreg.
|
||||
VReg,
|
||||
} type = NoRelocate;
|
||||
// Payload contains either frame index of the stack slot in which the value
|
||||
// was spilled, or virtual register which contains the re-definition.
|
||||
union payload_t {
|
||||
payload_t() : FI(-1) {}
|
||||
int FI;
|
||||
Register Reg;
|
||||
} payload;
|
||||
};
|
||||
|
||||
/// Keep track of each value which was relocated and the strategy used to
|
||||
/// relocate that value. This information is required when visiting
|
||||
/// gc.relocates which may appear in following blocks.
|
||||
using StatepointSpillMapTy =
|
||||
DenseMap<const Value *, StatepointRelocationRecord>;
|
||||
DenseMap<const Instruction *, StatepointSpillMapTy> StatepointRelocationMaps;
|
||||
|
||||
/// StaticAllocaMap - Keep track of frame indices for fixed sized allocas in
|
||||
/// the entry block. This allows the allocas to be efficiently referenced
|
||||
/// anywhere in the function.
|
||||
DenseMap<const AllocaInst*, int> StaticAllocaMap;
|
||||
|
||||
/// ByValArgFrameIndexMap - Keep track of frame indices for byval arguments.
|
||||
DenseMap<const Argument*, int> ByValArgFrameIndexMap;
|
||||
|
||||
/// ArgDbgValues - A list of DBG_VALUE instructions created during isel for
|
||||
/// function arguments that are inserted after scheduling is completed.
|
||||
SmallVector<MachineInstr*, 8> ArgDbgValues;
|
||||
|
||||
/// Bitvector with a bit set if corresponding argument is described in
|
||||
/// ArgDbgValues. Using arg numbers according to Argument numbering.
|
||||
BitVector DescribedArgs;
|
||||
|
||||
/// RegFixups - Registers which need to be replaced after isel is done.
|
||||
DenseMap<Register, Register> RegFixups;
|
||||
|
||||
DenseSet<Register> RegsWithFixups;
|
||||
|
||||
/// StatepointStackSlots - A list of temporary stack slots (frame indices)
|
||||
/// used to spill values at a statepoint. We store them here to enable
|
||||
/// reuse of the same stack slots across different statepoints in different
|
||||
/// basic blocks.
|
||||
SmallVector<unsigned, 50> StatepointStackSlots;
|
||||
|
||||
/// MBB - The current block.
|
||||
MachineBasicBlock *MBB;
|
||||
|
||||
/// MBB - The current insert position inside the current block.
|
||||
MachineBasicBlock::iterator InsertPt;
|
||||
|
||||
struct LiveOutInfo {
|
||||
unsigned NumSignBits : 31;
|
||||
unsigned IsValid : 1;
|
||||
KnownBits Known = 1;
|
||||
|
||||
LiveOutInfo() : NumSignBits(0), IsValid(true) {}
|
||||
};
|
||||
|
||||
/// Record the preferred extend type (ISD::SIGN_EXTEND or ISD::ZERO_EXTEND)
|
||||
/// for a value.
|
||||
DenseMap<const Value *, ISD::NodeType> PreferredExtendType;
|
||||
|
||||
/// VisitedBBs - The set of basic blocks visited thus far by instruction
|
||||
/// selection.
|
||||
SmallPtrSet<const BasicBlock*, 4> VisitedBBs;
|
||||
|
||||
/// PHINodesToUpdate - A list of phi instructions whose operand list will
|
||||
/// be updated after processing the current basic block.
|
||||
/// TODO: This isn't per-function state, it's per-basic-block state. But
|
||||
/// there's no other convenient place for it to live right now.
|
||||
std::vector<std::pair<MachineInstr*, unsigned> > PHINodesToUpdate;
|
||||
unsigned OrigNumPHINodesToUpdate;
|
||||
|
||||
/// If the current MBB is a landing pad, the exception pointer and exception
|
||||
/// selector registers are copied into these virtual registers by
|
||||
/// SelectionDAGISel::PrepareEHLandingPad().
|
||||
unsigned ExceptionPointerVirtReg, ExceptionSelectorVirtReg;
|
||||
|
||||
/// set - Initialize this FunctionLoweringInfo with the given Function
|
||||
/// and its associated MachineFunction.
|
||||
///
|
||||
void set(const Function &Fn, MachineFunction &MF, SelectionDAG *DAG);
|
||||
|
||||
/// clear - Clear out all the function-specific state. This returns this
|
||||
/// FunctionLoweringInfo to an empty state, ready to be used for a
|
||||
/// different function.
|
||||
void clear();
|
||||
|
||||
/// isExportedInst - Return true if the specified value is an instruction
|
||||
/// exported from its block.
|
||||
bool isExportedInst(const Value *V) const {
|
||||
return ValueMap.count(V);
|
||||
}
|
||||
|
||||
Register CreateReg(MVT VT, bool isDivergent = false);
|
||||
|
||||
Register CreateRegs(const Value *V);
|
||||
|
||||
Register CreateRegs(Type *Ty, bool isDivergent = false);
|
||||
|
||||
Register InitializeRegForValue(const Value *V) {
|
||||
// Tokens never live in vregs.
|
||||
if (V->getType()->isTokenTy())
|
||||
return 0;
|
||||
Register &R = ValueMap[V];
|
||||
assert(R == 0 && "Already initialized this value register!");
|
||||
assert(VirtReg2Value.empty());
|
||||
return R = CreateRegs(V);
|
||||
}
|
||||
|
||||
/// GetLiveOutRegInfo - Gets LiveOutInfo for a register, returning NULL if the
|
||||
/// register is a PHI destination and the PHI's LiveOutInfo is not valid.
|
||||
const LiveOutInfo *GetLiveOutRegInfo(Register Reg) {
|
||||
if (!LiveOutRegInfo.inBounds(Reg))
|
||||
return nullptr;
|
||||
|
||||
const LiveOutInfo *LOI = &LiveOutRegInfo[Reg];
|
||||
if (!LOI->IsValid)
|
||||
return nullptr;
|
||||
|
||||
return LOI;
|
||||
}
|
||||
|
||||
/// GetLiveOutRegInfo - Gets LiveOutInfo for a register, returning NULL if the
|
||||
/// register is a PHI destination and the PHI's LiveOutInfo is not valid. If
|
||||
/// the register's LiveOutInfo is for a smaller bit width, it is extended to
|
||||
/// the larger bit width by zero extension. The bit width must be no smaller
|
||||
/// than the LiveOutInfo's existing bit width.
|
||||
const LiveOutInfo *GetLiveOutRegInfo(Register Reg, unsigned BitWidth);
|
||||
|
||||
/// AddLiveOutRegInfo - Adds LiveOutInfo for a register.
|
||||
void AddLiveOutRegInfo(Register Reg, unsigned NumSignBits,
|
||||
const KnownBits &Known) {
|
||||
// Only install this information if it tells us something.
|
||||
if (NumSignBits == 1 && Known.isUnknown())
|
||||
return;
|
||||
|
||||
LiveOutRegInfo.grow(Reg);
|
||||
LiveOutInfo &LOI = LiveOutRegInfo[Reg];
|
||||
LOI.NumSignBits = NumSignBits;
|
||||
LOI.Known.One = Known.One;
|
||||
LOI.Known.Zero = Known.Zero;
|
||||
}
|
||||
|
||||
/// ComputePHILiveOutRegInfo - Compute LiveOutInfo for a PHI's destination
|
||||
/// register based on the LiveOutInfo of its operands.
|
||||
void ComputePHILiveOutRegInfo(const PHINode*);
|
||||
|
||||
/// InvalidatePHILiveOutRegInfo - Invalidates a PHI's LiveOutInfo, to be
|
||||
/// called when a block is visited before all of its predecessors.
|
||||
void InvalidatePHILiveOutRegInfo(const PHINode *PN) {
|
||||
// PHIs with no uses have no ValueMap entry.
|
||||
DenseMap<const Value*, Register>::const_iterator It = ValueMap.find(PN);
|
||||
if (It == ValueMap.end())
|
||||
return;
|
||||
|
||||
Register Reg = It->second;
|
||||
if (Reg == 0)
|
||||
return;
|
||||
|
||||
LiveOutRegInfo.grow(Reg);
|
||||
LiveOutRegInfo[Reg].IsValid = false;
|
||||
}
|
||||
|
||||
/// setArgumentFrameIndex - Record frame index for the byval
|
||||
/// argument.
|
||||
void setArgumentFrameIndex(const Argument *A, int FI);
|
||||
|
||||
/// getArgumentFrameIndex - Get frame index for the byval argument.
|
||||
int getArgumentFrameIndex(const Argument *A);
|
||||
|
||||
Register getCatchPadExceptionPointerVReg(const Value *CPI,
|
||||
const TargetRegisterClass *RC);
|
||||
|
||||
private:
|
||||
/// LiveOutRegInfo - Information about live out vregs.
|
||||
IndexedMap<LiveOutInfo, VirtReg2IndexFunctor> LiveOutRegInfo;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_FUNCTIONLOWERINGINFO_H
|
||||
205
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GCMetadata.h
vendored
Normal file
205
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GCMetadata.h
vendored
Normal file
@@ -0,0 +1,205 @@
|
||||
//===- GCMetadata.h - Garbage collector metadata ----------------*- 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 file declares the GCFunctionInfo and GCModuleInfo classes, which are
|
||||
// used as a communication channel from the target code generator to the target
|
||||
// garbage collectors. This interface allows code generators and garbage
|
||||
// collectors to be developed independently.
|
||||
//
|
||||
// The GCFunctionInfo class logs the data necessary to build a type accurate
|
||||
// stack map. The code generator outputs:
|
||||
//
|
||||
// - Safe points as specified by the GCStrategy's NeededSafePoints.
|
||||
// - Stack offsets for GC roots, as specified by calls to llvm.gcroot
|
||||
//
|
||||
// As a refinement, liveness analysis calculates the set of live roots at each
|
||||
// safe point. Liveness analysis is not presently performed by the code
|
||||
// generator, so all roots are assumed live.
|
||||
//
|
||||
// GCModuleInfo simply collects GCFunctionInfo instances for each Function as
|
||||
// they are compiled. This accretion is necessary for collectors which must emit
|
||||
// a stack map for the compilation unit as a whole. Therefore, GCFunctionInfo
|
||||
// outlives the MachineFunction from which it is derived and must not refer to
|
||||
// any code generator data structures.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_GCMETADATA_H
|
||||
#define LLVM_CODEGEN_GCMETADATA_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/IR/DebugLoc.h"
|
||||
#include "llvm/IR/GCStrategy.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Constant;
|
||||
class Function;
|
||||
class MCSymbol;
|
||||
|
||||
/// GCPoint - Metadata for a collector-safe point in machine code.
|
||||
///
|
||||
struct GCPoint {
|
||||
MCSymbol *Label; ///< A label.
|
||||
DebugLoc Loc;
|
||||
|
||||
GCPoint(MCSymbol *L, DebugLoc DL)
|
||||
: Label(L), Loc(std::move(DL)) {}
|
||||
};
|
||||
|
||||
/// GCRoot - Metadata for a pointer to an object managed by the garbage
|
||||
/// collector.
|
||||
struct GCRoot {
|
||||
int Num; ///< Usually a frame index.
|
||||
int StackOffset = -1; ///< Offset from the stack pointer.
|
||||
const Constant *Metadata; ///< Metadata straight from the call
|
||||
///< to llvm.gcroot.
|
||||
|
||||
GCRoot(int N, const Constant *MD) : Num(N), Metadata(MD) {}
|
||||
};
|
||||
|
||||
/// Garbage collection metadata for a single function. Currently, this
|
||||
/// information only applies to GCStrategies which use GCRoot.
|
||||
class GCFunctionInfo {
|
||||
public:
|
||||
using iterator = std::vector<GCPoint>::iterator;
|
||||
using roots_iterator = std::vector<GCRoot>::iterator;
|
||||
using live_iterator = std::vector<GCRoot>::const_iterator;
|
||||
|
||||
private:
|
||||
const Function &F;
|
||||
GCStrategy &S;
|
||||
uint64_t FrameSize;
|
||||
std::vector<GCRoot> Roots;
|
||||
std::vector<GCPoint> SafePoints;
|
||||
|
||||
// FIXME: Liveness. A 2D BitVector, perhaps?
|
||||
//
|
||||
// BitVector Liveness;
|
||||
//
|
||||
// bool islive(int point, int root) =
|
||||
// Liveness[point * SafePoints.size() + root]
|
||||
//
|
||||
// The bit vector is the more compact representation where >3.2% of roots
|
||||
// are live per safe point (1.5% on 64-bit hosts).
|
||||
|
||||
public:
|
||||
GCFunctionInfo(const Function &F, GCStrategy &S);
|
||||
~GCFunctionInfo();
|
||||
|
||||
/// getFunction - Return the function to which this metadata applies.
|
||||
const Function &getFunction() const { return F; }
|
||||
|
||||
/// getStrategy - Return the GC strategy for the function.
|
||||
GCStrategy &getStrategy() { return S; }
|
||||
|
||||
/// addStackRoot - Registers a root that lives on the stack. Num is the
|
||||
/// stack object ID for the alloca (if the code generator is
|
||||
// using MachineFrameInfo).
|
||||
void addStackRoot(int Num, const Constant *Metadata) {
|
||||
Roots.push_back(GCRoot(Num, Metadata));
|
||||
}
|
||||
|
||||
/// removeStackRoot - Removes a root.
|
||||
roots_iterator removeStackRoot(roots_iterator position) {
|
||||
return Roots.erase(position);
|
||||
}
|
||||
|
||||
/// addSafePoint - Notes the existence of a safe point. Num is the ID of the
|
||||
/// label just prior to the safe point (if the code generator is using
|
||||
/// MachineModuleInfo).
|
||||
void addSafePoint(MCSymbol *Label, const DebugLoc &DL) {
|
||||
SafePoints.emplace_back(Label, DL);
|
||||
}
|
||||
|
||||
/// getFrameSize/setFrameSize - Records the function's frame size.
|
||||
uint64_t getFrameSize() const { return FrameSize; }
|
||||
void setFrameSize(uint64_t S) { FrameSize = S; }
|
||||
|
||||
/// begin/end - Iterators for safe points.
|
||||
iterator begin() { return SafePoints.begin(); }
|
||||
iterator end() { return SafePoints.end(); }
|
||||
size_t size() const { return SafePoints.size(); }
|
||||
|
||||
/// roots_begin/roots_end - Iterators for all roots in the function.
|
||||
roots_iterator roots_begin() { return Roots.begin(); }
|
||||
roots_iterator roots_end() { return Roots.end(); }
|
||||
size_t roots_size() const { return Roots.size(); }
|
||||
|
||||
/// live_begin/live_end - Iterators for live roots at a given safe point.
|
||||
live_iterator live_begin(const iterator &p) { return roots_begin(); }
|
||||
live_iterator live_end(const iterator &p) { return roots_end(); }
|
||||
size_t live_size(const iterator &p) const { return roots_size(); }
|
||||
};
|
||||
|
||||
/// An analysis pass which caches information about the entire Module.
|
||||
/// Records both the function level information used by GCRoots and a
|
||||
/// cache of the 'active' gc strategy objects for the current Module.
|
||||
class GCModuleInfo : public ImmutablePass {
|
||||
/// An owning list of all GCStrategies which have been created
|
||||
SmallVector<std::unique_ptr<GCStrategy>, 1> GCStrategyList;
|
||||
/// A helper map to speedup lookups into the above list
|
||||
StringMap<GCStrategy*> GCStrategyMap;
|
||||
|
||||
public:
|
||||
/// Lookup the GCStrategy object associated with the given gc name.
|
||||
/// Objects are owned internally; No caller should attempt to delete the
|
||||
/// returned objects.
|
||||
GCStrategy *getGCStrategy(const StringRef Name);
|
||||
|
||||
/// List of per function info objects. In theory, Each of these
|
||||
/// may be associated with a different GC.
|
||||
using FuncInfoVec = std::vector<std::unique_ptr<GCFunctionInfo>>;
|
||||
|
||||
FuncInfoVec::iterator funcinfo_begin() { return Functions.begin(); }
|
||||
FuncInfoVec::iterator funcinfo_end() { return Functions.end(); }
|
||||
|
||||
private:
|
||||
/// Owning list of all GCFunctionInfos associated with this Module
|
||||
FuncInfoVec Functions;
|
||||
|
||||
/// Non-owning map to bypass linear search when finding the GCFunctionInfo
|
||||
/// associated with a particular Function.
|
||||
using finfo_map_type = DenseMap<const Function *, GCFunctionInfo *>;
|
||||
finfo_map_type FInfoMap;
|
||||
|
||||
public:
|
||||
using iterator = SmallVector<std::unique_ptr<GCStrategy>, 1>::const_iterator;
|
||||
|
||||
static char ID;
|
||||
|
||||
GCModuleInfo();
|
||||
|
||||
/// clear - Resets the pass. Any pass, which uses GCModuleInfo, should
|
||||
/// call it in doFinalization().
|
||||
///
|
||||
void clear();
|
||||
|
||||
/// begin/end - Iterators for used strategies.
|
||||
///
|
||||
iterator begin() const { return GCStrategyList.begin(); }
|
||||
iterator end() const { return GCStrategyList.end(); }
|
||||
|
||||
/// get - Look up function metadata. This is currently assumed
|
||||
/// have the side effect of initializing the associated GCStrategy. That
|
||||
/// will soon change.
|
||||
GCFunctionInfo &getFunctionInfo(const Function &F);
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_GCMETADATA_H
|
||||
72
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GCMetadataPrinter.h
vendored
Normal file
72
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GCMetadataPrinter.h
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
//===- llvm/CodeGen/GCMetadataPrinter.h - Prints asm GC tables --*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The abstract base class GCMetadataPrinter supports writing GC metadata tables
|
||||
// as assembly code. This is a separate class from GCStrategy in order to allow
|
||||
// users of the LLVM JIT to avoid linking with the AsmWriter.
|
||||
//
|
||||
// Subclasses of GCMetadataPrinter must be registered using the
|
||||
// GCMetadataPrinterRegistry. This is separate from the GCStrategy itself
|
||||
// because these subclasses are logically plugins for the AsmWriter.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_GCMETADATAPRINTER_H
|
||||
#define LLVM_CODEGEN_GCMETADATAPRINTER_H
|
||||
|
||||
#include "llvm/Support/Registry.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class AsmPrinter;
|
||||
class GCMetadataPrinter;
|
||||
class GCModuleInfo;
|
||||
class GCStrategy;
|
||||
class Module;
|
||||
class StackMaps;
|
||||
|
||||
/// GCMetadataPrinterRegistry - The GC assembly printer registry uses all the
|
||||
/// defaults from Registry.
|
||||
using GCMetadataPrinterRegistry = Registry<GCMetadataPrinter>;
|
||||
|
||||
/// GCMetadataPrinter - Emits GC metadata as assembly code. Instances are
|
||||
/// created, managed, and owned by the AsmPrinter.
|
||||
class GCMetadataPrinter {
|
||||
private:
|
||||
friend class AsmPrinter;
|
||||
|
||||
GCStrategy *S;
|
||||
|
||||
protected:
|
||||
// May only be subclassed.
|
||||
GCMetadataPrinter();
|
||||
|
||||
public:
|
||||
GCMetadataPrinter(const GCMetadataPrinter &) = delete;
|
||||
GCMetadataPrinter &operator=(const GCMetadataPrinter &) = delete;
|
||||
virtual ~GCMetadataPrinter();
|
||||
|
||||
GCStrategy &getStrategy() { return *S; }
|
||||
|
||||
/// Called before the assembly for the module is generated by
|
||||
/// the AsmPrinter (but after target specific hooks.)
|
||||
virtual void beginAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) {}
|
||||
|
||||
/// Called after the assembly for the module is generated by
|
||||
/// the AsmPrinter (but before target specific hooks)
|
||||
virtual void finishAssembly(Module &M, GCModuleInfo &Info, AsmPrinter &AP) {}
|
||||
|
||||
/// Called when the stack maps are generated. Return true if
|
||||
/// stack maps with a custom format are generated. Otherwise
|
||||
/// returns false and the default format will be used.
|
||||
virtual bool emitStackMaps(StackMaps &SM, AsmPrinter &AP) { return false; }
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_GCMETADATAPRINTER_H
|
||||
242
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/CSEInfo.h
vendored
Normal file
242
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/CSEInfo.h
vendored
Normal file
@@ -0,0 +1,242 @@
|
||||
//===- llvm/CodeGen/GlobalISel/CSEInfo.h ------------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// Provides analysis for continuously CSEing during GISel passes.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_CSEINFO_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_CSEINFO_H
|
||||
|
||||
#include "llvm/ADT/FoldingSet.h"
|
||||
#include "llvm/CodeGen/CSEConfigBase.h"
|
||||
#include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
|
||||
#include "llvm/CodeGen/GlobalISel/GISelWorkList.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/CodeGen.h"
|
||||
|
||||
namespace llvm {
|
||||
class MachineBasicBlock;
|
||||
|
||||
/// A class that wraps MachineInstrs and derives from FoldingSetNode in order to
|
||||
/// be uniqued in a CSEMap. The tradeoff here is extra memory allocations for
|
||||
/// UniqueMachineInstr vs making MachineInstr bigger.
|
||||
class UniqueMachineInstr : public FoldingSetNode {
|
||||
friend class GISelCSEInfo;
|
||||
const MachineInstr *MI;
|
||||
explicit UniqueMachineInstr(const MachineInstr *MI) : MI(MI) {}
|
||||
|
||||
public:
|
||||
void Profile(FoldingSetNodeID &ID);
|
||||
};
|
||||
|
||||
// A CSE config for fully optimized builds.
|
||||
class CSEConfigFull : public CSEConfigBase {
|
||||
public:
|
||||
virtual ~CSEConfigFull() = default;
|
||||
virtual bool shouldCSEOpc(unsigned Opc) override;
|
||||
};
|
||||
|
||||
// Commonly used for O0 config.
|
||||
class CSEConfigConstantOnly : public CSEConfigBase {
|
||||
public:
|
||||
virtual ~CSEConfigConstantOnly() = default;
|
||||
virtual bool shouldCSEOpc(unsigned Opc) override;
|
||||
};
|
||||
|
||||
// Returns the standard expected CSEConfig for the given optimization level.
|
||||
// We have this logic here so targets can make use of it from their derived
|
||||
// TargetPassConfig, but can't put this logic into TargetPassConfig directly
|
||||
// because the CodeGen library can't depend on GlobalISel.
|
||||
std::unique_ptr<CSEConfigBase>
|
||||
getStandardCSEConfigForOpt(CodeGenOpt::Level Level);
|
||||
|
||||
/// The CSE Analysis object.
|
||||
/// This installs itself as a delegate to the MachineFunction to track
|
||||
/// new instructions as well as deletions. It however will not be able to
|
||||
/// track instruction mutations. In such cases, recordNewInstruction should be
|
||||
/// called (for eg inside MachineIRBuilder::recordInsertion).
|
||||
/// Also because of how just the instruction can be inserted without adding any
|
||||
/// operands to the instruction, instructions are uniqued and inserted lazily.
|
||||
/// CSEInfo should assert when trying to enter an incomplete instruction into
|
||||
/// the CSEMap. There is Opcode level granularity on which instructions can be
|
||||
/// CSE'd and for now, only Generic instructions are CSEable.
|
||||
class GISelCSEInfo : public GISelChangeObserver {
|
||||
// Make it accessible only to CSEMIRBuilder.
|
||||
friend class CSEMIRBuilder;
|
||||
|
||||
BumpPtrAllocator UniqueInstrAllocator;
|
||||
FoldingSet<UniqueMachineInstr> CSEMap;
|
||||
MachineRegisterInfo *MRI = nullptr;
|
||||
MachineFunction *MF = nullptr;
|
||||
std::unique_ptr<CSEConfigBase> CSEOpt;
|
||||
/// Keep a cache of UniqueInstrs for each MachineInstr. In GISel,
|
||||
/// often instructions are mutated (while their ID has completely changed).
|
||||
/// Whenever mutation happens, invalidate the UniqueMachineInstr for the
|
||||
/// MachineInstr
|
||||
DenseMap<const MachineInstr *, UniqueMachineInstr *> InstrMapping;
|
||||
|
||||
/// Store instructions that are not fully formed in TemporaryInsts.
|
||||
/// Also because CSE insertion happens lazily, we can remove insts from this
|
||||
/// list and avoid inserting and then removing from the CSEMap.
|
||||
GISelWorkList<8> TemporaryInsts;
|
||||
|
||||
// Only used in asserts.
|
||||
DenseMap<unsigned, unsigned> OpcodeHitTable;
|
||||
|
||||
bool isUniqueMachineInstValid(const UniqueMachineInstr &UMI) const;
|
||||
|
||||
void invalidateUniqueMachineInstr(UniqueMachineInstr *UMI);
|
||||
|
||||
UniqueMachineInstr *getNodeIfExists(FoldingSetNodeID &ID,
|
||||
MachineBasicBlock *MBB, void *&InsertPos);
|
||||
|
||||
/// Allocate and construct a new UniqueMachineInstr for MI and return.
|
||||
UniqueMachineInstr *getUniqueInstrForMI(const MachineInstr *MI);
|
||||
|
||||
void insertNode(UniqueMachineInstr *UMI, void *InsertPos = nullptr);
|
||||
|
||||
/// Get the MachineInstr(Unique) if it exists already in the CSEMap and the
|
||||
/// same MachineBasicBlock.
|
||||
MachineInstr *getMachineInstrIfExists(FoldingSetNodeID &ID,
|
||||
MachineBasicBlock *MBB,
|
||||
void *&InsertPos);
|
||||
|
||||
/// Use this method to allocate a new UniqueMachineInstr for MI and insert it
|
||||
/// into the CSEMap. MI should return true for shouldCSE(MI->getOpcode())
|
||||
void insertInstr(MachineInstr *MI, void *InsertPos = nullptr);
|
||||
|
||||
public:
|
||||
GISelCSEInfo() = default;
|
||||
|
||||
virtual ~GISelCSEInfo();
|
||||
|
||||
void setMF(MachineFunction &MF);
|
||||
|
||||
Error verify();
|
||||
|
||||
/// Records a newly created inst in a list and lazily insert it to the CSEMap.
|
||||
/// Sometimes, this method might be called with a partially constructed
|
||||
/// MachineInstr,
|
||||
// (right after BuildMI without adding any operands) - and in such cases,
|
||||
// defer the hashing of the instruction to a later stage.
|
||||
void recordNewInstruction(MachineInstr *MI);
|
||||
|
||||
/// Use this callback to inform CSE about a newly fully created instruction.
|
||||
void handleRecordedInst(MachineInstr *MI);
|
||||
|
||||
/// Use this callback to insert all the recorded instructions. At this point,
|
||||
/// all of these insts need to be fully constructed and should not be missing
|
||||
/// any operands.
|
||||
void handleRecordedInsts();
|
||||
|
||||
/// Remove this inst from the CSE map. If this inst has not been inserted yet,
|
||||
/// it will be removed from the Tempinsts list if it exists.
|
||||
void handleRemoveInst(MachineInstr *MI);
|
||||
|
||||
void releaseMemory();
|
||||
|
||||
void setCSEConfig(std::unique_ptr<CSEConfigBase> Opt) {
|
||||
CSEOpt = std::move(Opt);
|
||||
}
|
||||
|
||||
bool shouldCSE(unsigned Opc) const;
|
||||
|
||||
void analyze(MachineFunction &MF);
|
||||
|
||||
void countOpcodeHit(unsigned Opc);
|
||||
|
||||
void print();
|
||||
|
||||
// Observer API
|
||||
void erasingInstr(MachineInstr &MI) override;
|
||||
void createdInstr(MachineInstr &MI) override;
|
||||
void changingInstr(MachineInstr &MI) override;
|
||||
void changedInstr(MachineInstr &MI) override;
|
||||
};
|
||||
|
||||
class TargetRegisterClass;
|
||||
class RegisterBank;
|
||||
|
||||
// Simple builder class to easily profile properties about MIs.
|
||||
class GISelInstProfileBuilder {
|
||||
FoldingSetNodeID &ID;
|
||||
const MachineRegisterInfo &MRI;
|
||||
|
||||
public:
|
||||
GISelInstProfileBuilder(FoldingSetNodeID &ID, const MachineRegisterInfo &MRI)
|
||||
: ID(ID), MRI(MRI) {}
|
||||
// Profiling methods.
|
||||
const GISelInstProfileBuilder &addNodeIDOpcode(unsigned Opc) const;
|
||||
const GISelInstProfileBuilder &addNodeIDRegType(const LLT Ty) const;
|
||||
const GISelInstProfileBuilder &addNodeIDRegType(const Register) const;
|
||||
|
||||
const GISelInstProfileBuilder &
|
||||
addNodeIDRegType(const TargetRegisterClass *RC) const;
|
||||
const GISelInstProfileBuilder &addNodeIDRegType(const RegisterBank *RB) const;
|
||||
|
||||
const GISelInstProfileBuilder &addNodeIDRegNum(Register Reg) const;
|
||||
|
||||
const GISelInstProfileBuilder &addNodeIDReg(Register Reg) const;
|
||||
|
||||
const GISelInstProfileBuilder &addNodeIDImmediate(int64_t Imm) const;
|
||||
const GISelInstProfileBuilder &
|
||||
addNodeIDMBB(const MachineBasicBlock *MBB) const;
|
||||
|
||||
const GISelInstProfileBuilder &
|
||||
addNodeIDMachineOperand(const MachineOperand &MO) const;
|
||||
|
||||
const GISelInstProfileBuilder &addNodeIDFlag(unsigned Flag) const;
|
||||
const GISelInstProfileBuilder &addNodeID(const MachineInstr *MI) const;
|
||||
};
|
||||
|
||||
/// Simple wrapper that does the following.
|
||||
/// 1) Lazily evaluate the MachineFunction to compute CSEable instructions.
|
||||
/// 2) Allows configuration of which instructions are CSEd through CSEConfig
|
||||
/// object. Provides a method called get which takes a CSEConfig object.
|
||||
class GISelCSEAnalysisWrapper {
|
||||
GISelCSEInfo Info;
|
||||
MachineFunction *MF = nullptr;
|
||||
bool AlreadyComputed = false;
|
||||
|
||||
public:
|
||||
/// Takes a CSEConfigBase object that defines what opcodes get CSEd.
|
||||
/// If CSEConfig is already set, and the CSE Analysis has been preserved,
|
||||
/// it will not use the new CSEOpt(use Recompute to force using the new
|
||||
/// CSEOpt).
|
||||
GISelCSEInfo &get(std::unique_ptr<CSEConfigBase> CSEOpt,
|
||||
bool ReCompute = false);
|
||||
void setMF(MachineFunction &MFunc) { MF = &MFunc; }
|
||||
void setComputed(bool Computed) { AlreadyComputed = Computed; }
|
||||
void releaseMemory() { Info.releaseMemory(); }
|
||||
};
|
||||
|
||||
/// The actual analysis pass wrapper.
|
||||
class GISelCSEAnalysisWrapperPass : public MachineFunctionPass {
|
||||
GISelCSEAnalysisWrapper Wrapper;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
GISelCSEAnalysisWrapperPass();
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
const GISelCSEAnalysisWrapper &getCSEWrapper() const { return Wrapper; }
|
||||
GISelCSEAnalysisWrapper &getCSEWrapper() { return Wrapper; }
|
||||
|
||||
bool runOnMachineFunction(MachineFunction &MF) override;
|
||||
|
||||
void releaseMemory() override {
|
||||
Wrapper.releaseMemory();
|
||||
Wrapper.setComputed(false);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
109
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/CSEMIRBuilder.h
vendored
Normal file
109
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/CSEMIRBuilder.h
vendored
Normal file
@@ -0,0 +1,109 @@
|
||||
//===-- llvm/CodeGen/GlobalISel/CSEMIRBuilder.h --*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// This file implements a version of MachineIRBuilder which CSEs insts within
|
||||
/// a MachineBasicBlock.
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_CSEMIRBUILDER_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_CSEMIRBUILDER_H
|
||||
|
||||
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
|
||||
#include "llvm/CodeGen/GlobalISel/Utils.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// Defines a builder that does CSE of MachineInstructions using GISelCSEInfo.
|
||||
/// Eg usage.
|
||||
///
|
||||
///
|
||||
/// GISelCSEInfo *Info =
|
||||
/// &getAnalysis<GISelCSEAnalysisWrapperPass>().getCSEInfo(); CSEMIRBuilder
|
||||
/// CB(Builder.getState()); CB.setCSEInfo(Info); auto A = CB.buildConstant(s32,
|
||||
/// 42); auto B = CB.buildConstant(s32, 42); assert(A == B); unsigned CReg =
|
||||
/// MRI.createGenericVirtualRegister(s32); auto C = CB.buildConstant(CReg, 42);
|
||||
/// assert(C->getOpcode() == TargetOpcode::COPY);
|
||||
/// Explicitly passing in a register would materialize a copy if possible.
|
||||
/// CSEMIRBuilder also does trivial constant folding for binary ops.
|
||||
class CSEMIRBuilder : public MachineIRBuilder {
|
||||
|
||||
/// Returns true if A dominates B (within the same basic block).
|
||||
/// Both iterators must be in the same basic block.
|
||||
//
|
||||
// TODO: Another approach for checking dominance is having two iterators and
|
||||
// making them go towards each other until they meet or reach begin/end. Which
|
||||
// approach is better? Should this even change dynamically? For G_CONSTANTS
|
||||
// most of which will be at the top of the BB, the top down approach would be
|
||||
// a better choice. Does IRTranslator placing constants at the beginning still
|
||||
// make sense? Should this change based on Opcode?
|
||||
bool dominates(MachineBasicBlock::const_iterator A,
|
||||
MachineBasicBlock::const_iterator B) const;
|
||||
|
||||
/// For given ID, find a machineinstr in the CSE Map. If found, check if it
|
||||
/// dominates the current insertion point and if not, move it just before the
|
||||
/// current insertion point and return it. If not found, return Null
|
||||
/// MachineInstrBuilder.
|
||||
MachineInstrBuilder getDominatingInstrForID(FoldingSetNodeID &ID,
|
||||
void *&NodeInsertPos);
|
||||
/// Simple check if we can CSE (we have the CSEInfo) or if this Opcode is
|
||||
/// safe to CSE.
|
||||
bool canPerformCSEForOpc(unsigned Opc) const;
|
||||
|
||||
void profileDstOp(const DstOp &Op, GISelInstProfileBuilder &B) const;
|
||||
|
||||
void profileDstOps(ArrayRef<DstOp> Ops, GISelInstProfileBuilder &B) const {
|
||||
for (const DstOp &Op : Ops)
|
||||
profileDstOp(Op, B);
|
||||
}
|
||||
|
||||
void profileSrcOp(const SrcOp &Op, GISelInstProfileBuilder &B) const;
|
||||
|
||||
void profileSrcOps(ArrayRef<SrcOp> Ops, GISelInstProfileBuilder &B) const {
|
||||
for (const SrcOp &Op : Ops)
|
||||
profileSrcOp(Op, B);
|
||||
}
|
||||
|
||||
void profileMBBOpcode(GISelInstProfileBuilder &B, unsigned Opc) const;
|
||||
|
||||
void profileEverything(unsigned Opc, ArrayRef<DstOp> DstOps,
|
||||
ArrayRef<SrcOp> SrcOps, Optional<unsigned> Flags,
|
||||
GISelInstProfileBuilder &B) const;
|
||||
|
||||
// Takes a MachineInstrBuilder and inserts it into the CSEMap using the
|
||||
// NodeInsertPos.
|
||||
MachineInstrBuilder memoizeMI(MachineInstrBuilder MIB, void *NodeInsertPos);
|
||||
|
||||
// If we have can CSE an instruction, but still need to materialize to a VReg,
|
||||
// we emit a copy from the CSE'd inst to the VReg.
|
||||
MachineInstrBuilder generateCopiesIfRequired(ArrayRef<DstOp> DstOps,
|
||||
MachineInstrBuilder &MIB);
|
||||
|
||||
// If we have can CSE an instruction, but still need to materialize to a VReg,
|
||||
// check if we can generate copies. It's not possible to return a single MIB,
|
||||
// while emitting copies to multiple vregs.
|
||||
bool checkCopyToDefsPossible(ArrayRef<DstOp> DstOps);
|
||||
|
||||
public:
|
||||
// Pull in base class constructors.
|
||||
using MachineIRBuilder::MachineIRBuilder;
|
||||
// Unhide buildInstr
|
||||
MachineInstrBuilder buildInstr(unsigned Opc, ArrayRef<DstOp> DstOps,
|
||||
ArrayRef<SrcOp> SrcOps,
|
||||
Optional<unsigned> Flag = None) override;
|
||||
// Bring in the other overload from the base class.
|
||||
using MachineIRBuilder::buildConstant;
|
||||
|
||||
MachineInstrBuilder buildConstant(const DstOp &Res,
|
||||
const ConstantInt &Val) override;
|
||||
|
||||
// Bring in the other overload from the base class.
|
||||
using MachineIRBuilder::buildFConstant;
|
||||
MachineInstrBuilder buildFConstant(const DstOp &Res,
|
||||
const ConstantFP &Val) override;
|
||||
};
|
||||
} // namespace llvm
|
||||
#endif
|
||||
591
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/CallLowering.h
vendored
Normal file
591
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/CallLowering.h
vendored
Normal file
@@ -0,0 +1,591 @@
|
||||
//===- llvm/CodeGen/GlobalISel/CallLowering.h - Call lowering ---*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// This file describes how to lower LLVM calls to machine code calls.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_CALLLOWERING_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_CALLLOWERING_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/CodeGen/CallingConvLower.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineOperand.h"
|
||||
#include "llvm/CodeGen/TargetCallingConv.h"
|
||||
#include "llvm/IR/Attributes.h"
|
||||
#include "llvm/IR/CallingConv.h"
|
||||
#include "llvm/IR/Type.h"
|
||||
#include "llvm/IR/Value.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/MachineValueType.h"
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class CallBase;
|
||||
class DataLayout;
|
||||
class Function;
|
||||
class FunctionLoweringInfo;
|
||||
class MachineIRBuilder;
|
||||
struct MachinePointerInfo;
|
||||
class MachineRegisterInfo;
|
||||
class TargetLowering;
|
||||
|
||||
class CallLowering {
|
||||
const TargetLowering *TLI;
|
||||
|
||||
virtual void anchor();
|
||||
public:
|
||||
struct BaseArgInfo {
|
||||
Type *Ty;
|
||||
SmallVector<ISD::ArgFlagsTy, 4> Flags;
|
||||
bool IsFixed;
|
||||
|
||||
BaseArgInfo(Type *Ty,
|
||||
ArrayRef<ISD::ArgFlagsTy> Flags = ArrayRef<ISD::ArgFlagsTy>(),
|
||||
bool IsFixed = true)
|
||||
: Ty(Ty), Flags(Flags.begin(), Flags.end()), IsFixed(IsFixed) {}
|
||||
|
||||
BaseArgInfo() : Ty(nullptr), IsFixed(false) {}
|
||||
};
|
||||
|
||||
struct ArgInfo : public BaseArgInfo {
|
||||
SmallVector<Register, 4> Regs;
|
||||
// If the argument had to be split into multiple parts according to the
|
||||
// target calling convention, then this contains the original vregs
|
||||
// if the argument was an incoming arg.
|
||||
SmallVector<Register, 2> OrigRegs;
|
||||
|
||||
/// Optionally track the original IR value for the argument. This may not be
|
||||
/// meaningful in all contexts. This should only be used on for forwarding
|
||||
/// through to use for aliasing information in MachinePointerInfo for memory
|
||||
/// arguments.
|
||||
const Value *OrigValue = nullptr;
|
||||
|
||||
/// Index original Function's argument.
|
||||
unsigned OrigArgIndex;
|
||||
|
||||
/// Sentinel value for implicit machine-level input arguments.
|
||||
static const unsigned NoArgIndex = UINT_MAX;
|
||||
|
||||
ArgInfo(ArrayRef<Register> Regs, Type *Ty, unsigned OrigIndex,
|
||||
ArrayRef<ISD::ArgFlagsTy> Flags = ArrayRef<ISD::ArgFlagsTy>(),
|
||||
bool IsFixed = true, const Value *OrigValue = nullptr)
|
||||
: BaseArgInfo(Ty, Flags, IsFixed), Regs(Regs.begin(), Regs.end()),
|
||||
OrigValue(OrigValue), OrigArgIndex(OrigIndex) {
|
||||
if (!Regs.empty() && Flags.empty())
|
||||
this->Flags.push_back(ISD::ArgFlagsTy());
|
||||
// FIXME: We should have just one way of saying "no register".
|
||||
assert(((Ty->isVoidTy() || Ty->isEmptyTy()) ==
|
||||
(Regs.empty() || Regs[0] == 0)) &&
|
||||
"only void types should have no register");
|
||||
}
|
||||
|
||||
ArgInfo(ArrayRef<Register> Regs, const Value &OrigValue, unsigned OrigIndex,
|
||||
ArrayRef<ISD::ArgFlagsTy> Flags = ArrayRef<ISD::ArgFlagsTy>(),
|
||||
bool IsFixed = true)
|
||||
: ArgInfo(Regs, OrigValue.getType(), OrigIndex, Flags, IsFixed, &OrigValue) {}
|
||||
|
||||
ArgInfo() = default;
|
||||
};
|
||||
|
||||
struct CallLoweringInfo {
|
||||
/// Calling convention to be used for the call.
|
||||
CallingConv::ID CallConv = CallingConv::C;
|
||||
|
||||
/// Destination of the call. It should be either a register, globaladdress,
|
||||
/// or externalsymbol.
|
||||
MachineOperand Callee = MachineOperand::CreateImm(0);
|
||||
|
||||
/// Descriptor for the return type of the function.
|
||||
ArgInfo OrigRet;
|
||||
|
||||
/// List of descriptors of the arguments passed to the function.
|
||||
SmallVector<ArgInfo, 32> OrigArgs;
|
||||
|
||||
/// Valid if the call has a swifterror inout parameter, and contains the
|
||||
/// vreg that the swifterror should be copied into after the call.
|
||||
Register SwiftErrorVReg;
|
||||
|
||||
/// Original IR callsite corresponding to this call, if available.
|
||||
const CallBase *CB = nullptr;
|
||||
|
||||
MDNode *KnownCallees = nullptr;
|
||||
|
||||
/// True if the call must be tail call optimized.
|
||||
bool IsMustTailCall = false;
|
||||
|
||||
/// True if the call passes all target-independent checks for tail call
|
||||
/// optimization.
|
||||
bool IsTailCall = false;
|
||||
|
||||
/// True if the call was lowered as a tail call. This is consumed by the
|
||||
/// legalizer. This allows the legalizer to lower libcalls as tail calls.
|
||||
bool LoweredTailCall = false;
|
||||
|
||||
/// True if the call is to a vararg function.
|
||||
bool IsVarArg = false;
|
||||
|
||||
/// True if the function's return value can be lowered to registers.
|
||||
bool CanLowerReturn = true;
|
||||
|
||||
/// VReg to hold the hidden sret parameter.
|
||||
Register DemoteRegister;
|
||||
|
||||
/// The stack index for sret demotion.
|
||||
int DemoteStackIndex;
|
||||
};
|
||||
|
||||
/// Argument handling is mostly uniform between the four places that
|
||||
/// make these decisions: function formal arguments, call
|
||||
/// instruction args, call instruction returns and function
|
||||
/// returns. However, once a decision has been made on where an
|
||||
/// argument should go, exactly what happens can vary slightly. This
|
||||
/// class abstracts the differences.
|
||||
///
|
||||
/// ValueAssigner should not depend on any specific function state, and
|
||||
/// only determine the types and locations for arguments.
|
||||
struct ValueAssigner {
|
||||
ValueAssigner(bool IsIncoming, CCAssignFn *AssignFn_,
|
||||
CCAssignFn *AssignFnVarArg_ = nullptr)
|
||||
: AssignFn(AssignFn_), AssignFnVarArg(AssignFnVarArg_),
|
||||
IsIncomingArgumentHandler(IsIncoming) {
|
||||
|
||||
// Some targets change the handler depending on whether the call is
|
||||
// varargs or not. If
|
||||
if (!AssignFnVarArg)
|
||||
AssignFnVarArg = AssignFn;
|
||||
}
|
||||
|
||||
virtual ~ValueAssigner() = default;
|
||||
|
||||
/// Returns true if the handler is dealing with incoming arguments,
|
||||
/// i.e. those that move values from some physical location to vregs.
|
||||
bool isIncomingArgumentHandler() const {
|
||||
return IsIncomingArgumentHandler;
|
||||
}
|
||||
|
||||
/// Wrap call to (typically tablegenerated CCAssignFn). This may be
|
||||
/// overridden to track additional state information as arguments are
|
||||
/// assigned or apply target specific hacks around the legacy
|
||||
/// infrastructure.
|
||||
virtual bool assignArg(unsigned ValNo, EVT OrigVT, MVT ValVT, MVT LocVT,
|
||||
CCValAssign::LocInfo LocInfo, const ArgInfo &Info,
|
||||
ISD::ArgFlagsTy Flags, CCState &State) {
|
||||
if (getAssignFn(State.isVarArg())(ValNo, ValVT, LocVT, LocInfo, Flags,
|
||||
State))
|
||||
return true;
|
||||
StackOffset = State.getNextStackOffset();
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Assignment function to use for a general call.
|
||||
CCAssignFn *AssignFn;
|
||||
|
||||
/// Assignment function to use for a variadic call. This is usually the same
|
||||
/// as AssignFn on most targets.
|
||||
CCAssignFn *AssignFnVarArg;
|
||||
|
||||
/// Stack offset for next argument. At the end of argument evaluation, this
|
||||
/// is typically the total stack size.
|
||||
uint64_t StackOffset = 0;
|
||||
|
||||
/// Select the appropriate assignment function depending on whether this is
|
||||
/// a variadic call.
|
||||
CCAssignFn *getAssignFn(bool IsVarArg) const {
|
||||
return IsVarArg ? AssignFnVarArg : AssignFn;
|
||||
}
|
||||
|
||||
private:
|
||||
const bool IsIncomingArgumentHandler;
|
||||
virtual void anchor();
|
||||
};
|
||||
|
||||
struct IncomingValueAssigner : public ValueAssigner {
|
||||
IncomingValueAssigner(CCAssignFn *AssignFn_,
|
||||
CCAssignFn *AssignFnVarArg_ = nullptr)
|
||||
: ValueAssigner(true, AssignFn_, AssignFnVarArg_) {}
|
||||
};
|
||||
|
||||
struct OutgoingValueAssigner : public ValueAssigner {
|
||||
OutgoingValueAssigner(CCAssignFn *AssignFn_,
|
||||
CCAssignFn *AssignFnVarArg_ = nullptr)
|
||||
: ValueAssigner(false, AssignFn_, AssignFnVarArg_) {}
|
||||
};
|
||||
|
||||
struct ValueHandler {
|
||||
MachineIRBuilder &MIRBuilder;
|
||||
MachineRegisterInfo &MRI;
|
||||
const bool IsIncomingArgumentHandler;
|
||||
|
||||
ValueHandler(bool IsIncoming, MachineIRBuilder &MIRBuilder,
|
||||
MachineRegisterInfo &MRI)
|
||||
: MIRBuilder(MIRBuilder), MRI(MRI),
|
||||
IsIncomingArgumentHandler(IsIncoming) {}
|
||||
|
||||
virtual ~ValueHandler() = default;
|
||||
|
||||
/// Returns true if the handler is dealing with incoming arguments,
|
||||
/// i.e. those that move values from some physical location to vregs.
|
||||
bool isIncomingArgumentHandler() const {
|
||||
return IsIncomingArgumentHandler;
|
||||
}
|
||||
|
||||
/// Materialize a VReg containing the address of the specified
|
||||
/// stack-based object. This is either based on a FrameIndex or
|
||||
/// direct SP manipulation, depending on the context. \p MPO
|
||||
/// should be initialized to an appropriate description of the
|
||||
/// address created.
|
||||
virtual Register getStackAddress(uint64_t MemSize, int64_t Offset,
|
||||
MachinePointerInfo &MPO,
|
||||
ISD::ArgFlagsTy Flags) = 0;
|
||||
|
||||
/// Return the in-memory size to write for the argument at \p VA. This may
|
||||
/// be smaller than the allocated stack slot size.
|
||||
///
|
||||
/// This is overridable primarily for targets to maintain compatibility with
|
||||
/// hacks around the existing DAG call lowering infrastructure.
|
||||
virtual LLT getStackValueStoreType(const DataLayout &DL,
|
||||
const CCValAssign &VA,
|
||||
ISD::ArgFlagsTy Flags) const;
|
||||
|
||||
/// The specified value has been assigned to a physical register,
|
||||
/// handle the appropriate COPY (either to or from) and mark any
|
||||
/// relevant uses/defines as needed.
|
||||
virtual void assignValueToReg(Register ValVReg, Register PhysReg,
|
||||
CCValAssign VA) = 0;
|
||||
|
||||
/// The specified value has been assigned to a stack
|
||||
/// location. Load or store it there, with appropriate extension
|
||||
/// if necessary.
|
||||
virtual void assignValueToAddress(Register ValVReg, Register Addr,
|
||||
LLT MemTy, MachinePointerInfo &MPO,
|
||||
CCValAssign &VA) = 0;
|
||||
|
||||
/// An overload which takes an ArgInfo if additional information about the
|
||||
/// arg is needed. \p ValRegIndex is the index in \p Arg.Regs for the value
|
||||
/// to store.
|
||||
virtual void assignValueToAddress(const ArgInfo &Arg, unsigned ValRegIndex,
|
||||
Register Addr, LLT MemTy,
|
||||
MachinePointerInfo &MPO,
|
||||
CCValAssign &VA) {
|
||||
assignValueToAddress(Arg.Regs[ValRegIndex], Addr, MemTy, MPO, VA);
|
||||
}
|
||||
|
||||
/// Handle custom values, which may be passed into one or more of \p VAs.
|
||||
/// \p If the handler wants the assignments to be delayed until after
|
||||
/// mem loc assignments, then it sets \p Thunk to the thunk to do the
|
||||
/// assignment.
|
||||
/// \return The number of \p VAs that have been assigned after the first
|
||||
/// one, and which should therefore be skipped from further
|
||||
/// processing.
|
||||
virtual unsigned assignCustomValue(ArgInfo &Arg, ArrayRef<CCValAssign> VAs,
|
||||
std::function<void()> *Thunk = nullptr) {
|
||||
// This is not a pure virtual method because not all targets need to worry
|
||||
// about custom values.
|
||||
llvm_unreachable("Custom values not supported");
|
||||
}
|
||||
|
||||
/// Do a memory copy of \p MemSize bytes from \p SrcPtr to \p DstPtr. This
|
||||
/// is necessary for outgoing stack-passed byval arguments.
|
||||
void
|
||||
copyArgumentMemory(const ArgInfo &Arg, Register DstPtr, Register SrcPtr,
|
||||
const MachinePointerInfo &DstPtrInfo, Align DstAlign,
|
||||
const MachinePointerInfo &SrcPtrInfo, Align SrcAlign,
|
||||
uint64_t MemSize, CCValAssign &VA) const;
|
||||
|
||||
/// Extend a register to the location type given in VA, capped at extending
|
||||
/// to at most MaxSize bits. If MaxSizeBits is 0 then no maximum is set.
|
||||
Register extendRegister(Register ValReg, CCValAssign &VA,
|
||||
unsigned MaxSizeBits = 0);
|
||||
};
|
||||
|
||||
/// Base class for ValueHandlers used for arguments coming into the current
|
||||
/// function, or for return values received from a call.
|
||||
struct IncomingValueHandler : public ValueHandler {
|
||||
IncomingValueHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI)
|
||||
: ValueHandler(/*IsIncoming*/ true, MIRBuilder, MRI) {}
|
||||
|
||||
/// Insert G_ASSERT_ZEXT/G_ASSERT_SEXT or other hint instruction based on \p
|
||||
/// VA, returning the new register if a hint was inserted.
|
||||
Register buildExtensionHint(CCValAssign &VA, Register SrcReg, LLT NarrowTy);
|
||||
|
||||
/// Provides a default implementation for argument handling.
|
||||
void assignValueToReg(Register ValVReg, Register PhysReg,
|
||||
CCValAssign VA) override;
|
||||
};
|
||||
|
||||
/// Base class for ValueHandlers used for arguments passed to a function call,
|
||||
/// or for return values.
|
||||
struct OutgoingValueHandler : public ValueHandler {
|
||||
OutgoingValueHandler(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI)
|
||||
: ValueHandler(/*IsIncoming*/ false, MIRBuilder, MRI) {}
|
||||
};
|
||||
|
||||
protected:
|
||||
/// Getter for generic TargetLowering class.
|
||||
const TargetLowering *getTLI() const {
|
||||
return TLI;
|
||||
}
|
||||
|
||||
/// Getter for target specific TargetLowering class.
|
||||
template <class XXXTargetLowering>
|
||||
const XXXTargetLowering *getTLI() const {
|
||||
return static_cast<const XXXTargetLowering *>(TLI);
|
||||
}
|
||||
|
||||
/// \returns Flags corresponding to the attributes on the \p ArgIdx-th
|
||||
/// parameter of \p Call.
|
||||
ISD::ArgFlagsTy getAttributesForArgIdx(const CallBase &Call,
|
||||
unsigned ArgIdx) const;
|
||||
|
||||
/// Adds flags to \p Flags based off of the attributes in \p Attrs.
|
||||
/// \p OpIdx is the index in \p Attrs to add flags from.
|
||||
void addArgFlagsFromAttributes(ISD::ArgFlagsTy &Flags,
|
||||
const AttributeList &Attrs,
|
||||
unsigned OpIdx) const;
|
||||
|
||||
template <typename FuncInfoTy>
|
||||
void setArgFlags(ArgInfo &Arg, unsigned OpIdx, const DataLayout &DL,
|
||||
const FuncInfoTy &FuncInfo) const;
|
||||
|
||||
/// Break \p OrigArgInfo into one or more pieces the calling convention can
|
||||
/// process, returned in \p SplitArgs. For example, this should break structs
|
||||
/// down into individual fields.
|
||||
///
|
||||
/// If \p Offsets is non-null, it points to a vector to be filled in
|
||||
/// with the in-memory offsets of each of the individual values.
|
||||
void splitToValueTypes(const ArgInfo &OrigArgInfo,
|
||||
SmallVectorImpl<ArgInfo> &SplitArgs,
|
||||
const DataLayout &DL, CallingConv::ID CallConv,
|
||||
SmallVectorImpl<uint64_t> *Offsets = nullptr) const;
|
||||
|
||||
/// Analyze the argument list in \p Args, using \p Assigner to populate \p
|
||||
/// CCInfo. This will determine the types and locations to use for passed or
|
||||
/// returned values. This may resize fields in \p Args if the value is split
|
||||
/// across multiple registers or stack slots.
|
||||
///
|
||||
/// This is independent of the function state and can be used
|
||||
/// to determine how a call would pass arguments without needing to change the
|
||||
/// function. This can be used to check if arguments are suitable for tail
|
||||
/// call lowering.
|
||||
///
|
||||
/// \return True if everything has succeeded, false otherwise.
|
||||
bool determineAssignments(ValueAssigner &Assigner,
|
||||
SmallVectorImpl<ArgInfo> &Args,
|
||||
CCState &CCInfo) const;
|
||||
|
||||
/// Invoke ValueAssigner::assignArg on each of the given \p Args and then use
|
||||
/// \p Handler to move them to the assigned locations.
|
||||
///
|
||||
/// \return True if everything has succeeded, false otherwise.
|
||||
bool
|
||||
determineAndHandleAssignments(ValueHandler &Handler, ValueAssigner &Assigner,
|
||||
SmallVectorImpl<ArgInfo> &Args,
|
||||
MachineIRBuilder &MIRBuilder,
|
||||
CallingConv::ID CallConv, bool IsVarArg,
|
||||
ArrayRef<Register> ThisReturnRegs = None) const;
|
||||
|
||||
/// Use \p Handler to insert code to handle the argument/return values
|
||||
/// represented by \p Args. It's expected determineAssignments previously
|
||||
/// processed these arguments to populate \p CCState and \p ArgLocs.
|
||||
bool handleAssignments(ValueHandler &Handler, SmallVectorImpl<ArgInfo> &Args,
|
||||
CCState &CCState,
|
||||
SmallVectorImpl<CCValAssign> &ArgLocs,
|
||||
MachineIRBuilder &MIRBuilder,
|
||||
ArrayRef<Register> ThisReturnRegs = None) const;
|
||||
|
||||
/// Check whether parameters to a call that are passed in callee saved
|
||||
/// registers are the same as from the calling function. This needs to be
|
||||
/// checked for tail call eligibility.
|
||||
bool parametersInCSRMatch(const MachineRegisterInfo &MRI,
|
||||
const uint32_t *CallerPreservedMask,
|
||||
const SmallVectorImpl<CCValAssign> &ArgLocs,
|
||||
const SmallVectorImpl<ArgInfo> &OutVals) const;
|
||||
|
||||
/// \returns True if the calling convention for a callee and its caller pass
|
||||
/// results in the same way. Typically used for tail call eligibility checks.
|
||||
///
|
||||
/// \p Info is the CallLoweringInfo for the call.
|
||||
/// \p MF is the MachineFunction for the caller.
|
||||
/// \p InArgs contains the results of the call.
|
||||
/// \p CalleeAssigner specifies the target's handling of the argument types
|
||||
/// for the callee.
|
||||
/// \p CallerAssigner specifies the target's handling of the
|
||||
/// argument types for the caller.
|
||||
bool resultsCompatible(CallLoweringInfo &Info, MachineFunction &MF,
|
||||
SmallVectorImpl<ArgInfo> &InArgs,
|
||||
ValueAssigner &CalleeAssigner,
|
||||
ValueAssigner &CallerAssigner) const;
|
||||
|
||||
public:
|
||||
CallLowering(const TargetLowering *TLI) : TLI(TLI) {}
|
||||
virtual ~CallLowering() = default;
|
||||
|
||||
/// \return true if the target is capable of handling swifterror values that
|
||||
/// have been promoted to a specified register. The extended versions of
|
||||
/// lowerReturn and lowerCall should be implemented.
|
||||
virtual bool supportSwiftError() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Load the returned value from the stack into virtual registers in \p VRegs.
|
||||
/// It uses the frame index \p FI and the start offset from \p DemoteReg.
|
||||
/// The loaded data size will be determined from \p RetTy.
|
||||
void insertSRetLoads(MachineIRBuilder &MIRBuilder, Type *RetTy,
|
||||
ArrayRef<Register> VRegs, Register DemoteReg,
|
||||
int FI) const;
|
||||
|
||||
/// Store the return value given by \p VRegs into stack starting at the offset
|
||||
/// specified in \p DemoteReg.
|
||||
void insertSRetStores(MachineIRBuilder &MIRBuilder, Type *RetTy,
|
||||
ArrayRef<Register> VRegs, Register DemoteReg) const;
|
||||
|
||||
/// Insert the hidden sret ArgInfo to the beginning of \p SplitArgs.
|
||||
/// This function should be called from the target specific
|
||||
/// lowerFormalArguments when \p F requires the sret demotion.
|
||||
void insertSRetIncomingArgument(const Function &F,
|
||||
SmallVectorImpl<ArgInfo> &SplitArgs,
|
||||
Register &DemoteReg, MachineRegisterInfo &MRI,
|
||||
const DataLayout &DL) const;
|
||||
|
||||
/// For the call-base described by \p CB, insert the hidden sret ArgInfo to
|
||||
/// the OrigArgs field of \p Info.
|
||||
void insertSRetOutgoingArgument(MachineIRBuilder &MIRBuilder,
|
||||
const CallBase &CB,
|
||||
CallLoweringInfo &Info) const;
|
||||
|
||||
/// \return True if the return type described by \p Outs can be returned
|
||||
/// without performing sret demotion.
|
||||
bool checkReturn(CCState &CCInfo, SmallVectorImpl<BaseArgInfo> &Outs,
|
||||
CCAssignFn *Fn) const;
|
||||
|
||||
/// Get the type and the ArgFlags for the split components of \p RetTy as
|
||||
/// returned by \c ComputeValueVTs.
|
||||
void getReturnInfo(CallingConv::ID CallConv, Type *RetTy, AttributeList Attrs,
|
||||
SmallVectorImpl<BaseArgInfo> &Outs,
|
||||
const DataLayout &DL) const;
|
||||
|
||||
/// Toplevel function to check the return type based on the target calling
|
||||
/// convention. \return True if the return value of \p MF can be returned
|
||||
/// without performing sret demotion.
|
||||
bool checkReturnTypeForCallConv(MachineFunction &MF) const;
|
||||
|
||||
/// This hook must be implemented to check whether the return values
|
||||
/// described by \p Outs can fit into the return registers. If false
|
||||
/// is returned, an sret-demotion is performed.
|
||||
virtual bool canLowerReturn(MachineFunction &MF, CallingConv::ID CallConv,
|
||||
SmallVectorImpl<BaseArgInfo> &Outs,
|
||||
bool IsVarArg) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// This hook must be implemented to lower outgoing return values, described
|
||||
/// by \p Val, into the specified virtual registers \p VRegs.
|
||||
/// This hook is used by GlobalISel.
|
||||
///
|
||||
/// \p FLI is required for sret demotion.
|
||||
///
|
||||
/// \p SwiftErrorVReg is non-zero if the function has a swifterror parameter
|
||||
/// that needs to be implicitly returned.
|
||||
///
|
||||
/// \return True if the lowering succeeds, false otherwise.
|
||||
virtual bool lowerReturn(MachineIRBuilder &MIRBuilder, const Value *Val,
|
||||
ArrayRef<Register> VRegs, FunctionLoweringInfo &FLI,
|
||||
Register SwiftErrorVReg) const {
|
||||
if (!supportSwiftError()) {
|
||||
assert(SwiftErrorVReg == 0 && "attempt to use unsupported swifterror");
|
||||
return lowerReturn(MIRBuilder, Val, VRegs, FLI);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// This hook behaves as the extended lowerReturn function, but for targets
|
||||
/// that do not support swifterror value promotion.
|
||||
virtual bool lowerReturn(MachineIRBuilder &MIRBuilder, const Value *Val,
|
||||
ArrayRef<Register> VRegs,
|
||||
FunctionLoweringInfo &FLI) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool fallBackToDAGISel(const MachineFunction &MF) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// This hook must be implemented to lower the incoming (formal)
|
||||
/// arguments, described by \p VRegs, for GlobalISel. Each argument
|
||||
/// must end up in the related virtual registers described by \p VRegs.
|
||||
/// In other words, the first argument should end up in \c VRegs[0],
|
||||
/// the second in \c VRegs[1], and so on. For each argument, there will be one
|
||||
/// register for each non-aggregate type, as returned by \c computeValueLLTs.
|
||||
/// \p MIRBuilder is set to the proper insertion for the argument
|
||||
/// lowering. \p FLI is required for sret demotion.
|
||||
///
|
||||
/// \return True if the lowering succeeded, false otherwise.
|
||||
virtual bool lowerFormalArguments(MachineIRBuilder &MIRBuilder,
|
||||
const Function &F,
|
||||
ArrayRef<ArrayRef<Register>> VRegs,
|
||||
FunctionLoweringInfo &FLI) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// This hook must be implemented to lower the given call instruction,
|
||||
/// including argument and return value marshalling.
|
||||
///
|
||||
///
|
||||
/// \return true if the lowering succeeded, false otherwise.
|
||||
virtual bool lowerCall(MachineIRBuilder &MIRBuilder,
|
||||
CallLoweringInfo &Info) const {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Lower the given call instruction, including argument and return value
|
||||
/// marshalling.
|
||||
///
|
||||
/// \p CI is the call/invoke instruction.
|
||||
///
|
||||
/// \p ResRegs are the registers where the call's return value should be
|
||||
/// stored (or 0 if there is no return value). There will be one register for
|
||||
/// each non-aggregate type, as returned by \c computeValueLLTs.
|
||||
///
|
||||
/// \p ArgRegs is a list of lists of virtual registers containing each
|
||||
/// argument that needs to be passed (argument \c i should be placed in \c
|
||||
/// ArgRegs[i]). For each argument, there will be one register for each
|
||||
/// non-aggregate type, as returned by \c computeValueLLTs.
|
||||
///
|
||||
/// \p SwiftErrorVReg is non-zero if the call has a swifterror inout
|
||||
/// parameter, and contains the vreg that the swifterror should be copied into
|
||||
/// after the call.
|
||||
///
|
||||
/// \p GetCalleeReg is a callback to materialize a register for the callee if
|
||||
/// the target determines it cannot jump to the destination based purely on \p
|
||||
/// CI. This might be because \p CI is indirect, or because of the limited
|
||||
/// range of an immediate jump.
|
||||
///
|
||||
/// \return true if the lowering succeeded, false otherwise.
|
||||
bool lowerCall(MachineIRBuilder &MIRBuilder, const CallBase &Call,
|
||||
ArrayRef<Register> ResRegs,
|
||||
ArrayRef<ArrayRef<Register>> ArgRegs, Register SwiftErrorVReg,
|
||||
std::function<unsigned()> GetCalleeReg) const;
|
||||
|
||||
/// For targets which want to use big-endian can enable it with
|
||||
/// enableBigEndian() hook
|
||||
virtual bool enableBigEndian() const { return false; }
|
||||
|
||||
/// For targets which support the "returned" parameter attribute, returns
|
||||
/// true if the given type is a valid one to use with "returned".
|
||||
virtual bool isTypeIsValidForThisReturn(EVT Ty) const { return false; }
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_GLOBALISEL_CALLLOWERING_H
|
||||
46
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/Combiner.h
vendored
Normal file
46
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/Combiner.h
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
//== ----- llvm/CodeGen/GlobalISel/Combiner.h -------------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// This contains common code to drive combines. Combiner Passes will need to
|
||||
/// setup a CombinerInfo and call combineMachineFunction.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_COMBINER_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_COMBINER_H
|
||||
|
||||
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
|
||||
namespace llvm {
|
||||
class MachineRegisterInfo;
|
||||
class CombinerInfo;
|
||||
class GISelCSEInfo;
|
||||
class TargetPassConfig;
|
||||
class MachineFunction;
|
||||
|
||||
class Combiner {
|
||||
public:
|
||||
Combiner(CombinerInfo &CombinerInfo, const TargetPassConfig *TPC);
|
||||
|
||||
/// If CSEInfo is not null, then the Combiner will setup observer for
|
||||
/// CSEInfo and instantiate a CSEMIRBuilder. Pass nullptr if CSE is not
|
||||
/// needed.
|
||||
bool combineMachineInstrs(MachineFunction &MF, GISelCSEInfo *CSEInfo);
|
||||
|
||||
protected:
|
||||
CombinerInfo &CInfo;
|
||||
|
||||
MachineRegisterInfo *MRI = nullptr;
|
||||
const TargetPassConfig *TPC;
|
||||
std::unique_ptr<MachineIRBuilder> Builder;
|
||||
};
|
||||
|
||||
} // End namespace llvm.
|
||||
|
||||
#endif // LLVM_CODEGEN_GLOBALISEL_COMBINER_H
|
||||
753
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
vendored
Normal file
753
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
vendored
Normal file
@@ -0,0 +1,753 @@
|
||||
//===-- llvm/CodeGen/GlobalISel/CombinerHelper.h --------------*- 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
|
||||
//
|
||||
//===--------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// This contains common combine transformations that may be used in a combine
|
||||
/// pass,or by the target elsewhere.
|
||||
/// Targets can pick individual opcode transformations from the helper or use
|
||||
/// tryCombine which invokes all transformations. All of the transformations
|
||||
/// return true if the MachineInstruction changed and false otherwise.
|
||||
///
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_COMBINERHELPER_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_COMBINERHELPER_H
|
||||
|
||||
#include "llvm/ADT/APFloat.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
|
||||
#include "llvm/CodeGen/LowLevelType.h"
|
||||
#include "llvm/CodeGen/Register.h"
|
||||
#include "llvm/Support/Alignment.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class GISelChangeObserver;
|
||||
class MachineIRBuilder;
|
||||
class MachineInstrBuilder;
|
||||
class MachineRegisterInfo;
|
||||
class MachineInstr;
|
||||
class MachineOperand;
|
||||
class GISelKnownBits;
|
||||
class MachineDominatorTree;
|
||||
class LegalizerInfo;
|
||||
struct LegalityQuery;
|
||||
class RegisterBank;
|
||||
class RegisterBankInfo;
|
||||
class TargetLowering;
|
||||
class TargetRegisterInfo;
|
||||
|
||||
struct PreferredTuple {
|
||||
LLT Ty; // The result type of the extend.
|
||||
unsigned ExtendOpcode; // G_ANYEXT/G_SEXT/G_ZEXT
|
||||
MachineInstr *MI;
|
||||
};
|
||||
|
||||
struct IndexedLoadStoreMatchInfo {
|
||||
Register Addr;
|
||||
Register Base;
|
||||
Register Offset;
|
||||
bool IsPre;
|
||||
};
|
||||
|
||||
struct PtrAddChain {
|
||||
int64_t Imm;
|
||||
Register Base;
|
||||
const RegisterBank *Bank;
|
||||
};
|
||||
|
||||
struct RegisterImmPair {
|
||||
Register Reg;
|
||||
int64_t Imm;
|
||||
};
|
||||
|
||||
struct ShiftOfShiftedLogic {
|
||||
MachineInstr *Logic;
|
||||
MachineInstr *Shift2;
|
||||
Register LogicNonShiftReg;
|
||||
uint64_t ValSum;
|
||||
};
|
||||
|
||||
using BuildFnTy = std::function<void(MachineIRBuilder &)>;
|
||||
|
||||
struct MergeTruncStoresInfo {
|
||||
SmallVector<GStore *> FoundStores;
|
||||
GStore *LowestIdxStore = nullptr;
|
||||
Register WideSrcVal;
|
||||
bool NeedBSwap = false;
|
||||
bool NeedRotate = false;
|
||||
};
|
||||
|
||||
using OperandBuildSteps =
|
||||
SmallVector<std::function<void(MachineInstrBuilder &)>, 4>;
|
||||
struct InstructionBuildSteps {
|
||||
unsigned Opcode = 0; /// The opcode for the produced instruction.
|
||||
OperandBuildSteps OperandFns; /// Operands to be added to the instruction.
|
||||
InstructionBuildSteps() = default;
|
||||
InstructionBuildSteps(unsigned Opcode, const OperandBuildSteps &OperandFns)
|
||||
: Opcode(Opcode), OperandFns(OperandFns) {}
|
||||
};
|
||||
|
||||
struct InstructionStepsMatchInfo {
|
||||
/// Describes instructions to be built during a combine.
|
||||
SmallVector<InstructionBuildSteps, 2> InstrsToBuild;
|
||||
InstructionStepsMatchInfo() = default;
|
||||
InstructionStepsMatchInfo(
|
||||
std::initializer_list<InstructionBuildSteps> InstrsToBuild)
|
||||
: InstrsToBuild(InstrsToBuild) {}
|
||||
};
|
||||
|
||||
class CombinerHelper {
|
||||
protected:
|
||||
MachineIRBuilder &Builder;
|
||||
MachineRegisterInfo &MRI;
|
||||
GISelChangeObserver &Observer;
|
||||
GISelKnownBits *KB;
|
||||
MachineDominatorTree *MDT;
|
||||
const LegalizerInfo *LI;
|
||||
const RegisterBankInfo *RBI;
|
||||
const TargetRegisterInfo *TRI;
|
||||
|
||||
public:
|
||||
CombinerHelper(GISelChangeObserver &Observer, MachineIRBuilder &B,
|
||||
GISelKnownBits *KB = nullptr,
|
||||
MachineDominatorTree *MDT = nullptr,
|
||||
const LegalizerInfo *LI = nullptr);
|
||||
|
||||
GISelKnownBits *getKnownBits() const {
|
||||
return KB;
|
||||
}
|
||||
|
||||
const TargetLowering &getTargetLowering() const;
|
||||
|
||||
/// \return true if the combine is running prior to legalization, or if \p
|
||||
/// Query is legal on the target.
|
||||
bool isLegalOrBeforeLegalizer(const LegalityQuery &Query) const;
|
||||
|
||||
/// MachineRegisterInfo::replaceRegWith() and inform the observer of the changes
|
||||
void replaceRegWith(MachineRegisterInfo &MRI, Register FromReg, Register ToReg) const;
|
||||
|
||||
/// Replace a single register operand with a new register and inform the
|
||||
/// observer of the changes.
|
||||
void replaceRegOpWith(MachineRegisterInfo &MRI, MachineOperand &FromRegOp,
|
||||
Register ToReg) const;
|
||||
|
||||
/// Replace the opcode in instruction with a new opcode and inform the
|
||||
/// observer of the changes.
|
||||
void replaceOpcodeWith(MachineInstr &FromMI, unsigned ToOpcode) const;
|
||||
|
||||
/// Get the register bank of \p Reg.
|
||||
/// If Reg has not been assigned a register, a register class,
|
||||
/// or a register bank, then this returns nullptr.
|
||||
///
|
||||
/// \pre Reg.isValid()
|
||||
const RegisterBank *getRegBank(Register Reg) const;
|
||||
|
||||
/// Set the register bank of \p Reg.
|
||||
/// Does nothing if the RegBank is null.
|
||||
/// This is the counterpart to getRegBank.
|
||||
void setRegBank(Register Reg, const RegisterBank *RegBank);
|
||||
|
||||
/// If \p MI is COPY, try to combine it.
|
||||
/// Returns true if MI changed.
|
||||
bool tryCombineCopy(MachineInstr &MI);
|
||||
bool matchCombineCopy(MachineInstr &MI);
|
||||
void applyCombineCopy(MachineInstr &MI);
|
||||
|
||||
/// Returns true if \p DefMI precedes \p UseMI or they are the same
|
||||
/// instruction. Both must be in the same basic block.
|
||||
bool isPredecessor(const MachineInstr &DefMI, const MachineInstr &UseMI);
|
||||
|
||||
/// Returns true if \p DefMI dominates \p UseMI. By definition an
|
||||
/// instruction dominates itself.
|
||||
///
|
||||
/// If we haven't been provided with a MachineDominatorTree during
|
||||
/// construction, this function returns a conservative result that tracks just
|
||||
/// a single basic block.
|
||||
bool dominates(const MachineInstr &DefMI, const MachineInstr &UseMI);
|
||||
|
||||
/// If \p MI is extend that consumes the result of a load, try to combine it.
|
||||
/// Returns true if MI changed.
|
||||
bool tryCombineExtendingLoads(MachineInstr &MI);
|
||||
bool matchCombineExtendingLoads(MachineInstr &MI, PreferredTuple &MatchInfo);
|
||||
void applyCombineExtendingLoads(MachineInstr &MI, PreferredTuple &MatchInfo);
|
||||
|
||||
/// Match (and (load x), mask) -> zextload x
|
||||
bool matchCombineLoadWithAndMask(MachineInstr &MI, BuildFnTy &MatchInfo);
|
||||
|
||||
/// Combine \p MI into a pre-indexed or post-indexed load/store operation if
|
||||
/// legal and the surrounding code makes it useful.
|
||||
bool tryCombineIndexedLoadStore(MachineInstr &MI);
|
||||
bool matchCombineIndexedLoadStore(MachineInstr &MI, IndexedLoadStoreMatchInfo &MatchInfo);
|
||||
void applyCombineIndexedLoadStore(MachineInstr &MI, IndexedLoadStoreMatchInfo &MatchInfo);
|
||||
|
||||
bool matchSextTruncSextLoad(MachineInstr &MI);
|
||||
void applySextTruncSextLoad(MachineInstr &MI);
|
||||
|
||||
/// Match sext_inreg(load p), imm -> sextload p
|
||||
bool matchSextInRegOfLoad(MachineInstr &MI, std::tuple<Register, unsigned> &MatchInfo);
|
||||
void applySextInRegOfLoad(MachineInstr &MI, std::tuple<Register, unsigned> &MatchInfo);
|
||||
|
||||
/// Try to combine G_[SU]DIV and G_[SU]REM into a single G_[SU]DIVREM
|
||||
/// when their source operands are identical.
|
||||
bool matchCombineDivRem(MachineInstr &MI, MachineInstr *&OtherMI);
|
||||
void applyCombineDivRem(MachineInstr &MI, MachineInstr *&OtherMI);
|
||||
|
||||
/// If a brcond's true block is not the fallthrough, make it so by inverting
|
||||
/// the condition and swapping operands.
|
||||
bool matchOptBrCondByInvertingCond(MachineInstr &MI, MachineInstr *&BrCond);
|
||||
void applyOptBrCondByInvertingCond(MachineInstr &MI, MachineInstr *&BrCond);
|
||||
|
||||
/// If \p MI is G_CONCAT_VECTORS, try to combine it.
|
||||
/// Returns true if MI changed.
|
||||
/// Right now, we support:
|
||||
/// - concat_vector(undef, undef) => undef
|
||||
/// - concat_vector(build_vector(A, B), build_vector(C, D)) =>
|
||||
/// build_vector(A, B, C, D)
|
||||
///
|
||||
/// \pre MI.getOpcode() == G_CONCAT_VECTORS.
|
||||
bool tryCombineConcatVectors(MachineInstr &MI);
|
||||
/// Check if the G_CONCAT_VECTORS \p MI is undef or if it
|
||||
/// can be flattened into a build_vector.
|
||||
/// In the first case \p IsUndef will be true.
|
||||
/// In the second case \p Ops will contain the operands needed
|
||||
/// to produce the flattened build_vector.
|
||||
///
|
||||
/// \pre MI.getOpcode() == G_CONCAT_VECTORS.
|
||||
bool matchCombineConcatVectors(MachineInstr &MI, bool &IsUndef,
|
||||
SmallVectorImpl<Register> &Ops);
|
||||
/// Replace \p MI with a flattened build_vector with \p Ops or an
|
||||
/// implicit_def if IsUndef is true.
|
||||
void applyCombineConcatVectors(MachineInstr &MI, bool IsUndef,
|
||||
const ArrayRef<Register> Ops);
|
||||
|
||||
/// Try to combine G_SHUFFLE_VECTOR into G_CONCAT_VECTORS.
|
||||
/// Returns true if MI changed.
|
||||
///
|
||||
/// \pre MI.getOpcode() == G_SHUFFLE_VECTOR.
|
||||
bool tryCombineShuffleVector(MachineInstr &MI);
|
||||
/// Check if the G_SHUFFLE_VECTOR \p MI can be replaced by a
|
||||
/// concat_vectors.
|
||||
/// \p Ops will contain the operands needed to produce the flattened
|
||||
/// concat_vectors.
|
||||
///
|
||||
/// \pre MI.getOpcode() == G_SHUFFLE_VECTOR.
|
||||
bool matchCombineShuffleVector(MachineInstr &MI,
|
||||
SmallVectorImpl<Register> &Ops);
|
||||
/// Replace \p MI with a concat_vectors with \p Ops.
|
||||
void applyCombineShuffleVector(MachineInstr &MI,
|
||||
const ArrayRef<Register> Ops);
|
||||
|
||||
/// Optimize memcpy intrinsics et al, e.g. constant len calls.
|
||||
/// /p MaxLen if non-zero specifies the max length of a mem libcall to inline.
|
||||
///
|
||||
/// For example (pre-indexed):
|
||||
///
|
||||
/// $addr = G_PTR_ADD $base, $offset
|
||||
/// [...]
|
||||
/// $val = G_LOAD $addr
|
||||
/// [...]
|
||||
/// $whatever = COPY $addr
|
||||
///
|
||||
/// -->
|
||||
///
|
||||
/// $val, $addr = G_INDEXED_LOAD $base, $offset, 1 (IsPre)
|
||||
/// [...]
|
||||
/// $whatever = COPY $addr
|
||||
///
|
||||
/// or (post-indexed):
|
||||
///
|
||||
/// G_STORE $val, $base
|
||||
/// [...]
|
||||
/// $addr = G_PTR_ADD $base, $offset
|
||||
/// [...]
|
||||
/// $whatever = COPY $addr
|
||||
///
|
||||
/// -->
|
||||
///
|
||||
/// $addr = G_INDEXED_STORE $val, $base, $offset
|
||||
/// [...]
|
||||
/// $whatever = COPY $addr
|
||||
bool tryCombineMemCpyFamily(MachineInstr &MI, unsigned MaxLen = 0);
|
||||
|
||||
bool matchPtrAddImmedChain(MachineInstr &MI, PtrAddChain &MatchInfo);
|
||||
void applyPtrAddImmedChain(MachineInstr &MI, PtrAddChain &MatchInfo);
|
||||
|
||||
/// Fold (shift (shift base, x), y) -> (shift base (x+y))
|
||||
bool matchShiftImmedChain(MachineInstr &MI, RegisterImmPair &MatchInfo);
|
||||
void applyShiftImmedChain(MachineInstr &MI, RegisterImmPair &MatchInfo);
|
||||
|
||||
/// If we have a shift-by-constant of a bitwise logic op that itself has a
|
||||
/// shift-by-constant operand with identical opcode, we may be able to convert
|
||||
/// that into 2 independent shifts followed by the logic op.
|
||||
bool matchShiftOfShiftedLogic(MachineInstr &MI,
|
||||
ShiftOfShiftedLogic &MatchInfo);
|
||||
void applyShiftOfShiftedLogic(MachineInstr &MI,
|
||||
ShiftOfShiftedLogic &MatchInfo);
|
||||
|
||||
/// Transform a multiply by a power-of-2 value to a left shift.
|
||||
bool matchCombineMulToShl(MachineInstr &MI, unsigned &ShiftVal);
|
||||
void applyCombineMulToShl(MachineInstr &MI, unsigned &ShiftVal);
|
||||
|
||||
// Transform a G_SHL with an extended source into a narrower shift if
|
||||
// possible.
|
||||
bool matchCombineShlOfExtend(MachineInstr &MI, RegisterImmPair &MatchData);
|
||||
void applyCombineShlOfExtend(MachineInstr &MI,
|
||||
const RegisterImmPair &MatchData);
|
||||
|
||||
/// Fold away a merge of an unmerge of the corresponding values.
|
||||
bool matchCombineMergeUnmerge(MachineInstr &MI, Register &MatchInfo);
|
||||
|
||||
/// Reduce a shift by a constant to an unmerge and a shift on a half sized
|
||||
/// type. This will not produce a shift smaller than \p TargetShiftSize.
|
||||
bool matchCombineShiftToUnmerge(MachineInstr &MI, unsigned TargetShiftSize,
|
||||
unsigned &ShiftVal);
|
||||
void applyCombineShiftToUnmerge(MachineInstr &MI, const unsigned &ShiftVal);
|
||||
bool tryCombineShiftToUnmerge(MachineInstr &MI, unsigned TargetShiftAmount);
|
||||
|
||||
/// Transform <ty,...> G_UNMERGE(G_MERGE ty X, Y, Z) -> ty X, Y, Z.
|
||||
bool
|
||||
matchCombineUnmergeMergeToPlainValues(MachineInstr &MI,
|
||||
SmallVectorImpl<Register> &Operands);
|
||||
void
|
||||
applyCombineUnmergeMergeToPlainValues(MachineInstr &MI,
|
||||
SmallVectorImpl<Register> &Operands);
|
||||
|
||||
/// Transform G_UNMERGE Constant -> Constant1, Constant2, ...
|
||||
bool matchCombineUnmergeConstant(MachineInstr &MI,
|
||||
SmallVectorImpl<APInt> &Csts);
|
||||
void applyCombineUnmergeConstant(MachineInstr &MI,
|
||||
SmallVectorImpl<APInt> &Csts);
|
||||
|
||||
/// Transform G_UNMERGE G_IMPLICIT_DEF -> G_IMPLICIT_DEF, G_IMPLICIT_DEF, ...
|
||||
bool
|
||||
matchCombineUnmergeUndef(MachineInstr &MI,
|
||||
std::function<void(MachineIRBuilder &)> &MatchInfo);
|
||||
|
||||
/// Transform X, Y<dead> = G_UNMERGE Z -> X = G_TRUNC Z.
|
||||
bool matchCombineUnmergeWithDeadLanesToTrunc(MachineInstr &MI);
|
||||
void applyCombineUnmergeWithDeadLanesToTrunc(MachineInstr &MI);
|
||||
|
||||
/// Transform X, Y = G_UNMERGE(G_ZEXT(Z)) -> X = G_ZEXT(Z); Y = G_CONSTANT 0
|
||||
bool matchCombineUnmergeZExtToZExt(MachineInstr &MI);
|
||||
void applyCombineUnmergeZExtToZExt(MachineInstr &MI);
|
||||
|
||||
/// Transform fp_instr(cst) to constant result of the fp operation.
|
||||
bool matchCombineConstantFoldFpUnary(MachineInstr &MI,
|
||||
Optional<APFloat> &Cst);
|
||||
void applyCombineConstantFoldFpUnary(MachineInstr &MI,
|
||||
Optional<APFloat> &Cst);
|
||||
|
||||
/// Transform IntToPtr(PtrToInt(x)) to x if cast is in the same address space.
|
||||
bool matchCombineI2PToP2I(MachineInstr &MI, Register &Reg);
|
||||
void applyCombineI2PToP2I(MachineInstr &MI, Register &Reg);
|
||||
|
||||
/// Transform PtrToInt(IntToPtr(x)) to x.
|
||||
bool matchCombineP2IToI2P(MachineInstr &MI, Register &Reg);
|
||||
void applyCombineP2IToI2P(MachineInstr &MI, Register &Reg);
|
||||
|
||||
/// Transform G_ADD (G_PTRTOINT x), y -> G_PTRTOINT (G_PTR_ADD x, y)
|
||||
/// Transform G_ADD y, (G_PTRTOINT x) -> G_PTRTOINT (G_PTR_ADD x, y)
|
||||
bool matchCombineAddP2IToPtrAdd(MachineInstr &MI,
|
||||
std::pair<Register, bool> &PtrRegAndCommute);
|
||||
void applyCombineAddP2IToPtrAdd(MachineInstr &MI,
|
||||
std::pair<Register, bool> &PtrRegAndCommute);
|
||||
|
||||
// Transform G_PTR_ADD (G_PTRTOINT C1), C2 -> C1 + C2
|
||||
bool matchCombineConstPtrAddToI2P(MachineInstr &MI, APInt &NewCst);
|
||||
void applyCombineConstPtrAddToI2P(MachineInstr &MI, APInt &NewCst);
|
||||
|
||||
/// Transform anyext(trunc(x)) to x.
|
||||
bool matchCombineAnyExtTrunc(MachineInstr &MI, Register &Reg);
|
||||
void applyCombineAnyExtTrunc(MachineInstr &MI, Register &Reg);
|
||||
|
||||
/// Transform zext(trunc(x)) to x.
|
||||
bool matchCombineZextTrunc(MachineInstr &MI, Register &Reg);
|
||||
|
||||
/// Transform [asz]ext([asz]ext(x)) to [asz]ext x.
|
||||
bool matchCombineExtOfExt(MachineInstr &MI,
|
||||
std::tuple<Register, unsigned> &MatchInfo);
|
||||
void applyCombineExtOfExt(MachineInstr &MI,
|
||||
std::tuple<Register, unsigned> &MatchInfo);
|
||||
|
||||
/// Transform fneg(fneg(x)) to x.
|
||||
bool matchCombineFNegOfFNeg(MachineInstr &MI, Register &Reg);
|
||||
|
||||
/// Match fabs(fabs(x)) to fabs(x).
|
||||
bool matchCombineFAbsOfFAbs(MachineInstr &MI, Register &Src);
|
||||
void applyCombineFAbsOfFAbs(MachineInstr &MI, Register &Src);
|
||||
|
||||
/// Transform fabs(fneg(x)) to fabs(x).
|
||||
bool matchCombineFAbsOfFNeg(MachineInstr &MI, BuildFnTy &MatchInfo);
|
||||
|
||||
/// Transform trunc ([asz]ext x) to x or ([asz]ext x) or (trunc x).
|
||||
bool matchCombineTruncOfExt(MachineInstr &MI,
|
||||
std::pair<Register, unsigned> &MatchInfo);
|
||||
void applyCombineTruncOfExt(MachineInstr &MI,
|
||||
std::pair<Register, unsigned> &MatchInfo);
|
||||
|
||||
/// Transform trunc (shl x, K) to shl (trunc x),
|
||||
/// K => K < VT.getScalarSizeInBits().
|
||||
bool matchCombineTruncOfShl(MachineInstr &MI,
|
||||
std::pair<Register, Register> &MatchInfo);
|
||||
void applyCombineTruncOfShl(MachineInstr &MI,
|
||||
std::pair<Register, Register> &MatchInfo);
|
||||
|
||||
/// Transform G_MUL(x, -1) to G_SUB(0, x)
|
||||
void applyCombineMulByNegativeOne(MachineInstr &MI);
|
||||
|
||||
/// Return true if any explicit use operand on \p MI is defined by a
|
||||
/// G_IMPLICIT_DEF.
|
||||
bool matchAnyExplicitUseIsUndef(MachineInstr &MI);
|
||||
|
||||
/// Return true if all register explicit use operands on \p MI are defined by
|
||||
/// a G_IMPLICIT_DEF.
|
||||
bool matchAllExplicitUsesAreUndef(MachineInstr &MI);
|
||||
|
||||
/// Return true if a G_SHUFFLE_VECTOR instruction \p MI has an undef mask.
|
||||
bool matchUndefShuffleVectorMask(MachineInstr &MI);
|
||||
|
||||
/// Return true if a G_STORE instruction \p MI is storing an undef value.
|
||||
bool matchUndefStore(MachineInstr &MI);
|
||||
|
||||
/// Return true if a G_SELECT instruction \p MI has an undef comparison.
|
||||
bool matchUndefSelectCmp(MachineInstr &MI);
|
||||
|
||||
/// Return true if a G_SELECT instruction \p MI has a constant comparison. If
|
||||
/// true, \p OpIdx will store the operand index of the known selected value.
|
||||
bool matchConstantSelectCmp(MachineInstr &MI, unsigned &OpIdx);
|
||||
|
||||
/// Replace an instruction with a G_FCONSTANT with value \p C.
|
||||
bool replaceInstWithFConstant(MachineInstr &MI, double C);
|
||||
|
||||
/// Replace an instruction with a G_CONSTANT with value \p C.
|
||||
bool replaceInstWithConstant(MachineInstr &MI, int64_t C);
|
||||
|
||||
/// Replace an instruction with a G_CONSTANT with value \p C.
|
||||
bool replaceInstWithConstant(MachineInstr &MI, APInt C);
|
||||
|
||||
/// Replace an instruction with a G_IMPLICIT_DEF.
|
||||
bool replaceInstWithUndef(MachineInstr &MI);
|
||||
|
||||
/// Delete \p MI and replace all of its uses with its \p OpIdx-th operand.
|
||||
bool replaceSingleDefInstWithOperand(MachineInstr &MI, unsigned OpIdx);
|
||||
|
||||
/// Delete \p MI and replace all of its uses with \p Replacement.
|
||||
bool replaceSingleDefInstWithReg(MachineInstr &MI, Register Replacement);
|
||||
|
||||
/// Return true if \p MOP1 and \p MOP2 are register operands are defined by
|
||||
/// equivalent instructions.
|
||||
bool matchEqualDefs(const MachineOperand &MOP1, const MachineOperand &MOP2);
|
||||
|
||||
/// Return true if \p MOP is defined by a G_CONSTANT with a value equal to
|
||||
/// \p C.
|
||||
bool matchConstantOp(const MachineOperand &MOP, int64_t C);
|
||||
|
||||
/// Optimize (cond ? x : x) -> x
|
||||
bool matchSelectSameVal(MachineInstr &MI);
|
||||
|
||||
/// Optimize (x op x) -> x
|
||||
bool matchBinOpSameVal(MachineInstr &MI);
|
||||
|
||||
/// Check if operand \p OpIdx is zero.
|
||||
bool matchOperandIsZero(MachineInstr &MI, unsigned OpIdx);
|
||||
|
||||
/// Check if operand \p OpIdx is undef.
|
||||
bool matchOperandIsUndef(MachineInstr &MI, unsigned OpIdx);
|
||||
|
||||
/// Check if operand \p OpIdx is known to be a power of 2.
|
||||
bool matchOperandIsKnownToBeAPowerOfTwo(MachineInstr &MI, unsigned OpIdx);
|
||||
|
||||
/// Erase \p MI
|
||||
bool eraseInst(MachineInstr &MI);
|
||||
|
||||
/// Return true if MI is a G_ADD which can be simplified to a G_SUB.
|
||||
bool matchSimplifyAddToSub(MachineInstr &MI,
|
||||
std::tuple<Register, Register> &MatchInfo);
|
||||
void applySimplifyAddToSub(MachineInstr &MI,
|
||||
std::tuple<Register, Register> &MatchInfo);
|
||||
|
||||
/// Match (logic_op (op x...), (op y...)) -> (op (logic_op x, y))
|
||||
bool
|
||||
matchHoistLogicOpWithSameOpcodeHands(MachineInstr &MI,
|
||||
InstructionStepsMatchInfo &MatchInfo);
|
||||
|
||||
/// Replace \p MI with a series of instructions described in \p MatchInfo.
|
||||
void applyBuildInstructionSteps(MachineInstr &MI,
|
||||
InstructionStepsMatchInfo &MatchInfo);
|
||||
|
||||
/// Match ashr (shl x, C), C -> sext_inreg (C)
|
||||
bool matchAshrShlToSextInreg(MachineInstr &MI,
|
||||
std::tuple<Register, int64_t> &MatchInfo);
|
||||
void applyAshShlToSextInreg(MachineInstr &MI,
|
||||
std::tuple<Register, int64_t> &MatchInfo);
|
||||
|
||||
/// Fold and(and(x, C1), C2) -> C1&C2 ? and(x, C1&C2) : 0
|
||||
bool matchOverlappingAnd(MachineInstr &MI,
|
||||
BuildFnTy &MatchInfo);
|
||||
|
||||
/// \return true if \p MI is a G_AND instruction whose operands are x and y
|
||||
/// where x & y == x or x & y == y. (E.g., one of operands is all-ones value.)
|
||||
///
|
||||
/// \param [in] MI - The G_AND instruction.
|
||||
/// \param [out] Replacement - A register the G_AND should be replaced with on
|
||||
/// success.
|
||||
bool matchRedundantAnd(MachineInstr &MI, Register &Replacement);
|
||||
|
||||
/// \return true if \p MI is a G_OR instruction whose operands are x and y
|
||||
/// where x | y == x or x | y == y. (E.g., one of operands is all-zeros
|
||||
/// value.)
|
||||
///
|
||||
/// \param [in] MI - The G_OR instruction.
|
||||
/// \param [out] Replacement - A register the G_OR should be replaced with on
|
||||
/// success.
|
||||
bool matchRedundantOr(MachineInstr &MI, Register &Replacement);
|
||||
|
||||
/// \return true if \p MI is a G_SEXT_INREG that can be erased.
|
||||
bool matchRedundantSExtInReg(MachineInstr &MI);
|
||||
|
||||
/// Combine inverting a result of a compare into the opposite cond code.
|
||||
bool matchNotCmp(MachineInstr &MI, SmallVectorImpl<Register> &RegsToNegate);
|
||||
void applyNotCmp(MachineInstr &MI, SmallVectorImpl<Register> &RegsToNegate);
|
||||
|
||||
/// Fold (xor (and x, y), y) -> (and (not x), y)
|
||||
///{
|
||||
bool matchXorOfAndWithSameReg(MachineInstr &MI,
|
||||
std::pair<Register, Register> &MatchInfo);
|
||||
void applyXorOfAndWithSameReg(MachineInstr &MI,
|
||||
std::pair<Register, Register> &MatchInfo);
|
||||
///}
|
||||
|
||||
/// Combine G_PTR_ADD with nullptr to G_INTTOPTR
|
||||
bool matchPtrAddZero(MachineInstr &MI);
|
||||
void applyPtrAddZero(MachineInstr &MI);
|
||||
|
||||
/// Combine G_UREM x, (known power of 2) to an add and bitmasking.
|
||||
void applySimplifyURemByPow2(MachineInstr &MI);
|
||||
|
||||
bool matchCombineInsertVecElts(MachineInstr &MI,
|
||||
SmallVectorImpl<Register> &MatchInfo);
|
||||
|
||||
void applyCombineInsertVecElts(MachineInstr &MI,
|
||||
SmallVectorImpl<Register> &MatchInfo);
|
||||
|
||||
/// Match expression trees of the form
|
||||
///
|
||||
/// \code
|
||||
/// sN *a = ...
|
||||
/// sM val = a[0] | (a[1] << N) | (a[2] << 2N) | (a[3] << 3N) ...
|
||||
/// \endcode
|
||||
///
|
||||
/// And check if the tree can be replaced with a M-bit load + possibly a
|
||||
/// bswap.
|
||||
bool matchLoadOrCombine(MachineInstr &MI, BuildFnTy &MatchInfo);
|
||||
|
||||
bool matchTruncStoreMerge(MachineInstr &MI, MergeTruncStoresInfo &MatchInfo);
|
||||
void applyTruncStoreMerge(MachineInstr &MI, MergeTruncStoresInfo &MatchInfo);
|
||||
|
||||
bool matchExtendThroughPhis(MachineInstr &MI, MachineInstr *&ExtMI);
|
||||
void applyExtendThroughPhis(MachineInstr &MI, MachineInstr *&ExtMI);
|
||||
|
||||
bool matchExtractVecEltBuildVec(MachineInstr &MI, Register &Reg);
|
||||
void applyExtractVecEltBuildVec(MachineInstr &MI, Register &Reg);
|
||||
|
||||
bool matchExtractAllEltsFromBuildVector(
|
||||
MachineInstr &MI,
|
||||
SmallVectorImpl<std::pair<Register, MachineInstr *>> &MatchInfo);
|
||||
void applyExtractAllEltsFromBuildVector(
|
||||
MachineInstr &MI,
|
||||
SmallVectorImpl<std::pair<Register, MachineInstr *>> &MatchInfo);
|
||||
|
||||
/// Use a function which takes in a MachineIRBuilder to perform a combine.
|
||||
/// By default, it erases the instruction \p MI from the function.
|
||||
void applyBuildFn(MachineInstr &MI, BuildFnTy &MatchInfo);
|
||||
/// Use a function which takes in a MachineIRBuilder to perform a combine.
|
||||
/// This variant does not erase \p MI after calling the build function.
|
||||
void applyBuildFnNoErase(MachineInstr &MI, BuildFnTy &MatchInfo);
|
||||
|
||||
bool matchOrShiftToFunnelShift(MachineInstr &MI, BuildFnTy &MatchInfo);
|
||||
bool matchFunnelShiftToRotate(MachineInstr &MI);
|
||||
void applyFunnelShiftToRotate(MachineInstr &MI);
|
||||
bool matchRotateOutOfRange(MachineInstr &MI);
|
||||
void applyRotateOutOfRange(MachineInstr &MI);
|
||||
|
||||
/// \returns true if a G_ICMP instruction \p MI can be replaced with a true
|
||||
/// or false constant based off of KnownBits information.
|
||||
bool matchICmpToTrueFalseKnownBits(MachineInstr &MI, int64_t &MatchInfo);
|
||||
|
||||
/// \returns true if a G_ICMP \p MI can be replaced with its LHS based off of
|
||||
/// KnownBits information.
|
||||
bool
|
||||
matchICmpToLHSKnownBits(MachineInstr &MI,
|
||||
BuildFnTy &MatchInfo);
|
||||
|
||||
/// \returns true if (and (or x, c1), c2) can be replaced with (and x, c2)
|
||||
bool matchAndOrDisjointMask(MachineInstr &MI, BuildFnTy &MatchInfo);
|
||||
|
||||
bool matchBitfieldExtractFromSExtInReg(MachineInstr &MI,
|
||||
BuildFnTy &MatchInfo);
|
||||
/// Match: and (lshr x, cst), mask -> ubfx x, cst, width
|
||||
bool matchBitfieldExtractFromAnd(MachineInstr &MI, BuildFnTy &MatchInfo);
|
||||
|
||||
/// Match: shr (shl x, n), k -> sbfx/ubfx x, pos, width
|
||||
bool matchBitfieldExtractFromShr(MachineInstr &MI, BuildFnTy &MatchInfo);
|
||||
|
||||
/// Match: shr (and x, n), k -> ubfx x, pos, width
|
||||
bool matchBitfieldExtractFromShrAnd(MachineInstr &MI, BuildFnTy &MatchInfo);
|
||||
|
||||
// Helpers for reassociation:
|
||||
bool matchReassocConstantInnerRHS(GPtrAdd &MI, MachineInstr *RHS,
|
||||
BuildFnTy &MatchInfo);
|
||||
bool matchReassocFoldConstantsInSubTree(GPtrAdd &MI, MachineInstr *LHS,
|
||||
MachineInstr *RHS,
|
||||
BuildFnTy &MatchInfo);
|
||||
bool matchReassocConstantInnerLHS(GPtrAdd &MI, MachineInstr *LHS,
|
||||
MachineInstr *RHS, BuildFnTy &MatchInfo);
|
||||
/// Reassociate pointer calculations with G_ADD involved, to allow better
|
||||
/// addressing mode usage.
|
||||
bool matchReassocPtrAdd(MachineInstr &MI, BuildFnTy &MatchInfo);
|
||||
|
||||
/// Do constant folding when opportunities are exposed after MIR building.
|
||||
bool matchConstantFold(MachineInstr &MI, APInt &MatchInfo);
|
||||
|
||||
/// \returns true if it is possible to narrow the width of a scalar binop
|
||||
/// feeding a G_AND instruction \p MI.
|
||||
bool matchNarrowBinopFeedingAnd(MachineInstr &MI, BuildFnTy &MatchInfo);
|
||||
|
||||
/// Given an G_UDIV \p MI expressing a divide by constant, return an
|
||||
/// expression that implements it by multiplying by a magic number.
|
||||
/// Ref: "Hacker's Delight" or "The PowerPC Compiler Writer's Guide".
|
||||
MachineInstr *buildUDivUsingMul(MachineInstr &MI);
|
||||
/// Combine G_UDIV by constant into a multiply by magic constant.
|
||||
bool matchUDivByConst(MachineInstr &MI);
|
||||
void applyUDivByConst(MachineInstr &MI);
|
||||
|
||||
// G_UMULH x, (1 << c)) -> x >> (bitwidth - c)
|
||||
bool matchUMulHToLShr(MachineInstr &MI);
|
||||
void applyUMulHToLShr(MachineInstr &MI);
|
||||
|
||||
/// Try to transform \p MI by using all of the above
|
||||
/// combine functions. Returns true if changed.
|
||||
bool tryCombine(MachineInstr &MI);
|
||||
|
||||
/// Emit loads and stores that perform the given memcpy.
|
||||
/// Assumes \p MI is a G_MEMCPY_INLINE
|
||||
/// TODO: implement dynamically sized inline memcpy,
|
||||
/// and rename: s/bool tryEmit/void emit/
|
||||
bool tryEmitMemcpyInline(MachineInstr &MI);
|
||||
|
||||
/// Match:
|
||||
/// (G_UMULO x, 2) -> (G_UADDO x, x)
|
||||
/// (G_SMULO x, 2) -> (G_SADDO x, x)
|
||||
bool matchMulOBy2(MachineInstr &MI, BuildFnTy &MatchInfo);
|
||||
|
||||
/// Transform (fadd x, fneg(y)) -> (fsub x, y)
|
||||
/// (fadd fneg(x), y) -> (fsub y, x)
|
||||
/// (fsub x, fneg(y)) -> (fadd x, y)
|
||||
/// (fmul fneg(x), fneg(y)) -> (fmul x, y)
|
||||
/// (fdiv fneg(x), fneg(y)) -> (fdiv x, y)
|
||||
/// (fmad fneg(x), fneg(y), z) -> (fmad x, y, z)
|
||||
/// (fma fneg(x), fneg(y), z) -> (fma x, y, z)
|
||||
bool matchRedundantNegOperands(MachineInstr &MI, BuildFnTy &MatchInfo);
|
||||
|
||||
bool canCombineFMadOrFMA(MachineInstr &MI, bool &AllowFusionGlobally,
|
||||
bool &HasFMAD, bool &Aggressive,
|
||||
bool CanReassociate = false);
|
||||
|
||||
/// Transform (fadd (fmul x, y), z) -> (fma x, y, z)
|
||||
/// (fadd (fmul x, y), z) -> (fmad x, y, z)
|
||||
bool matchCombineFAddFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo);
|
||||
|
||||
/// Transform (fadd (fpext (fmul x, y)), z) -> (fma (fpext x), (fpext y), z)
|
||||
/// (fadd (fpext (fmul x, y)), z) -> (fmad (fpext x), (fpext y), z)
|
||||
bool matchCombineFAddFpExtFMulToFMadOrFMA(MachineInstr &MI,
|
||||
BuildFnTy &MatchInfo);
|
||||
|
||||
/// Transform (fadd (fma x, y, (fmul u, v)), z) -> (fma x, y, (fma u, v, z))
|
||||
/// (fadd (fmad x, y, (fmul u, v)), z) -> (fmad x, y, (fmad u, v, z))
|
||||
bool matchCombineFAddFMAFMulToFMadOrFMA(MachineInstr &MI,
|
||||
BuildFnTy &MatchInfo);
|
||||
|
||||
// Transform (fadd (fma x, y, (fpext (fmul u, v))), z)
|
||||
// -> (fma x, y, (fma (fpext u), (fpext v), z))
|
||||
// (fadd (fmad x, y, (fpext (fmul u, v))), z)
|
||||
// -> (fmad x, y, (fmad (fpext u), (fpext v), z))
|
||||
bool matchCombineFAddFpExtFMulToFMadOrFMAAggressive(MachineInstr &MI,
|
||||
BuildFnTy &MatchInfo);
|
||||
|
||||
/// Transform (fsub (fmul x, y), z) -> (fma x, y, -z)
|
||||
/// (fsub (fmul x, y), z) -> (fmad x, y, -z)
|
||||
bool matchCombineFSubFMulToFMadOrFMA(MachineInstr &MI, BuildFnTy &MatchInfo);
|
||||
|
||||
/// Transform (fsub (fneg (fmul, x, y)), z) -> (fma (fneg x), y, (fneg z))
|
||||
/// (fsub (fneg (fmul, x, y)), z) -> (fmad (fneg x), y, (fneg z))
|
||||
bool matchCombineFSubFNegFMulToFMadOrFMA(MachineInstr &MI,
|
||||
BuildFnTy &MatchInfo);
|
||||
|
||||
/// Transform (fsub (fpext (fmul x, y)), z)
|
||||
/// -> (fma (fpext x), (fpext y), (fneg z))
|
||||
/// (fsub (fpext (fmul x, y)), z)
|
||||
/// -> (fmad (fpext x), (fpext y), (fneg z))
|
||||
bool matchCombineFSubFpExtFMulToFMadOrFMA(MachineInstr &MI,
|
||||
BuildFnTy &MatchInfo);
|
||||
|
||||
/// Transform (fsub (fpext (fneg (fmul x, y))), z)
|
||||
/// -> (fneg (fma (fpext x), (fpext y), z))
|
||||
/// (fsub (fpext (fneg (fmul x, y))), z)
|
||||
/// -> (fneg (fmad (fpext x), (fpext y), z))
|
||||
bool matchCombineFSubFpExtFNegFMulToFMadOrFMA(MachineInstr &MI,
|
||||
BuildFnTy &MatchInfo);
|
||||
|
||||
private:
|
||||
/// Given a non-indexed load or store instruction \p MI, find an offset that
|
||||
/// can be usefully and legally folded into it as a post-indexing operation.
|
||||
///
|
||||
/// \returns true if a candidate is found.
|
||||
bool findPostIndexCandidate(MachineInstr &MI, Register &Addr, Register &Base,
|
||||
Register &Offset);
|
||||
|
||||
/// Given a non-indexed load or store instruction \p MI, find an offset that
|
||||
/// can be usefully and legally folded into it as a pre-indexing operation.
|
||||
///
|
||||
/// \returns true if a candidate is found.
|
||||
bool findPreIndexCandidate(MachineInstr &MI, Register &Addr, Register &Base,
|
||||
Register &Offset);
|
||||
|
||||
/// Helper function for matchLoadOrCombine. Searches for Registers
|
||||
/// which may have been produced by a load instruction + some arithmetic.
|
||||
///
|
||||
/// \param [in] Root - The search root.
|
||||
///
|
||||
/// \returns The Registers found during the search.
|
||||
Optional<SmallVector<Register, 8>>
|
||||
findCandidatesForLoadOrCombine(const MachineInstr *Root) const;
|
||||
|
||||
/// Helper function for matchLoadOrCombine.
|
||||
///
|
||||
/// Checks if every register in \p RegsToVisit is defined by a load
|
||||
/// instruction + some arithmetic.
|
||||
///
|
||||
/// \param [out] MemOffset2Idx - Maps the byte positions each load ends up
|
||||
/// at to the index of the load.
|
||||
/// \param [in] MemSizeInBits - The number of bits each load should produce.
|
||||
///
|
||||
/// \returns On success, a 3-tuple containing lowest-index load found, the
|
||||
/// lowest index, and the last load in the sequence.
|
||||
Optional<std::tuple<GZExtLoad *, int64_t, GZExtLoad *>>
|
||||
findLoadOffsetsForLoadOrCombine(
|
||||
SmallDenseMap<int64_t, int64_t, 8> &MemOffset2Idx,
|
||||
const SmallVector<Register, 8> &RegsToVisit,
|
||||
const unsigned MemSizeInBits);
|
||||
|
||||
/// Examines the G_PTR_ADD instruction \p PtrAdd and determines if performing
|
||||
/// a re-association of its operands would break an existing legal addressing
|
||||
/// mode that the address computation currently represents.
|
||||
bool reassociationCanBreakAddressingModePattern(MachineInstr &PtrAdd);
|
||||
};
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
71
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/CombinerInfo.h
vendored
Normal file
71
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/CombinerInfo.h
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
//===- llvm/CodeGen/GlobalISel/CombinerInfo.h ------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// Interface for Targets to specify which operations are combined how and when.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_COMBINERINFO_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_COMBINERINFO_H
|
||||
|
||||
#include <cassert>
|
||||
namespace llvm {
|
||||
|
||||
class GISelChangeObserver;
|
||||
class LegalizerInfo;
|
||||
class MachineInstr;
|
||||
class MachineIRBuilder;
|
||||
|
||||
// Contains information relevant to enabling/disabling various combines for a
|
||||
// pass.
|
||||
class CombinerInfo {
|
||||
public:
|
||||
CombinerInfo(bool AllowIllegalOps, bool ShouldLegalizeIllegal,
|
||||
const LegalizerInfo *LInfo, bool OptEnabled, bool OptSize,
|
||||
bool MinSize)
|
||||
: IllegalOpsAllowed(AllowIllegalOps),
|
||||
LegalizeIllegalOps(ShouldLegalizeIllegal), LInfo(LInfo),
|
||||
EnableOpt(OptEnabled), EnableOptSize(OptSize), EnableMinSize(MinSize) {
|
||||
assert(((AllowIllegalOps || !LegalizeIllegalOps) || LInfo) &&
|
||||
"Expecting legalizerInfo when illegalops not allowed");
|
||||
}
|
||||
virtual ~CombinerInfo() = default;
|
||||
/// If \p IllegalOpsAllowed is false, the CombinerHelper will make use of
|
||||
/// the legalizerInfo to check for legality before each transformation.
|
||||
bool IllegalOpsAllowed; // TODO: Make use of this.
|
||||
|
||||
/// If \p LegalizeIllegalOps is true, the Combiner will also legalize the
|
||||
/// illegal ops that are created.
|
||||
bool LegalizeIllegalOps; // TODO: Make use of this.
|
||||
const LegalizerInfo *LInfo;
|
||||
|
||||
/// Whether optimizations should be enabled. This is to distinguish between
|
||||
/// uses of the combiner unconditionally and only when optimizations are
|
||||
/// specifically enabled/
|
||||
bool EnableOpt;
|
||||
/// Whether we're optimizing for size.
|
||||
bool EnableOptSize;
|
||||
/// Whether we're optimizing for minsize (-Oz).
|
||||
bool EnableMinSize;
|
||||
|
||||
/// Attempt to combine instructions using MI as the root.
|
||||
///
|
||||
/// Use Observer to report the creation, modification, and erasure of
|
||||
/// instructions. GISelChangeObserver will automatically report certain
|
||||
/// kinds of operations. These operations are:
|
||||
/// * Instructions that are newly inserted into the MachineFunction
|
||||
/// * Instructions that are erased from the MachineFunction.
|
||||
///
|
||||
/// However, it is important to report instruction modification and this is
|
||||
/// not automatic.
|
||||
virtual bool combine(GISelChangeObserver &Observer, MachineInstr &MI,
|
||||
MachineIRBuilder &B) const = 0;
|
||||
};
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
140
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/GISelChangeObserver.h
vendored
Normal file
140
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/GISelChangeObserver.h
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
//===----- llvm/CodeGen/GlobalISel/GISelChangeObserver.h --------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// This contains common code to allow clients to notify changes to machine
|
||||
/// instr.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_GISELCHANGEOBSERVER_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_GISELCHANGEOBSERVER_H
|
||||
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
|
||||
namespace llvm {
|
||||
class MachineInstr;
|
||||
class MachineRegisterInfo;
|
||||
|
||||
/// Abstract class that contains various methods for clients to notify about
|
||||
/// changes. This should be the preferred way for APIs to notify changes.
|
||||
/// Typically calling erasingInstr/createdInstr multiple times should not affect
|
||||
/// the result. The observer would likely need to check if it was already
|
||||
/// notified earlier (consider using GISelWorkList).
|
||||
class GISelChangeObserver {
|
||||
SmallPtrSet<MachineInstr *, 4> ChangingAllUsesOfReg;
|
||||
|
||||
public:
|
||||
virtual ~GISelChangeObserver() = default;
|
||||
|
||||
/// An instruction is about to be erased.
|
||||
virtual void erasingInstr(MachineInstr &MI) = 0;
|
||||
|
||||
/// An instruction has been created and inserted into the function.
|
||||
/// Note that the instruction might not be a fully fledged instruction at this
|
||||
/// point and won't be if the MachineFunction::Delegate is calling it. This is
|
||||
/// because the delegate only sees the construction of the MachineInstr before
|
||||
/// operands have been added.
|
||||
virtual void createdInstr(MachineInstr &MI) = 0;
|
||||
|
||||
/// This instruction is about to be mutated in some way.
|
||||
virtual void changingInstr(MachineInstr &MI) = 0;
|
||||
|
||||
/// This instruction was mutated in some way.
|
||||
virtual void changedInstr(MachineInstr &MI) = 0;
|
||||
|
||||
/// All the instructions using the given register are being changed.
|
||||
/// For convenience, finishedChangingAllUsesOfReg() will report the completion
|
||||
/// of the changes. The use list may change between this call and
|
||||
/// finishedChangingAllUsesOfReg().
|
||||
void changingAllUsesOfReg(const MachineRegisterInfo &MRI, Register Reg);
|
||||
/// All instructions reported as changing by changingAllUsesOfReg() have
|
||||
/// finished being changed.
|
||||
void finishedChangingAllUsesOfReg();
|
||||
|
||||
};
|
||||
|
||||
/// Simple wrapper observer that takes several observers, and calls
|
||||
/// each one for each event. If there are multiple observers (say CSE,
|
||||
/// Legalizer, Combiner), it's sufficient to register this to the machine
|
||||
/// function as the delegate.
|
||||
class GISelObserverWrapper : public MachineFunction::Delegate,
|
||||
public GISelChangeObserver {
|
||||
SmallVector<GISelChangeObserver *, 4> Observers;
|
||||
|
||||
public:
|
||||
GISelObserverWrapper() = default;
|
||||
GISelObserverWrapper(ArrayRef<GISelChangeObserver *> Obs)
|
||||
: Observers(Obs.begin(), Obs.end()) {}
|
||||
// Adds an observer.
|
||||
void addObserver(GISelChangeObserver *O) { Observers.push_back(O); }
|
||||
// Removes an observer from the list and does nothing if observer is not
|
||||
// present.
|
||||
void removeObserver(GISelChangeObserver *O) {
|
||||
auto It = std::find(Observers.begin(), Observers.end(), O);
|
||||
if (It != Observers.end())
|
||||
Observers.erase(It);
|
||||
}
|
||||
// API for Observer.
|
||||
void erasingInstr(MachineInstr &MI) override {
|
||||
for (auto &O : Observers)
|
||||
O->erasingInstr(MI);
|
||||
}
|
||||
void createdInstr(MachineInstr &MI) override {
|
||||
for (auto &O : Observers)
|
||||
O->createdInstr(MI);
|
||||
}
|
||||
void changingInstr(MachineInstr &MI) override {
|
||||
for (auto &O : Observers)
|
||||
O->changingInstr(MI);
|
||||
}
|
||||
void changedInstr(MachineInstr &MI) override {
|
||||
for (auto &O : Observers)
|
||||
O->changedInstr(MI);
|
||||
}
|
||||
// API for MachineFunction::Delegate
|
||||
void MF_HandleInsertion(MachineInstr &MI) override { createdInstr(MI); }
|
||||
void MF_HandleRemoval(MachineInstr &MI) override { erasingInstr(MI); }
|
||||
};
|
||||
|
||||
/// A simple RAII based Delegate installer.
|
||||
/// Use this in a scope to install a delegate to the MachineFunction and reset
|
||||
/// it at the end of the scope.
|
||||
class RAIIDelegateInstaller {
|
||||
MachineFunction &MF;
|
||||
MachineFunction::Delegate *Delegate;
|
||||
|
||||
public:
|
||||
RAIIDelegateInstaller(MachineFunction &MF, MachineFunction::Delegate *Del);
|
||||
~RAIIDelegateInstaller();
|
||||
};
|
||||
|
||||
/// A simple RAII based Observer installer.
|
||||
/// Use this in a scope to install the Observer to the MachineFunction and reset
|
||||
/// it at the end of the scope.
|
||||
class RAIIMFObserverInstaller {
|
||||
MachineFunction &MF;
|
||||
|
||||
public:
|
||||
RAIIMFObserverInstaller(MachineFunction &MF, GISelChangeObserver &Observer);
|
||||
~RAIIMFObserverInstaller();
|
||||
};
|
||||
|
||||
/// Class to install both of the above.
|
||||
class RAIIMFObsDelInstaller {
|
||||
RAIIDelegateInstaller DelI;
|
||||
RAIIMFObserverInstaller ObsI;
|
||||
|
||||
public:
|
||||
RAIIMFObsDelInstaller(MachineFunction &MF, GISelObserverWrapper &Wrapper)
|
||||
: DelI(MF, &Wrapper), ObsI(MF, Wrapper) {}
|
||||
~RAIIMFObsDelInstaller() = default;
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
#endif
|
||||
132
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/GISelKnownBits.h
vendored
Normal file
132
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/GISelKnownBits.h
vendored
Normal file
@@ -0,0 +1,132 @@
|
||||
//===- llvm/CodeGen/GlobalISel/GISelKnownBits.h ---------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// Provides analysis for querying information about KnownBits during GISel
|
||||
/// passes.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_GISELKNOWNBITS_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_GISELKNOWNBITS_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/Register.h"
|
||||
#include "llvm/InitializePasses.h"
|
||||
#include "llvm/Support/KnownBits.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class TargetLowering;
|
||||
class DataLayout;
|
||||
|
||||
class GISelKnownBits : public GISelChangeObserver {
|
||||
MachineFunction &MF;
|
||||
MachineRegisterInfo &MRI;
|
||||
const TargetLowering &TL;
|
||||
const DataLayout &DL;
|
||||
unsigned MaxDepth;
|
||||
/// Cache maintained during a computeKnownBits request.
|
||||
SmallDenseMap<Register, KnownBits, 16> ComputeKnownBitsCache;
|
||||
|
||||
void computeKnownBitsMin(Register Src0, Register Src1, KnownBits &Known,
|
||||
const APInt &DemandedElts,
|
||||
unsigned Depth = 0);
|
||||
|
||||
unsigned computeNumSignBitsMin(Register Src0, Register Src1,
|
||||
const APInt &DemandedElts, unsigned Depth = 0);
|
||||
|
||||
public:
|
||||
GISelKnownBits(MachineFunction &MF, unsigned MaxDepth = 6);
|
||||
virtual ~GISelKnownBits() = default;
|
||||
|
||||
const MachineFunction &getMachineFunction() const {
|
||||
return MF;
|
||||
}
|
||||
|
||||
const DataLayout &getDataLayout() const {
|
||||
return DL;
|
||||
}
|
||||
|
||||
virtual void computeKnownBitsImpl(Register R, KnownBits &Known,
|
||||
const APInt &DemandedElts,
|
||||
unsigned Depth = 0);
|
||||
|
||||
unsigned computeNumSignBits(Register R, const APInt &DemandedElts,
|
||||
unsigned Depth = 0);
|
||||
unsigned computeNumSignBits(Register R, unsigned Depth = 0);
|
||||
|
||||
// KnownBitsAPI
|
||||
KnownBits getKnownBits(Register R);
|
||||
KnownBits getKnownBits(Register R, const APInt &DemandedElts,
|
||||
unsigned Depth = 0);
|
||||
|
||||
// Calls getKnownBits for first operand def of MI.
|
||||
KnownBits getKnownBits(MachineInstr &MI);
|
||||
APInt getKnownZeroes(Register R);
|
||||
APInt getKnownOnes(Register R);
|
||||
|
||||
/// \return true if 'V & Mask' is known to be zero in DemandedElts. We use
|
||||
/// this predicate to simplify operations downstream.
|
||||
/// Mask is known to be zero for bits that V cannot have.
|
||||
bool maskedValueIsZero(Register Val, const APInt &Mask) {
|
||||
return Mask.isSubsetOf(getKnownBits(Val).Zero);
|
||||
}
|
||||
|
||||
/// \return true if the sign bit of Op is known to be zero. We use this
|
||||
/// predicate to simplify operations downstream.
|
||||
bool signBitIsZero(Register Op);
|
||||
|
||||
static void computeKnownBitsForAlignment(KnownBits &Known,
|
||||
Align Alignment) {
|
||||
// The low bits are known zero if the pointer is aligned.
|
||||
Known.Zero.setLowBits(Log2(Alignment));
|
||||
}
|
||||
|
||||
/// \return The known alignment for the pointer-like value \p R.
|
||||
Align computeKnownAlignment(Register R, unsigned Depth = 0);
|
||||
|
||||
// Observer API. No-op for non-caching implementation.
|
||||
void erasingInstr(MachineInstr &MI) override{};
|
||||
void createdInstr(MachineInstr &MI) override{};
|
||||
void changingInstr(MachineInstr &MI) override{};
|
||||
void changedInstr(MachineInstr &MI) override{};
|
||||
|
||||
protected:
|
||||
unsigned getMaxDepth() const { return MaxDepth; }
|
||||
};
|
||||
|
||||
/// To use KnownBitsInfo analysis in a pass,
|
||||
/// KnownBitsInfo &Info = getAnalysis<GISelKnownBitsInfoAnalysis>().get(MF);
|
||||
/// Add to observer if the Info is caching.
|
||||
/// WrapperObserver.addObserver(Info);
|
||||
|
||||
/// Eventually add other features such as caching/ser/deserializing
|
||||
/// to MIR etc. Those implementations can derive from GISelKnownBits
|
||||
/// and override computeKnownBitsImpl.
|
||||
class GISelKnownBitsAnalysis : public MachineFunctionPass {
|
||||
std::unique_ptr<GISelKnownBits> Info;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
GISelKnownBitsAnalysis() : MachineFunctionPass(ID) {
|
||||
initializeGISelKnownBitsAnalysisPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
GISelKnownBits &get(MachineFunction &MF) {
|
||||
if (!Info)
|
||||
Info = std::make_unique<GISelKnownBits>(MF);
|
||||
return *Info.get();
|
||||
}
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
bool runOnMachineFunction(MachineFunction &MF) override;
|
||||
void releaseMemory() override { Info.reset(); }
|
||||
};
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_GLOBALISEL_GISELKNOWNBITS_H
|
||||
112
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/GISelWorkList.h
vendored
Normal file
112
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/GISelWorkList.h
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
//===- GISelWorkList.h - Worklist for GISel passes ----*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_GISELWORKLIST_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_GISELWORKLIST_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MachineInstr;
|
||||
|
||||
// Worklist which mostly works similar to InstCombineWorkList, but on
|
||||
// MachineInstrs. The main difference with something like a SetVector is that
|
||||
// erasing an element doesn't move all elements over one place - instead just
|
||||
// nulls out the element of the vector.
|
||||
//
|
||||
// FIXME: Does it make sense to factor out common code with the
|
||||
// instcombinerWorkList?
|
||||
template<unsigned N>
|
||||
class GISelWorkList {
|
||||
SmallVector<MachineInstr *, N> Worklist;
|
||||
DenseMap<MachineInstr *, unsigned> WorklistMap;
|
||||
|
||||
#ifndef NDEBUG
|
||||
bool Finalized = true;
|
||||
#endif
|
||||
|
||||
public:
|
||||
GISelWorkList() : WorklistMap(N) {}
|
||||
|
||||
bool empty() const { return WorklistMap.empty(); }
|
||||
|
||||
unsigned size() const { return WorklistMap.size(); }
|
||||
|
||||
// Since we don't know ahead of time how many instructions we're going to add
|
||||
// to the worklist, and migrating densemap's elements is quite expensive
|
||||
// every time we resize, only insert to the smallvector (typically during the
|
||||
// initial phase of populating lists). Before the worklist can be used,
|
||||
// finalize should be called. Also assert with NDEBUG if list is ever used
|
||||
// without finalizing. Note that unlike insert, we won't check for duplicates
|
||||
// - so the ideal place to use this is during the initial prepopulating phase
|
||||
// of most passes.
|
||||
void deferred_insert(MachineInstr *I) {
|
||||
Worklist.push_back(I);
|
||||
#ifndef NDEBUG
|
||||
Finalized = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// This should only be called when using deferred_insert.
|
||||
// This asserts that the WorklistMap is empty, and then
|
||||
// inserts all the elements in the Worklist into the map.
|
||||
// It also asserts if there are any duplicate elements found.
|
||||
void finalize() {
|
||||
assert(WorklistMap.empty() && "Expecting empty worklistmap");
|
||||
if (Worklist.size() > N)
|
||||
WorklistMap.reserve(Worklist.size());
|
||||
for (unsigned i = 0; i < Worklist.size(); ++i)
|
||||
if (!WorklistMap.try_emplace(Worklist[i], i).second)
|
||||
llvm_unreachable("Duplicate elements in the list");
|
||||
#ifndef NDEBUG
|
||||
Finalized = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Add the specified instruction to the worklist if it isn't already in it.
|
||||
void insert(MachineInstr *I) {
|
||||
assert(Finalized && "GISelWorkList used without finalizing");
|
||||
if (WorklistMap.try_emplace(I, Worklist.size()).second)
|
||||
Worklist.push_back(I);
|
||||
}
|
||||
|
||||
/// Remove I from the worklist if it exists.
|
||||
void remove(const MachineInstr *I) {
|
||||
assert((Finalized || WorklistMap.empty()) && "Neither finalized nor empty");
|
||||
auto It = WorklistMap.find(I);
|
||||
if (It == WorklistMap.end())
|
||||
return; // Not in worklist.
|
||||
|
||||
// Don't bother moving everything down, just null out the slot.
|
||||
Worklist[It->second] = nullptr;
|
||||
|
||||
WorklistMap.erase(It);
|
||||
}
|
||||
|
||||
void clear() {
|
||||
Worklist.clear();
|
||||
WorklistMap.clear();
|
||||
}
|
||||
|
||||
MachineInstr *pop_back_val() {
|
||||
assert(Finalized && "GISelWorkList used without finalizing");
|
||||
MachineInstr *I;
|
||||
do {
|
||||
I = Worklist.pop_back_val();
|
||||
} while(!I);
|
||||
assert(I && "Pop back on empty worklist");
|
||||
WorklistMap.erase(I);
|
||||
return I;
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace llvm.
|
||||
|
||||
#endif
|
||||
231
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h
vendored
Normal file
231
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h
vendored
Normal file
@@ -0,0 +1,231 @@
|
||||
//===- llvm/CodeGen/GlobalISel/GenericMachineInstrs.h -----------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// Declares convenience wrapper classes for interpreting MachineInstr instances
|
||||
/// as specific generic operations.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_GENERICMACHINEINSTRS_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_GENERICMACHINEINSTRS_H
|
||||
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
#include "llvm/CodeGen/MachineMemOperand.h"
|
||||
#include "llvm/CodeGen/TargetOpcodes.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// A base class for all GenericMachineInstrs.
|
||||
class GenericMachineInstr : public MachineInstr {
|
||||
public:
|
||||
GenericMachineInstr() = delete;
|
||||
|
||||
/// Access the Idx'th operand as a register and return it.
|
||||
/// This assumes that the Idx'th operand is a Register type.
|
||||
Register getReg(unsigned Idx) const { return getOperand(Idx).getReg(); }
|
||||
|
||||
static bool classof(const MachineInstr *MI) {
|
||||
return isPreISelGenericOpcode(MI->getOpcode());
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents any type of generic load or store.
|
||||
/// G_LOAD, G_STORE, G_ZEXTLOAD, G_SEXTLOAD.
|
||||
class GLoadStore : public GenericMachineInstr {
|
||||
public:
|
||||
/// Get the source register of the pointer value.
|
||||
Register getPointerReg() const { return getOperand(1).getReg(); }
|
||||
|
||||
/// Get the MachineMemOperand on this instruction.
|
||||
MachineMemOperand &getMMO() const { return **memoperands_begin(); }
|
||||
|
||||
/// Returns true if the attached MachineMemOperand has the atomic flag set.
|
||||
bool isAtomic() const { return getMMO().isAtomic(); }
|
||||
/// Returns true if the attached MachineMemOpeand as the volatile flag set.
|
||||
bool isVolatile() const { return getMMO().isVolatile(); }
|
||||
/// Returns true if the memory operation is neither atomic or volatile.
|
||||
bool isSimple() const { return !isAtomic() && !isVolatile(); }
|
||||
/// Returns true if this memory operation doesn't have any ordering
|
||||
/// constraints other than normal aliasing. Volatile and (ordered) atomic
|
||||
/// memory operations can't be reordered.
|
||||
bool isUnordered() const { return getMMO().isUnordered(); }
|
||||
|
||||
/// Returns the size in bytes of the memory access.
|
||||
uint64_t getMemSize() const { return getMMO().getSize();
|
||||
} /// Returns the size in bits of the memory access.
|
||||
uint64_t getMemSizeInBits() const { return getMMO().getSizeInBits(); }
|
||||
|
||||
static bool classof(const MachineInstr *MI) {
|
||||
switch (MI->getOpcode()) {
|
||||
case TargetOpcode::G_LOAD:
|
||||
case TargetOpcode::G_STORE:
|
||||
case TargetOpcode::G_ZEXTLOAD:
|
||||
case TargetOpcode::G_SEXTLOAD:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents any generic load, including sign/zero extending variants.
|
||||
class GAnyLoad : public GLoadStore {
|
||||
public:
|
||||
/// Get the definition register of the loaded value.
|
||||
Register getDstReg() const { return getOperand(0).getReg(); }
|
||||
|
||||
static bool classof(const MachineInstr *MI) {
|
||||
switch (MI->getOpcode()) {
|
||||
case TargetOpcode::G_LOAD:
|
||||
case TargetOpcode::G_ZEXTLOAD:
|
||||
case TargetOpcode::G_SEXTLOAD:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents a G_LOAD.
|
||||
class GLoad : public GAnyLoad {
|
||||
public:
|
||||
static bool classof(const MachineInstr *MI) {
|
||||
return MI->getOpcode() == TargetOpcode::G_LOAD;
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents either a G_SEXTLOAD or G_ZEXTLOAD.
|
||||
class GExtLoad : public GAnyLoad {
|
||||
public:
|
||||
static bool classof(const MachineInstr *MI) {
|
||||
return MI->getOpcode() == TargetOpcode::G_SEXTLOAD ||
|
||||
MI->getOpcode() == TargetOpcode::G_ZEXTLOAD;
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents a G_SEXTLOAD.
|
||||
class GSExtLoad : public GExtLoad {
|
||||
public:
|
||||
static bool classof(const MachineInstr *MI) {
|
||||
return MI->getOpcode() == TargetOpcode::G_SEXTLOAD;
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents a G_ZEXTLOAD.
|
||||
class GZExtLoad : public GExtLoad {
|
||||
public:
|
||||
static bool classof(const MachineInstr *MI) {
|
||||
return MI->getOpcode() == TargetOpcode::G_ZEXTLOAD;
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents a G_STORE.
|
||||
class GStore : public GLoadStore {
|
||||
public:
|
||||
/// Get the stored value register.
|
||||
Register getValueReg() const { return getOperand(0).getReg(); }
|
||||
|
||||
static bool classof(const MachineInstr *MI) {
|
||||
return MI->getOpcode() == TargetOpcode::G_STORE;
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents a G_UNMERGE_VALUES.
|
||||
class GUnmerge : public GenericMachineInstr {
|
||||
public:
|
||||
/// Returns the number of def registers.
|
||||
unsigned getNumDefs() const { return getNumOperands() - 1; }
|
||||
/// Get the unmerge source register.
|
||||
Register getSourceReg() const { return getOperand(getNumDefs()).getReg(); }
|
||||
|
||||
static bool classof(const MachineInstr *MI) {
|
||||
return MI->getOpcode() == TargetOpcode::G_UNMERGE_VALUES;
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents G_BUILD_VECTOR, G_CONCAT_VECTORS or G_MERGE_VALUES.
|
||||
/// All these have the common property of generating a single value from
|
||||
/// multiple sources.
|
||||
class GMergeLikeOp : public GenericMachineInstr {
|
||||
public:
|
||||
/// Returns the number of source registers.
|
||||
unsigned getNumSources() const { return getNumOperands() - 1; }
|
||||
/// Returns the I'th source register.
|
||||
Register getSourceReg(unsigned I) const { return getReg(I + 1); }
|
||||
|
||||
static bool classof(const MachineInstr *MI) {
|
||||
switch (MI->getOpcode()) {
|
||||
case TargetOpcode::G_MERGE_VALUES:
|
||||
case TargetOpcode::G_CONCAT_VECTORS:
|
||||
case TargetOpcode::G_BUILD_VECTOR:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents a G_MERGE_VALUES.
|
||||
class GMerge : public GMergeLikeOp {
|
||||
public:
|
||||
static bool classof(const MachineInstr *MI) {
|
||||
return MI->getOpcode() == TargetOpcode::G_MERGE_VALUES;
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents a G_CONCAT_VECTORS.
|
||||
class GConcatVectors : public GMergeLikeOp {
|
||||
public:
|
||||
static bool classof(const MachineInstr *MI) {
|
||||
return MI->getOpcode() == TargetOpcode::G_CONCAT_VECTORS;
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents a G_BUILD_VECTOR.
|
||||
class GBuildVector : public GMergeLikeOp {
|
||||
public:
|
||||
static bool classof(const MachineInstr *MI) {
|
||||
return MI->getOpcode() == TargetOpcode::G_BUILD_VECTOR;
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents a G_PTR_ADD.
|
||||
class GPtrAdd : public GenericMachineInstr {
|
||||
public:
|
||||
Register getBaseReg() const { return getReg(1); }
|
||||
Register getOffsetReg() const { return getReg(2); }
|
||||
|
||||
static bool classof(const MachineInstr *MI) {
|
||||
return MI->getOpcode() == TargetOpcode::G_PTR_ADD;
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents a G_IMPLICIT_DEF.
|
||||
class GImplicitDef : public GenericMachineInstr {
|
||||
public:
|
||||
static bool classof(const MachineInstr *MI) {
|
||||
return MI->getOpcode() == TargetOpcode::G_IMPLICIT_DEF;
|
||||
}
|
||||
};
|
||||
|
||||
/// Represents a G_SELECT.
|
||||
class GSelect : public GenericMachineInstr {
|
||||
public:
|
||||
Register getCondReg() const { return getReg(1); }
|
||||
Register getTrueReg() const { return getReg(2); }
|
||||
Register getFalseReg() const { return getReg(3); }
|
||||
|
||||
static bool classof(const MachineInstr *MI) {
|
||||
return MI->getOpcode() == TargetOpcode::G_SELECT;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_GLOBALISEL_GENERICMACHINEINSTRS_H
|
||||
731
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/IRTranslator.h
vendored
Normal file
731
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/IRTranslator.h
vendored
Normal file
@@ -0,0 +1,731 @@
|
||||
//===- llvm/CodeGen/GlobalISel/IRTranslator.h - IRTranslator ----*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// This file declares the IRTranslator pass.
|
||||
/// This pass is responsible for translating LLVM IR into MachineInstr.
|
||||
/// It uses target hooks to lower the ABI but aside from that, the pass
|
||||
/// generated code is generic. This is the default translator used for
|
||||
/// GlobalISel.
|
||||
///
|
||||
/// \todo Replace the comments with actual doxygen comments.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_IRTRANSLATOR_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_IRTRANSLATOR_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/CodeGen/CodeGenCommonISel.h"
|
||||
#include "llvm/CodeGen/FunctionLoweringInfo.h"
|
||||
#include "llvm/CodeGen/GlobalISel/CSEMIRBuilder.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/SwiftErrorValueTracking.h"
|
||||
#include "llvm/CodeGen/SwitchLoweringUtils.h"
|
||||
#include "llvm/IR/Intrinsics.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/CodeGen.h"
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class AllocaInst;
|
||||
class BasicBlock;
|
||||
class CallInst;
|
||||
class CallLowering;
|
||||
class Constant;
|
||||
class ConstrainedFPIntrinsic;
|
||||
class DataLayout;
|
||||
class Instruction;
|
||||
class MachineBasicBlock;
|
||||
class MachineFunction;
|
||||
class MachineInstr;
|
||||
class MachineRegisterInfo;
|
||||
class OptimizationRemarkEmitter;
|
||||
class PHINode;
|
||||
class TargetPassConfig;
|
||||
class User;
|
||||
class Value;
|
||||
|
||||
// Technically the pass should run on an hypothetical MachineModule,
|
||||
// since it should translate Global into some sort of MachineGlobal.
|
||||
// The MachineGlobal should ultimately just be a transfer of ownership of
|
||||
// the interesting bits that are relevant to represent a global value.
|
||||
// That being said, we could investigate what would it cost to just duplicate
|
||||
// the information from the LLVM IR.
|
||||
// The idea is that ultimately we would be able to free up the memory used
|
||||
// by the LLVM IR as soon as the translation is over.
|
||||
class IRTranslator : public MachineFunctionPass {
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
private:
|
||||
/// Interface used to lower the everything related to calls.
|
||||
const CallLowering *CLI;
|
||||
|
||||
/// This class contains the mapping between the Values to vreg related data.
|
||||
class ValueToVRegInfo {
|
||||
public:
|
||||
ValueToVRegInfo() = default;
|
||||
|
||||
using VRegListT = SmallVector<Register, 1>;
|
||||
using OffsetListT = SmallVector<uint64_t, 1>;
|
||||
|
||||
using const_vreg_iterator =
|
||||
DenseMap<const Value *, VRegListT *>::const_iterator;
|
||||
using const_offset_iterator =
|
||||
DenseMap<const Value *, OffsetListT *>::const_iterator;
|
||||
|
||||
inline const_vreg_iterator vregs_end() const { return ValToVRegs.end(); }
|
||||
|
||||
VRegListT *getVRegs(const Value &V) {
|
||||
auto It = ValToVRegs.find(&V);
|
||||
if (It != ValToVRegs.end())
|
||||
return It->second;
|
||||
|
||||
return insertVRegs(V);
|
||||
}
|
||||
|
||||
OffsetListT *getOffsets(const Value &V) {
|
||||
auto It = TypeToOffsets.find(V.getType());
|
||||
if (It != TypeToOffsets.end())
|
||||
return It->second;
|
||||
|
||||
return insertOffsets(V);
|
||||
}
|
||||
|
||||
const_vreg_iterator findVRegs(const Value &V) const {
|
||||
return ValToVRegs.find(&V);
|
||||
}
|
||||
|
||||
bool contains(const Value &V) const {
|
||||
return ValToVRegs.find(&V) != ValToVRegs.end();
|
||||
}
|
||||
|
||||
void reset() {
|
||||
ValToVRegs.clear();
|
||||
TypeToOffsets.clear();
|
||||
VRegAlloc.DestroyAll();
|
||||
OffsetAlloc.DestroyAll();
|
||||
}
|
||||
|
||||
private:
|
||||
VRegListT *insertVRegs(const Value &V) {
|
||||
assert(ValToVRegs.find(&V) == ValToVRegs.end() && "Value already exists");
|
||||
|
||||
// We placement new using our fast allocator since we never try to free
|
||||
// the vectors until translation is finished.
|
||||
auto *VRegList = new (VRegAlloc.Allocate()) VRegListT();
|
||||
ValToVRegs[&V] = VRegList;
|
||||
return VRegList;
|
||||
}
|
||||
|
||||
OffsetListT *insertOffsets(const Value &V) {
|
||||
assert(TypeToOffsets.find(V.getType()) == TypeToOffsets.end() &&
|
||||
"Type already exists");
|
||||
|
||||
auto *OffsetList = new (OffsetAlloc.Allocate()) OffsetListT();
|
||||
TypeToOffsets[V.getType()] = OffsetList;
|
||||
return OffsetList;
|
||||
}
|
||||
SpecificBumpPtrAllocator<VRegListT> VRegAlloc;
|
||||
SpecificBumpPtrAllocator<OffsetListT> OffsetAlloc;
|
||||
|
||||
// We store pointers to vectors here since references may be invalidated
|
||||
// while we hold them if we stored the vectors directly.
|
||||
DenseMap<const Value *, VRegListT*> ValToVRegs;
|
||||
DenseMap<const Type *, OffsetListT*> TypeToOffsets;
|
||||
};
|
||||
|
||||
/// Mapping of the values of the current LLVM IR function to the related
|
||||
/// virtual registers and offsets.
|
||||
ValueToVRegInfo VMap;
|
||||
|
||||
// N.b. it's not completely obvious that this will be sufficient for every
|
||||
// LLVM IR construct (with "invoke" being the obvious candidate to mess up our
|
||||
// lives.
|
||||
DenseMap<const BasicBlock *, MachineBasicBlock *> BBToMBB;
|
||||
|
||||
// One BasicBlock can be translated to multiple MachineBasicBlocks. For such
|
||||
// BasicBlocks translated to multiple MachineBasicBlocks, MachinePreds retains
|
||||
// a mapping between the edges arriving at the BasicBlock to the corresponding
|
||||
// created MachineBasicBlocks. Some BasicBlocks that get translated to a
|
||||
// single MachineBasicBlock may also end up in this Map.
|
||||
using CFGEdge = std::pair<const BasicBlock *, const BasicBlock *>;
|
||||
DenseMap<CFGEdge, SmallVector<MachineBasicBlock *, 1>> MachinePreds;
|
||||
|
||||
// List of stubbed PHI instructions, for values and basic blocks to be filled
|
||||
// in once all MachineBasicBlocks have been created.
|
||||
SmallVector<std::pair<const PHINode *, SmallVector<MachineInstr *, 1>>, 4>
|
||||
PendingPHIs;
|
||||
|
||||
/// Record of what frame index has been allocated to specified allocas for
|
||||
/// this function.
|
||||
DenseMap<const AllocaInst *, int> FrameIndices;
|
||||
|
||||
SwiftErrorValueTracking SwiftError;
|
||||
|
||||
/// \name Methods for translating form LLVM IR to MachineInstr.
|
||||
/// \see ::translate for general information on the translate methods.
|
||||
/// @{
|
||||
|
||||
/// Translate \p Inst into its corresponding MachineInstr instruction(s).
|
||||
/// Insert the newly translated instruction(s) right where the CurBuilder
|
||||
/// is set.
|
||||
///
|
||||
/// The general algorithm is:
|
||||
/// 1. Look for a virtual register for each operand or
|
||||
/// create one.
|
||||
/// 2 Update the VMap accordingly.
|
||||
/// 2.alt. For constant arguments, if they are compile time constants,
|
||||
/// produce an immediate in the right operand and do not touch
|
||||
/// ValToReg. Actually we will go with a virtual register for each
|
||||
/// constants because it may be expensive to actually materialize the
|
||||
/// constant. Moreover, if the constant spans on several instructions,
|
||||
/// CSE may not catch them.
|
||||
/// => Update ValToVReg and remember that we saw a constant in Constants.
|
||||
/// We will materialize all the constants in finalize.
|
||||
/// Note: we would need to do something so that we can recognize such operand
|
||||
/// as constants.
|
||||
/// 3. Create the generic instruction.
|
||||
///
|
||||
/// \return true if the translation succeeded.
|
||||
bool translate(const Instruction &Inst);
|
||||
|
||||
/// Materialize \p C into virtual-register \p Reg. The generic instructions
|
||||
/// performing this materialization will be inserted into the entry block of
|
||||
/// the function.
|
||||
///
|
||||
/// \return true if the materialization succeeded.
|
||||
bool translate(const Constant &C, Register Reg);
|
||||
|
||||
// Translate U as a copy of V.
|
||||
bool translateCopy(const User &U, const Value &V,
|
||||
MachineIRBuilder &MIRBuilder);
|
||||
|
||||
/// Translate an LLVM bitcast into generic IR. Either a COPY or a G_BITCAST is
|
||||
/// emitted.
|
||||
bool translateBitCast(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
/// Translate an LLVM load instruction into generic IR.
|
||||
bool translateLoad(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
/// Translate an LLVM store instruction into generic IR.
|
||||
bool translateStore(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
/// Translate an LLVM string intrinsic (memcpy, memset, ...).
|
||||
bool translateMemFunc(const CallInst &CI, MachineIRBuilder &MIRBuilder,
|
||||
unsigned Opcode);
|
||||
|
||||
void getStackGuard(Register DstReg, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateOverflowIntrinsic(const CallInst &CI, unsigned Op,
|
||||
MachineIRBuilder &MIRBuilder);
|
||||
bool translateFixedPointIntrinsic(unsigned Op, const CallInst &CI,
|
||||
MachineIRBuilder &MIRBuilder);
|
||||
|
||||
/// Helper function for translateSimpleIntrinsic.
|
||||
/// \return The generic opcode for \p IntrinsicID if \p IntrinsicID is a
|
||||
/// simple intrinsic (ceil, fabs, etc.). Otherwise, returns
|
||||
/// Intrinsic::not_intrinsic.
|
||||
unsigned getSimpleIntrinsicOpcode(Intrinsic::ID ID);
|
||||
|
||||
/// Translates the intrinsics defined in getSimpleIntrinsicOpcode.
|
||||
/// \return true if the translation succeeded.
|
||||
bool translateSimpleIntrinsic(const CallInst &CI, Intrinsic::ID ID,
|
||||
MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateConstrainedFPIntrinsic(const ConstrainedFPIntrinsic &FPI,
|
||||
MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID,
|
||||
MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateInlineAsm(const CallBase &CB, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
/// Returns true if the value should be split into multiple LLTs.
|
||||
/// If \p Offsets is given then the split type's offsets will be stored in it.
|
||||
/// If \p Offsets is not empty it will be cleared first.
|
||||
bool valueIsSplit(const Value &V,
|
||||
SmallVectorImpl<uint64_t> *Offsets = nullptr);
|
||||
|
||||
/// Common code for translating normal calls or invokes.
|
||||
bool translateCallBase(const CallBase &CB, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
/// Translate call instruction.
|
||||
/// \pre \p U is a call instruction.
|
||||
bool translateCall(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
/// When an invoke or a cleanupret unwinds to the next EH pad, there are
|
||||
/// many places it could ultimately go. In the IR, we have a single unwind
|
||||
/// destination, but in the machine CFG, we enumerate all the possible blocks.
|
||||
/// This function skips over imaginary basic blocks that hold catchswitch
|
||||
/// instructions, and finds all the "real" machine
|
||||
/// basic block destinations. As those destinations may not be successors of
|
||||
/// EHPadBB, here we also calculate the edge probability to those
|
||||
/// destinations. The passed-in Prob is the edge probability to EHPadBB.
|
||||
bool findUnwindDestinations(
|
||||
const BasicBlock *EHPadBB, BranchProbability Prob,
|
||||
SmallVectorImpl<std::pair<MachineBasicBlock *, BranchProbability>>
|
||||
&UnwindDests);
|
||||
|
||||
bool translateInvoke(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateCallBr(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateLandingPad(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
/// Translate one of LLVM's cast instructions into MachineInstrs, with the
|
||||
/// given generic Opcode.
|
||||
bool translateCast(unsigned Opcode, const User &U,
|
||||
MachineIRBuilder &MIRBuilder);
|
||||
|
||||
/// Translate a phi instruction.
|
||||
bool translatePHI(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
/// Translate a comparison (icmp or fcmp) instruction or constant.
|
||||
bool translateCompare(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
/// Translate an integer compare instruction (or constant).
|
||||
bool translateICmp(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateCompare(U, MIRBuilder);
|
||||
}
|
||||
|
||||
/// Translate a floating-point compare instruction (or constant).
|
||||
bool translateFCmp(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateCompare(U, MIRBuilder);
|
||||
}
|
||||
|
||||
/// Add remaining operands onto phis we've translated. Executed after all
|
||||
/// MachineBasicBlocks for the function have been created.
|
||||
void finishPendingPhis();
|
||||
|
||||
/// Translate \p Inst into a unary operation \p Opcode.
|
||||
/// \pre \p U is a unary operation.
|
||||
bool translateUnaryOp(unsigned Opcode, const User &U,
|
||||
MachineIRBuilder &MIRBuilder);
|
||||
|
||||
/// Translate \p Inst into a binary operation \p Opcode.
|
||||
/// \pre \p U is a binary operation.
|
||||
bool translateBinaryOp(unsigned Opcode, const User &U,
|
||||
MachineIRBuilder &MIRBuilder);
|
||||
|
||||
/// If the set of cases should be emitted as a series of branches, return
|
||||
/// true. If we should emit this as a bunch of and/or'd together conditions,
|
||||
/// return false.
|
||||
bool shouldEmitAsBranches(const std::vector<SwitchCG::CaseBlock> &Cases);
|
||||
/// Helper method for findMergedConditions.
|
||||
/// This function emits a branch and is used at the leaves of an OR or an
|
||||
/// AND operator tree.
|
||||
void emitBranchForMergedCondition(const Value *Cond, MachineBasicBlock *TBB,
|
||||
MachineBasicBlock *FBB,
|
||||
MachineBasicBlock *CurBB,
|
||||
MachineBasicBlock *SwitchBB,
|
||||
BranchProbability TProb,
|
||||
BranchProbability FProb, bool InvertCond);
|
||||
/// Used during condbr translation to find trees of conditions that can be
|
||||
/// optimized.
|
||||
void findMergedConditions(const Value *Cond, MachineBasicBlock *TBB,
|
||||
MachineBasicBlock *FBB, MachineBasicBlock *CurBB,
|
||||
MachineBasicBlock *SwitchBB,
|
||||
Instruction::BinaryOps Opc, BranchProbability TProb,
|
||||
BranchProbability FProb, bool InvertCond);
|
||||
|
||||
/// Translate branch (br) instruction.
|
||||
/// \pre \p U is a branch instruction.
|
||||
bool translateBr(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
// Begin switch lowering functions.
|
||||
bool emitJumpTableHeader(SwitchCG::JumpTable &JT,
|
||||
SwitchCG::JumpTableHeader &JTH,
|
||||
MachineBasicBlock *HeaderBB);
|
||||
void emitJumpTable(SwitchCG::JumpTable &JT, MachineBasicBlock *MBB);
|
||||
|
||||
void emitSwitchCase(SwitchCG::CaseBlock &CB, MachineBasicBlock *SwitchBB,
|
||||
MachineIRBuilder &MIB);
|
||||
|
||||
/// Generate for for the BitTest header block, which precedes each sequence of
|
||||
/// BitTestCases.
|
||||
void emitBitTestHeader(SwitchCG::BitTestBlock &BTB,
|
||||
MachineBasicBlock *SwitchMBB);
|
||||
/// Generate code to produces one "bit test" for a given BitTestCase \p B.
|
||||
void emitBitTestCase(SwitchCG::BitTestBlock &BB, MachineBasicBlock *NextMBB,
|
||||
BranchProbability BranchProbToNext, Register Reg,
|
||||
SwitchCG::BitTestCase &B, MachineBasicBlock *SwitchBB);
|
||||
|
||||
bool lowerJumpTableWorkItem(
|
||||
SwitchCG::SwitchWorkListItem W, MachineBasicBlock *SwitchMBB,
|
||||
MachineBasicBlock *CurMBB, MachineBasicBlock *DefaultMBB,
|
||||
MachineIRBuilder &MIB, MachineFunction::iterator BBI,
|
||||
BranchProbability UnhandledProbs, SwitchCG::CaseClusterIt I,
|
||||
MachineBasicBlock *Fallthrough, bool FallthroughUnreachable);
|
||||
|
||||
bool lowerSwitchRangeWorkItem(SwitchCG::CaseClusterIt I, Value *Cond,
|
||||
MachineBasicBlock *Fallthrough,
|
||||
bool FallthroughUnreachable,
|
||||
BranchProbability UnhandledProbs,
|
||||
MachineBasicBlock *CurMBB,
|
||||
MachineIRBuilder &MIB,
|
||||
MachineBasicBlock *SwitchMBB);
|
||||
|
||||
bool lowerBitTestWorkItem(
|
||||
SwitchCG::SwitchWorkListItem W, MachineBasicBlock *SwitchMBB,
|
||||
MachineBasicBlock *CurMBB, MachineBasicBlock *DefaultMBB,
|
||||
MachineIRBuilder &MIB, MachineFunction::iterator BBI,
|
||||
BranchProbability DefaultProb, BranchProbability UnhandledProbs,
|
||||
SwitchCG::CaseClusterIt I, MachineBasicBlock *Fallthrough,
|
||||
bool FallthroughUnreachable);
|
||||
|
||||
bool lowerSwitchWorkItem(SwitchCG::SwitchWorkListItem W, Value *Cond,
|
||||
MachineBasicBlock *SwitchMBB,
|
||||
MachineBasicBlock *DefaultMBB,
|
||||
MachineIRBuilder &MIB);
|
||||
|
||||
bool translateSwitch(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
// End switch lowering section.
|
||||
|
||||
bool translateIndirectBr(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateExtractValue(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateInsertValue(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateSelect(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateGetElementPtr(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateAlloca(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
/// Translate return (ret) instruction.
|
||||
/// The target needs to implement CallLowering::lowerReturn for
|
||||
/// this to succeed.
|
||||
/// \pre \p U is a return instruction.
|
||||
bool translateRet(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateFNeg(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateAdd(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateBinaryOp(TargetOpcode::G_ADD, U, MIRBuilder);
|
||||
}
|
||||
bool translateSub(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateBinaryOp(TargetOpcode::G_SUB, U, MIRBuilder);
|
||||
}
|
||||
bool translateAnd(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateBinaryOp(TargetOpcode::G_AND, U, MIRBuilder);
|
||||
}
|
||||
bool translateMul(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateBinaryOp(TargetOpcode::G_MUL, U, MIRBuilder);
|
||||
}
|
||||
bool translateOr(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateBinaryOp(TargetOpcode::G_OR, U, MIRBuilder);
|
||||
}
|
||||
bool translateXor(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateBinaryOp(TargetOpcode::G_XOR, U, MIRBuilder);
|
||||
}
|
||||
|
||||
bool translateUDiv(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateBinaryOp(TargetOpcode::G_UDIV, U, MIRBuilder);
|
||||
}
|
||||
bool translateSDiv(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateBinaryOp(TargetOpcode::G_SDIV, U, MIRBuilder);
|
||||
}
|
||||
bool translateURem(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateBinaryOp(TargetOpcode::G_UREM, U, MIRBuilder);
|
||||
}
|
||||
bool translateSRem(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateBinaryOp(TargetOpcode::G_SREM, U, MIRBuilder);
|
||||
}
|
||||
bool translateIntToPtr(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateCast(TargetOpcode::G_INTTOPTR, U, MIRBuilder);
|
||||
}
|
||||
bool translatePtrToInt(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateCast(TargetOpcode::G_PTRTOINT, U, MIRBuilder);
|
||||
}
|
||||
bool translateTrunc(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateCast(TargetOpcode::G_TRUNC, U, MIRBuilder);
|
||||
}
|
||||
bool translateFPTrunc(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateCast(TargetOpcode::G_FPTRUNC, U, MIRBuilder);
|
||||
}
|
||||
bool translateFPExt(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateCast(TargetOpcode::G_FPEXT, U, MIRBuilder);
|
||||
}
|
||||
bool translateFPToUI(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateCast(TargetOpcode::G_FPTOUI, U, MIRBuilder);
|
||||
}
|
||||
bool translateFPToSI(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateCast(TargetOpcode::G_FPTOSI, U, MIRBuilder);
|
||||
}
|
||||
bool translateUIToFP(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateCast(TargetOpcode::G_UITOFP, U, MIRBuilder);
|
||||
}
|
||||
bool translateSIToFP(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateCast(TargetOpcode::G_SITOFP, U, MIRBuilder);
|
||||
}
|
||||
bool translateUnreachable(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateSExt(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateCast(TargetOpcode::G_SEXT, U, MIRBuilder);
|
||||
}
|
||||
|
||||
bool translateZExt(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateCast(TargetOpcode::G_ZEXT, U, MIRBuilder);
|
||||
}
|
||||
|
||||
bool translateShl(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateBinaryOp(TargetOpcode::G_SHL, U, MIRBuilder);
|
||||
}
|
||||
bool translateLShr(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateBinaryOp(TargetOpcode::G_LSHR, U, MIRBuilder);
|
||||
}
|
||||
bool translateAShr(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateBinaryOp(TargetOpcode::G_ASHR, U, MIRBuilder);
|
||||
}
|
||||
|
||||
bool translateFAdd(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateBinaryOp(TargetOpcode::G_FADD, U, MIRBuilder);
|
||||
}
|
||||
bool translateFSub(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateBinaryOp(TargetOpcode::G_FSUB, U, MIRBuilder);
|
||||
}
|
||||
bool translateFMul(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateBinaryOp(TargetOpcode::G_FMUL, U, MIRBuilder);
|
||||
}
|
||||
bool translateFDiv(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateBinaryOp(TargetOpcode::G_FDIV, U, MIRBuilder);
|
||||
}
|
||||
bool translateFRem(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateBinaryOp(TargetOpcode::G_FREM, U, MIRBuilder);
|
||||
}
|
||||
|
||||
bool translateVAArg(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateInsertElement(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateExtractElement(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateShuffleVector(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
bool translateAtomicCmpXchg(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
bool translateAtomicRMW(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
bool translateFence(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
bool translateFreeze(const User &U, MachineIRBuilder &MIRBuilder);
|
||||
|
||||
// Stubs to keep the compiler happy while we implement the rest of the
|
||||
// translation.
|
||||
bool translateResume(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return false;
|
||||
}
|
||||
bool translateCleanupRet(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return false;
|
||||
}
|
||||
bool translateCatchRet(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return false;
|
||||
}
|
||||
bool translateCatchSwitch(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return false;
|
||||
}
|
||||
bool translateAddrSpaceCast(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return translateCast(TargetOpcode::G_ADDRSPACE_CAST, U, MIRBuilder);
|
||||
}
|
||||
bool translateCleanupPad(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return false;
|
||||
}
|
||||
bool translateCatchPad(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return false;
|
||||
}
|
||||
bool translateUserOp1(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return false;
|
||||
}
|
||||
bool translateUserOp2(const User &U, MachineIRBuilder &MIRBuilder) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// @}
|
||||
|
||||
// Builder for machine instruction a la IRBuilder.
|
||||
// I.e., compared to regular MIBuilder, this one also inserts the instruction
|
||||
// in the current block, it can creates block, etc., basically a kind of
|
||||
// IRBuilder, but for Machine IR.
|
||||
// CSEMIRBuilder CurBuilder;
|
||||
std::unique_ptr<MachineIRBuilder> CurBuilder;
|
||||
|
||||
// Builder set to the entry block (just after ABI lowering instructions). Used
|
||||
// as a convenient location for Constants.
|
||||
// CSEMIRBuilder EntryBuilder;
|
||||
std::unique_ptr<MachineIRBuilder> EntryBuilder;
|
||||
|
||||
// The MachineFunction currently being translated.
|
||||
MachineFunction *MF;
|
||||
|
||||
/// MachineRegisterInfo used to create virtual registers.
|
||||
MachineRegisterInfo *MRI = nullptr;
|
||||
|
||||
const DataLayout *DL;
|
||||
|
||||
/// Current target configuration. Controls how the pass handles errors.
|
||||
const TargetPassConfig *TPC;
|
||||
|
||||
CodeGenOpt::Level OptLevel;
|
||||
|
||||
/// Current optimization remark emitter. Used to report failures.
|
||||
std::unique_ptr<OptimizationRemarkEmitter> ORE;
|
||||
|
||||
FunctionLoweringInfo FuncInfo;
|
||||
|
||||
// True when either the Target Machine specifies no optimizations or the
|
||||
// function has the optnone attribute.
|
||||
bool EnableOpts = false;
|
||||
|
||||
/// True when the block contains a tail call. This allows the IRTranslator to
|
||||
/// stop translating such blocks early.
|
||||
bool HasTailCall = false;
|
||||
|
||||
StackProtectorDescriptor SPDescriptor;
|
||||
|
||||
/// Switch analysis and optimization.
|
||||
class GISelSwitchLowering : public SwitchCG::SwitchLowering {
|
||||
public:
|
||||
GISelSwitchLowering(IRTranslator *irt, FunctionLoweringInfo &funcinfo)
|
||||
: SwitchLowering(funcinfo), IRT(irt) {
|
||||
assert(irt && "irt is null!");
|
||||
}
|
||||
|
||||
virtual void addSuccessorWithProb(
|
||||
MachineBasicBlock *Src, MachineBasicBlock *Dst,
|
||||
BranchProbability Prob = BranchProbability::getUnknown()) override {
|
||||
IRT->addSuccessorWithProb(Src, Dst, Prob);
|
||||
}
|
||||
|
||||
virtual ~GISelSwitchLowering() = default;
|
||||
|
||||
private:
|
||||
IRTranslator *IRT;
|
||||
};
|
||||
|
||||
std::unique_ptr<GISelSwitchLowering> SL;
|
||||
|
||||
// * Insert all the code needed to materialize the constants
|
||||
// at the proper place. E.g., Entry block or dominator block
|
||||
// of each constant depending on how fancy we want to be.
|
||||
// * Clear the different maps.
|
||||
void finalizeFunction();
|
||||
|
||||
// Processing steps done per block. E.g. emitting jump tables, stack
|
||||
// protectors etc. Returns true if no errors, false if there was a problem
|
||||
// that caused an abort.
|
||||
bool finalizeBasicBlock(const BasicBlock &BB, MachineBasicBlock &MBB);
|
||||
|
||||
/// Codegen a new tail for a stack protector check ParentMBB which has had its
|
||||
/// tail spliced into a stack protector check success bb.
|
||||
///
|
||||
/// For a high level explanation of how this fits into the stack protector
|
||||
/// generation see the comment on the declaration of class
|
||||
/// StackProtectorDescriptor.
|
||||
///
|
||||
/// \return true if there were no problems.
|
||||
bool emitSPDescriptorParent(StackProtectorDescriptor &SPD,
|
||||
MachineBasicBlock *ParentBB);
|
||||
|
||||
/// Codegen the failure basic block for a stack protector check.
|
||||
///
|
||||
/// A failure stack protector machine basic block consists simply of a call to
|
||||
/// __stack_chk_fail().
|
||||
///
|
||||
/// For a high level explanation of how this fits into the stack protector
|
||||
/// generation see the comment on the declaration of class
|
||||
/// StackProtectorDescriptor.
|
||||
///
|
||||
/// \return true if there were no problems.
|
||||
bool emitSPDescriptorFailure(StackProtectorDescriptor &SPD,
|
||||
MachineBasicBlock *FailureBB);
|
||||
|
||||
/// Get the VRegs that represent \p Val.
|
||||
/// Non-aggregate types have just one corresponding VReg and the list can be
|
||||
/// used as a single "unsigned". Aggregates get flattened. If such VRegs do
|
||||
/// not exist, they are created.
|
||||
ArrayRef<Register> getOrCreateVRegs(const Value &Val);
|
||||
|
||||
Register getOrCreateVReg(const Value &Val) {
|
||||
auto Regs = getOrCreateVRegs(Val);
|
||||
if (Regs.empty())
|
||||
return 0;
|
||||
assert(Regs.size() == 1 &&
|
||||
"attempt to get single VReg for aggregate or void");
|
||||
return Regs[0];
|
||||
}
|
||||
|
||||
/// Allocate some vregs and offsets in the VMap. Then populate just the
|
||||
/// offsets while leaving the vregs empty.
|
||||
ValueToVRegInfo::VRegListT &allocateVRegs(const Value &Val);
|
||||
|
||||
/// Get the frame index that represents \p Val.
|
||||
/// If such VReg does not exist, it is created.
|
||||
int getOrCreateFrameIndex(const AllocaInst &AI);
|
||||
|
||||
/// Get the alignment of the given memory operation instruction. This will
|
||||
/// either be the explicitly specified value or the ABI-required alignment for
|
||||
/// the type being accessed (according to the Module's DataLayout).
|
||||
Align getMemOpAlign(const Instruction &I);
|
||||
|
||||
/// Get the MachineBasicBlock that represents \p BB. Specifically, the block
|
||||
/// returned will be the head of the translated block (suitable for branch
|
||||
/// destinations).
|
||||
MachineBasicBlock &getMBB(const BasicBlock &BB);
|
||||
|
||||
/// Record \p NewPred as a Machine predecessor to `Edge.second`, corresponding
|
||||
/// to `Edge.first` at the IR level. This is used when IRTranslation creates
|
||||
/// multiple MachineBasicBlocks for a given IR block and the CFG is no longer
|
||||
/// represented simply by the IR-level CFG.
|
||||
void addMachineCFGPred(CFGEdge Edge, MachineBasicBlock *NewPred);
|
||||
|
||||
/// Returns the Machine IR predecessors for the given IR CFG edge. Usually
|
||||
/// this is just the single MachineBasicBlock corresponding to the predecessor
|
||||
/// in the IR. More complex lowering can result in multiple MachineBasicBlocks
|
||||
/// preceding the original though (e.g. switch instructions).
|
||||
SmallVector<MachineBasicBlock *, 1> getMachinePredBBs(CFGEdge Edge) {
|
||||
auto RemappedEdge = MachinePreds.find(Edge);
|
||||
if (RemappedEdge != MachinePreds.end())
|
||||
return RemappedEdge->second;
|
||||
return SmallVector<MachineBasicBlock *, 4>(1, &getMBB(*Edge.first));
|
||||
}
|
||||
|
||||
/// Return branch probability calculated by BranchProbabilityInfo for IR
|
||||
/// blocks.
|
||||
BranchProbability getEdgeProbability(const MachineBasicBlock *Src,
|
||||
const MachineBasicBlock *Dst) const;
|
||||
|
||||
void addSuccessorWithProb(
|
||||
MachineBasicBlock *Src, MachineBasicBlock *Dst,
|
||||
BranchProbability Prob = BranchProbability::getUnknown());
|
||||
|
||||
public:
|
||||
IRTranslator(CodeGenOpt::Level OptLevel = CodeGenOpt::None);
|
||||
|
||||
StringRef getPassName() const override { return "IRTranslator"; }
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
// Algo:
|
||||
// CallLowering = MF.subtarget.getCallLowering()
|
||||
// F = MF.getParent()
|
||||
// MIRBuilder.reset(MF)
|
||||
// getMBB(F.getEntryBB())
|
||||
// CallLowering->translateArguments(MIRBuilder, F, ValToVReg)
|
||||
// for each bb in F
|
||||
// getMBB(bb)
|
||||
// for each inst in bb
|
||||
// if (!translate(MIRBuilder, inst, ValToVReg, ConstantToSequence))
|
||||
// report_fatal_error("Don't know how to translate input");
|
||||
// finalize()
|
||||
bool runOnMachineFunction(MachineFunction &MF) override;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_GLOBALISEL_IRTRANSLATOR_H
|
||||
67
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/InlineAsmLowering.h
vendored
Normal file
67
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/InlineAsmLowering.h
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
//===- llvm/CodeGen/GlobalISel/InlineAsmLowering.h --------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// This file describes how to lower LLVM inline asm to machine code INLINEASM.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_INLINEASMLOWERING_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_INLINEASMLOWERING_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include <functional>
|
||||
|
||||
namespace llvm {
|
||||
class CallBase;
|
||||
class MachineIRBuilder;
|
||||
class MachineOperand;
|
||||
class Register;
|
||||
class TargetLowering;
|
||||
class Value;
|
||||
|
||||
class InlineAsmLowering {
|
||||
const TargetLowering *TLI;
|
||||
|
||||
virtual void anchor();
|
||||
|
||||
public:
|
||||
/// Lower the given inline asm call instruction
|
||||
/// \p GetOrCreateVRegs is a callback to materialize a register for the
|
||||
/// input and output operands of the inline asm
|
||||
/// \return True if the lowering succeeds, false otherwise.
|
||||
bool lowerInlineAsm(MachineIRBuilder &MIRBuilder, const CallBase &CB,
|
||||
std::function<ArrayRef<Register>(const Value &Val)>
|
||||
GetOrCreateVRegs) const;
|
||||
|
||||
/// Lower the specified operand into the Ops vector.
|
||||
/// \p Val is the IR input value to be lowered
|
||||
/// \p Constraint is the user supplied constraint string
|
||||
/// \p Ops is the vector to be filled with the lowered operands
|
||||
/// \return True if the lowering succeeds, false otherwise.
|
||||
virtual bool lowerAsmOperandForConstraint(Value *Val, StringRef Constraint,
|
||||
std::vector<MachineOperand> &Ops,
|
||||
MachineIRBuilder &MIRBuilder) const;
|
||||
|
||||
protected:
|
||||
/// Getter for generic TargetLowering class.
|
||||
const TargetLowering *getTLI() const { return TLI; }
|
||||
|
||||
/// Getter for target specific TargetLowering class.
|
||||
template <class XXXTargetLowering> const XXXTargetLowering *getTLI() const {
|
||||
return static_cast<const XXXTargetLowering *>(TLI);
|
||||
}
|
||||
|
||||
public:
|
||||
InlineAsmLowering(const TargetLowering *TLI) : TLI(TLI) {}
|
||||
virtual ~InlineAsmLowering() = default;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_GLOBALISEL_INLINEASMLOWERING_H
|
||||
63
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/InstructionSelect.h
vendored
Normal file
63
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/InstructionSelect.h
vendored
Normal file
@@ -0,0 +1,63 @@
|
||||
//== llvm/CodeGen/GlobalISel/InstructionSelect.h -----------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file This file describes the interface of the MachineFunctionPass
|
||||
/// responsible for selecting (possibly generic) machine instructions to
|
||||
/// target-specific instructions.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECT_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECT_H
|
||||
|
||||
#include "llvm/CodeGen/GlobalISel/InstructionSelector.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class BlockFrequencyInfo;
|
||||
class ProfileSummaryInfo;
|
||||
|
||||
/// This pass is responsible for selecting generic machine instructions to
|
||||
/// target-specific instructions. It relies on the InstructionSelector provided
|
||||
/// by the target.
|
||||
/// Selection is done by examining blocks in post-order, and instructions in
|
||||
/// reverse order.
|
||||
///
|
||||
/// \post for all inst in MF: not isPreISelGenericOpcode(inst.opcode)
|
||||
class InstructionSelect : public MachineFunctionPass {
|
||||
public:
|
||||
static char ID;
|
||||
StringRef getPassName() const override { return "InstructionSelect"; }
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
MachineFunctionProperties getRequiredProperties() const override {
|
||||
return MachineFunctionProperties()
|
||||
.set(MachineFunctionProperties::Property::IsSSA)
|
||||
.set(MachineFunctionProperties::Property::Legalized)
|
||||
.set(MachineFunctionProperties::Property::RegBankSelected);
|
||||
}
|
||||
|
||||
MachineFunctionProperties getSetProperties() const override {
|
||||
return MachineFunctionProperties().set(
|
||||
MachineFunctionProperties::Property::Selected);
|
||||
}
|
||||
|
||||
InstructionSelect(CodeGenOpt::Level OL);
|
||||
InstructionSelect();
|
||||
|
||||
bool runOnMachineFunction(MachineFunction &MF) override;
|
||||
|
||||
protected:
|
||||
BlockFrequencyInfo *BFI = nullptr;
|
||||
ProfileSummaryInfo *PSI = nullptr;
|
||||
|
||||
CodeGenOpt::Level OptLevel = CodeGenOpt::None;
|
||||
};
|
||||
} // End namespace llvm.
|
||||
|
||||
#endif
|
||||
569
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/InstructionSelector.h
vendored
Normal file
569
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/InstructionSelector.h
vendored
Normal file
@@ -0,0 +1,569 @@
|
||||
//===- llvm/CodeGen/GlobalISel/InstructionSelector.h ------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
/// \file This file declares the API for the instruction selector.
|
||||
/// This class is responsible for selecting machine instructions.
|
||||
/// It's implemented by the target. It's used by the InstructionSelect pass.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTOR_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTOR_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Analysis/BlockFrequencyInfo.h"
|
||||
#include "llvm/Analysis/ProfileSummaryInfo.h"
|
||||
#include "llvm/CodeGen/GlobalISel/Utils.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/Support/CodeGenCoverage.h"
|
||||
#include "llvm/Support/LowLevelTypeImpl.h"
|
||||
#include <bitset>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <initializer_list>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class APInt;
|
||||
class APFloat;
|
||||
class GISelKnownBits;
|
||||
class MachineInstr;
|
||||
class MachineInstrBuilder;
|
||||
class MachineFunction;
|
||||
class MachineOperand;
|
||||
class MachineRegisterInfo;
|
||||
class RegisterBankInfo;
|
||||
class TargetInstrInfo;
|
||||
class TargetRegisterInfo;
|
||||
|
||||
/// Container class for CodeGen predicate results.
|
||||
/// This is convenient because std::bitset does not have a constructor
|
||||
/// with an initializer list of set bits.
|
||||
///
|
||||
/// Each InstructionSelector subclass should define a PredicateBitset class
|
||||
/// with:
|
||||
/// const unsigned MAX_SUBTARGET_PREDICATES = 192;
|
||||
/// using PredicateBitset = PredicateBitsetImpl<MAX_SUBTARGET_PREDICATES>;
|
||||
/// and updating the constant to suit the target. Tablegen provides a suitable
|
||||
/// definition for the predicates in use in <Target>GenGlobalISel.inc when
|
||||
/// GET_GLOBALISEL_PREDICATE_BITSET is defined.
|
||||
template <std::size_t MaxPredicates>
|
||||
class PredicateBitsetImpl : public std::bitset<MaxPredicates> {
|
||||
public:
|
||||
// Cannot inherit constructors because it's not supported by VC++..
|
||||
PredicateBitsetImpl() = default;
|
||||
|
||||
PredicateBitsetImpl(const std::bitset<MaxPredicates> &B)
|
||||
: std::bitset<MaxPredicates>(B) {}
|
||||
|
||||
PredicateBitsetImpl(std::initializer_list<unsigned> Init) {
|
||||
for (auto I : Init)
|
||||
std::bitset<MaxPredicates>::set(I);
|
||||
}
|
||||
};
|
||||
|
||||
enum {
|
||||
/// Begin a try-block to attempt a match and jump to OnFail if it is
|
||||
/// unsuccessful.
|
||||
/// - OnFail - The MatchTable entry at which to resume if the match fails.
|
||||
///
|
||||
/// FIXME: This ought to take an argument indicating the number of try-blocks
|
||||
/// to exit on failure. It's usually one but the last match attempt of
|
||||
/// a block will need more. The (implemented) alternative is to tack a
|
||||
/// GIM_Reject on the end of each try-block which is simpler but
|
||||
/// requires an extra opcode and iteration in the interpreter on each
|
||||
/// failed match.
|
||||
GIM_Try,
|
||||
|
||||
/// Switch over the opcode on the specified instruction
|
||||
/// - InsnID - Instruction ID
|
||||
/// - LowerBound - numerically minimum opcode supported
|
||||
/// - UpperBound - numerically maximum + 1 opcode supported
|
||||
/// - Default - failure jump target
|
||||
/// - JumpTable... - (UpperBound - LowerBound) (at least 2) jump targets
|
||||
GIM_SwitchOpcode,
|
||||
|
||||
/// Switch over the LLT on the specified instruction operand
|
||||
/// - InsnID - Instruction ID
|
||||
/// - OpIdx - Operand index
|
||||
/// - LowerBound - numerically minimum Type ID supported
|
||||
/// - UpperBound - numerically maximum + 1 Type ID supported
|
||||
/// - Default - failure jump target
|
||||
/// - JumpTable... - (UpperBound - LowerBound) (at least 2) jump targets
|
||||
GIM_SwitchType,
|
||||
|
||||
/// Record the specified instruction
|
||||
/// - NewInsnID - Instruction ID to define
|
||||
/// - InsnID - Instruction ID
|
||||
/// - OpIdx - Operand index
|
||||
GIM_RecordInsn,
|
||||
|
||||
/// Check the feature bits
|
||||
/// - Expected features
|
||||
GIM_CheckFeatures,
|
||||
|
||||
/// Check the opcode on the specified instruction
|
||||
/// - InsnID - Instruction ID
|
||||
/// - Expected opcode
|
||||
GIM_CheckOpcode,
|
||||
|
||||
/// Check the opcode on the specified instruction, checking 2 acceptable
|
||||
/// alternatives.
|
||||
/// - InsnID - Instruction ID
|
||||
/// - Expected opcode
|
||||
/// - Alternative expected opcode
|
||||
GIM_CheckOpcodeIsEither,
|
||||
|
||||
/// Check the instruction has the right number of operands
|
||||
/// - InsnID - Instruction ID
|
||||
/// - Expected number of operands
|
||||
GIM_CheckNumOperands,
|
||||
/// Check an immediate predicate on the specified instruction
|
||||
/// - InsnID - Instruction ID
|
||||
/// - The predicate to test
|
||||
GIM_CheckI64ImmPredicate,
|
||||
/// Check an immediate predicate on the specified instruction via an APInt.
|
||||
/// - InsnID - Instruction ID
|
||||
/// - The predicate to test
|
||||
GIM_CheckAPIntImmPredicate,
|
||||
/// Check a floating point immediate predicate on the specified instruction.
|
||||
/// - InsnID - Instruction ID
|
||||
/// - The predicate to test
|
||||
GIM_CheckAPFloatImmPredicate,
|
||||
/// Check an immediate predicate on the specified instruction
|
||||
/// - InsnID - Instruction ID
|
||||
/// - OpIdx - Operand index
|
||||
/// - The predicate to test
|
||||
GIM_CheckImmOperandPredicate,
|
||||
/// Check a memory operation has the specified atomic ordering.
|
||||
/// - InsnID - Instruction ID
|
||||
/// - Ordering - The AtomicOrdering value
|
||||
GIM_CheckAtomicOrdering,
|
||||
GIM_CheckAtomicOrderingOrStrongerThan,
|
||||
GIM_CheckAtomicOrderingWeakerThan,
|
||||
/// Check the size of the memory access for the given machine memory operand.
|
||||
/// - InsnID - Instruction ID
|
||||
/// - MMOIdx - MMO index
|
||||
/// - Size - The size in bytes of the memory access
|
||||
GIM_CheckMemorySizeEqualTo,
|
||||
|
||||
/// Check the address space of the memory access for the given machine memory
|
||||
/// operand.
|
||||
/// - InsnID - Instruction ID
|
||||
/// - MMOIdx - MMO index
|
||||
/// - NumAddrSpace - Number of valid address spaces
|
||||
/// - AddrSpaceN - An allowed space of the memory access
|
||||
/// - AddrSpaceN+1 ...
|
||||
GIM_CheckMemoryAddressSpace,
|
||||
|
||||
/// Check the minimum alignment of the memory access for the given machine
|
||||
/// memory operand.
|
||||
/// - InsnID - Instruction ID
|
||||
/// - MMOIdx - MMO index
|
||||
/// - MinAlign - Minimum acceptable alignment
|
||||
GIM_CheckMemoryAlignment,
|
||||
|
||||
/// Check the size of the memory access for the given machine memory operand
|
||||
/// against the size of an operand.
|
||||
/// - InsnID - Instruction ID
|
||||
/// - MMOIdx - MMO index
|
||||
/// - OpIdx - The operand index to compare the MMO against
|
||||
GIM_CheckMemorySizeEqualToLLT,
|
||||
GIM_CheckMemorySizeLessThanLLT,
|
||||
GIM_CheckMemorySizeGreaterThanLLT,
|
||||
|
||||
/// Check if this is a vector that can be treated as a vector splat
|
||||
/// constant. This is valid for both G_BUILD_VECTOR as well as
|
||||
/// G_BUILD_VECTOR_TRUNC. For AllOnes refers to individual bits, so a -1
|
||||
/// element.
|
||||
/// - InsnID - Instruction ID
|
||||
GIM_CheckIsBuildVectorAllOnes,
|
||||
GIM_CheckIsBuildVectorAllZeros,
|
||||
|
||||
/// Check a generic C++ instruction predicate
|
||||
/// - InsnID - Instruction ID
|
||||
/// - PredicateID - The ID of the predicate function to call
|
||||
GIM_CheckCxxInsnPredicate,
|
||||
|
||||
/// Check the type for the specified operand
|
||||
/// - InsnID - Instruction ID
|
||||
/// - OpIdx - Operand index
|
||||
/// - Expected type
|
||||
GIM_CheckType,
|
||||
/// Check the type of a pointer to any address space.
|
||||
/// - InsnID - Instruction ID
|
||||
/// - OpIdx - Operand index
|
||||
/// - SizeInBits - The size of the pointer value in bits.
|
||||
GIM_CheckPointerToAny,
|
||||
/// Check the register bank for the specified operand
|
||||
/// - InsnID - Instruction ID
|
||||
/// - OpIdx - Operand index
|
||||
/// - Expected register bank (specified as a register class)
|
||||
GIM_CheckRegBankForClass,
|
||||
|
||||
/// Check the operand matches a complex predicate
|
||||
/// - InsnID - Instruction ID
|
||||
/// - OpIdx - Operand index
|
||||
/// - RendererID - The renderer to hold the result
|
||||
/// - Complex predicate ID
|
||||
GIM_CheckComplexPattern,
|
||||
|
||||
/// Check the operand is a specific integer
|
||||
/// - InsnID - Instruction ID
|
||||
/// - OpIdx - Operand index
|
||||
/// - Expected integer
|
||||
GIM_CheckConstantInt,
|
||||
/// Check the operand is a specific literal integer (i.e. MO.isImm() or
|
||||
/// MO.isCImm() is true).
|
||||
/// - InsnID - Instruction ID
|
||||
/// - OpIdx - Operand index
|
||||
/// - Expected integer
|
||||
GIM_CheckLiteralInt,
|
||||
/// Check the operand is a specific intrinsic ID
|
||||
/// - InsnID - Instruction ID
|
||||
/// - OpIdx - Operand index
|
||||
/// - Expected Intrinsic ID
|
||||
GIM_CheckIntrinsicID,
|
||||
|
||||
/// Check the operand is a specific predicate
|
||||
/// - InsnID - Instruction ID
|
||||
/// - OpIdx - Operand index
|
||||
/// - Expected predicate
|
||||
GIM_CheckCmpPredicate,
|
||||
|
||||
/// Check the specified operand is an MBB
|
||||
/// - InsnID - Instruction ID
|
||||
/// - OpIdx - Operand index
|
||||
GIM_CheckIsMBB,
|
||||
|
||||
/// Check the specified operand is an Imm
|
||||
/// - InsnID - Instruction ID
|
||||
/// - OpIdx - Operand index
|
||||
GIM_CheckIsImm,
|
||||
|
||||
/// Check if the specified operand is safe to fold into the current
|
||||
/// instruction.
|
||||
/// - InsnID - Instruction ID
|
||||
GIM_CheckIsSafeToFold,
|
||||
|
||||
/// Check the specified operands are identical.
|
||||
/// - InsnID - Instruction ID
|
||||
/// - OpIdx - Operand index
|
||||
/// - OtherInsnID - Other instruction ID
|
||||
/// - OtherOpIdx - Other operand index
|
||||
GIM_CheckIsSameOperand,
|
||||
|
||||
/// Predicates with 'let PredicateCodeUsesOperands = 1' need to examine some
|
||||
/// named operands that will be recorded in RecordedOperands. Names of these
|
||||
/// operands are referenced in predicate argument list. Emitter determines
|
||||
/// StoreIdx(corresponds to the order in which names appear in argument list).
|
||||
/// - InsnID - Instruction ID
|
||||
/// - OpIdx - Operand index
|
||||
/// - StoreIdx - Store location in RecordedOperands.
|
||||
GIM_RecordNamedOperand,
|
||||
|
||||
/// Fail the current try-block, or completely fail to match if there is no
|
||||
/// current try-block.
|
||||
GIM_Reject,
|
||||
|
||||
//=== Renderers ===
|
||||
|
||||
/// Mutate an instruction
|
||||
/// - NewInsnID - Instruction ID to define
|
||||
/// - OldInsnID - Instruction ID to mutate
|
||||
/// - NewOpcode - The new opcode to use
|
||||
GIR_MutateOpcode,
|
||||
|
||||
/// Build a new instruction
|
||||
/// - InsnID - Instruction ID to define
|
||||
/// - Opcode - The new opcode to use
|
||||
GIR_BuildMI,
|
||||
|
||||
/// Copy an operand to the specified instruction
|
||||
/// - NewInsnID - Instruction ID to modify
|
||||
/// - OldInsnID - Instruction ID to copy from
|
||||
/// - OpIdx - The operand to copy
|
||||
GIR_Copy,
|
||||
|
||||
/// Copy an operand to the specified instruction or add a zero register if the
|
||||
/// operand is a zero immediate.
|
||||
/// - NewInsnID - Instruction ID to modify
|
||||
/// - OldInsnID - Instruction ID to copy from
|
||||
/// - OpIdx - The operand to copy
|
||||
/// - ZeroReg - The zero register to use
|
||||
GIR_CopyOrAddZeroReg,
|
||||
/// Copy an operand to the specified instruction
|
||||
/// - NewInsnID - Instruction ID to modify
|
||||
/// - OldInsnID - Instruction ID to copy from
|
||||
/// - OpIdx - The operand to copy
|
||||
/// - SubRegIdx - The subregister to copy
|
||||
GIR_CopySubReg,
|
||||
|
||||
/// Add an implicit register def to the specified instruction
|
||||
/// - InsnID - Instruction ID to modify
|
||||
/// - RegNum - The register to add
|
||||
GIR_AddImplicitDef,
|
||||
/// Add an implicit register use to the specified instruction
|
||||
/// - InsnID - Instruction ID to modify
|
||||
/// - RegNum - The register to add
|
||||
GIR_AddImplicitUse,
|
||||
/// Add an register to the specified instruction
|
||||
/// - InsnID - Instruction ID to modify
|
||||
/// - RegNum - The register to add
|
||||
GIR_AddRegister,
|
||||
|
||||
/// Add a temporary register to the specified instruction
|
||||
/// - InsnID - Instruction ID to modify
|
||||
/// - TempRegID - The temporary register ID to add
|
||||
/// - TempRegFlags - The register flags to set
|
||||
GIR_AddTempRegister,
|
||||
|
||||
/// Add a temporary register to the specified instruction
|
||||
/// - InsnID - Instruction ID to modify
|
||||
/// - TempRegID - The temporary register ID to add
|
||||
/// - TempRegFlags - The register flags to set
|
||||
/// - SubRegIndex - The subregister index to set
|
||||
GIR_AddTempSubRegister,
|
||||
|
||||
/// Add an immediate to the specified instruction
|
||||
/// - InsnID - Instruction ID to modify
|
||||
/// - Imm - The immediate to add
|
||||
GIR_AddImm,
|
||||
/// Render complex operands to the specified instruction
|
||||
/// - InsnID - Instruction ID to modify
|
||||
/// - RendererID - The renderer to call
|
||||
GIR_ComplexRenderer,
|
||||
|
||||
/// Render sub-operands of complex operands to the specified instruction
|
||||
/// - InsnID - Instruction ID to modify
|
||||
/// - RendererID - The renderer to call
|
||||
/// - RenderOpID - The suboperand to render.
|
||||
GIR_ComplexSubOperandRenderer,
|
||||
/// Render operands to the specified instruction using a custom function
|
||||
/// - InsnID - Instruction ID to modify
|
||||
/// - OldInsnID - Instruction ID to get the matched operand from
|
||||
/// - RendererFnID - Custom renderer function to call
|
||||
GIR_CustomRenderer,
|
||||
|
||||
/// Render operands to the specified instruction using a custom function,
|
||||
/// reading from a specific operand.
|
||||
/// - InsnID - Instruction ID to modify
|
||||
/// - OldInsnID - Instruction ID to get the matched operand from
|
||||
/// - OpIdx - Operand index in OldInsnID the render function should read from..
|
||||
/// - RendererFnID - Custom renderer function to call
|
||||
GIR_CustomOperandRenderer,
|
||||
|
||||
/// Render a G_CONSTANT operator as a sign-extended immediate.
|
||||
/// - NewInsnID - Instruction ID to modify
|
||||
/// - OldInsnID - Instruction ID to copy from
|
||||
/// The operand index is implicitly 1.
|
||||
GIR_CopyConstantAsSImm,
|
||||
|
||||
/// Render a G_FCONSTANT operator as a sign-extended immediate.
|
||||
/// - NewInsnID - Instruction ID to modify
|
||||
/// - OldInsnID - Instruction ID to copy from
|
||||
/// The operand index is implicitly 1.
|
||||
GIR_CopyFConstantAsFPImm,
|
||||
|
||||
/// Constrain an instruction operand to a register class.
|
||||
/// - InsnID - Instruction ID to modify
|
||||
/// - OpIdx - Operand index
|
||||
/// - RCEnum - Register class enumeration value
|
||||
GIR_ConstrainOperandRC,
|
||||
|
||||
/// Constrain an instructions operands according to the instruction
|
||||
/// description.
|
||||
/// - InsnID - Instruction ID to modify
|
||||
GIR_ConstrainSelectedInstOperands,
|
||||
|
||||
/// Merge all memory operands into instruction.
|
||||
/// - InsnID - Instruction ID to modify
|
||||
/// - MergeInsnID... - One or more Instruction ID to merge into the result.
|
||||
/// - GIU_MergeMemOperands_EndOfList - Terminates the list of instructions to
|
||||
/// merge.
|
||||
GIR_MergeMemOperands,
|
||||
|
||||
/// Erase from parent.
|
||||
/// - InsnID - Instruction ID to erase
|
||||
GIR_EraseFromParent,
|
||||
|
||||
/// Create a new temporary register that's not constrained.
|
||||
/// - TempRegID - The temporary register ID to initialize.
|
||||
/// - Expected type
|
||||
GIR_MakeTempReg,
|
||||
|
||||
/// A successful emission
|
||||
GIR_Done,
|
||||
|
||||
/// Increment the rule coverage counter.
|
||||
/// - RuleID - The ID of the rule that was covered.
|
||||
GIR_Coverage,
|
||||
|
||||
/// Keeping track of the number of the GI opcodes. Must be the last entry.
|
||||
GIU_NumOpcodes,
|
||||
};
|
||||
|
||||
enum {
|
||||
/// Indicates the end of the variable-length MergeInsnID list in a
|
||||
/// GIR_MergeMemOperands opcode.
|
||||
GIU_MergeMemOperands_EndOfList = -1,
|
||||
};
|
||||
|
||||
/// Provides the logic to select generic machine instructions.
|
||||
class InstructionSelector {
|
||||
public:
|
||||
virtual ~InstructionSelector() = default;
|
||||
|
||||
/// Select the (possibly generic) instruction \p I to only use target-specific
|
||||
/// opcodes. It is OK to insert multiple instructions, but they cannot be
|
||||
/// generic pre-isel instructions.
|
||||
///
|
||||
/// \returns whether selection succeeded.
|
||||
/// \pre I.getParent() && I.getParent()->getParent()
|
||||
/// \post
|
||||
/// if returns true:
|
||||
/// for I in all mutated/inserted instructions:
|
||||
/// !isPreISelGenericOpcode(I.getOpcode())
|
||||
virtual bool select(MachineInstr &I) = 0;
|
||||
|
||||
CodeGenCoverage *CoverageInfo = nullptr;
|
||||
GISelKnownBits *KnownBits = nullptr;
|
||||
MachineFunction *MF = nullptr;
|
||||
ProfileSummaryInfo *PSI = nullptr;
|
||||
BlockFrequencyInfo *BFI = nullptr;
|
||||
// For some predicates, we need to track the current MBB.
|
||||
MachineBasicBlock *CurMBB = nullptr;
|
||||
|
||||
virtual void setupGeneratedPerFunctionState(MachineFunction &MF) {
|
||||
llvm_unreachable("TableGen should have emitted implementation");
|
||||
}
|
||||
|
||||
/// Setup per-MF selector state.
|
||||
virtual void setupMF(MachineFunction &mf, GISelKnownBits *KB,
|
||||
CodeGenCoverage &covinfo, ProfileSummaryInfo *psi,
|
||||
BlockFrequencyInfo *bfi) {
|
||||
CoverageInfo = &covinfo;
|
||||
KnownBits = KB;
|
||||
MF = &mf;
|
||||
PSI = psi;
|
||||
BFI = bfi;
|
||||
CurMBB = nullptr;
|
||||
setupGeneratedPerFunctionState(mf);
|
||||
}
|
||||
|
||||
protected:
|
||||
using ComplexRendererFns =
|
||||
Optional<SmallVector<std::function<void(MachineInstrBuilder &)>, 4>>;
|
||||
using RecordedMIVector = SmallVector<MachineInstr *, 4>;
|
||||
using NewMIVector = SmallVector<MachineInstrBuilder, 4>;
|
||||
|
||||
struct MatcherState {
|
||||
std::vector<ComplexRendererFns::value_type> Renderers;
|
||||
RecordedMIVector MIs;
|
||||
DenseMap<unsigned, unsigned> TempRegisters;
|
||||
/// Named operands that predicate with 'let PredicateCodeUsesOperands = 1'
|
||||
/// referenced in its argument list. Operands are inserted at index set by
|
||||
/// emitter, it corresponds to the order in which names appear in argument
|
||||
/// list. Currently such predicates don't have more than 3 arguments.
|
||||
std::array<const MachineOperand *, 3> RecordedOperands;
|
||||
|
||||
MatcherState(unsigned MaxRenderers);
|
||||
};
|
||||
|
||||
bool shouldOptForSize(const MachineFunction *MF) const {
|
||||
const auto &F = MF->getFunction();
|
||||
return F.hasOptSize() || F.hasMinSize() ||
|
||||
(PSI && BFI && CurMBB && llvm::shouldOptForSize(*CurMBB, PSI, BFI));
|
||||
}
|
||||
|
||||
public:
|
||||
template <class PredicateBitset, class ComplexMatcherMemFn,
|
||||
class CustomRendererFn>
|
||||
struct ISelInfoTy {
|
||||
ISelInfoTy(const LLT *TypeObjects, size_t NumTypeObjects,
|
||||
const PredicateBitset *FeatureBitsets,
|
||||
const ComplexMatcherMemFn *ComplexPredicates,
|
||||
const CustomRendererFn *CustomRenderers)
|
||||
: TypeObjects(TypeObjects),
|
||||
FeatureBitsets(FeatureBitsets),
|
||||
ComplexPredicates(ComplexPredicates),
|
||||
CustomRenderers(CustomRenderers) {
|
||||
|
||||
for (size_t I = 0; I < NumTypeObjects; ++I)
|
||||
TypeIDMap[TypeObjects[I]] = I;
|
||||
}
|
||||
const LLT *TypeObjects;
|
||||
const PredicateBitset *FeatureBitsets;
|
||||
const ComplexMatcherMemFn *ComplexPredicates;
|
||||
const CustomRendererFn *CustomRenderers;
|
||||
|
||||
SmallDenseMap<LLT, unsigned, 64> TypeIDMap;
|
||||
};
|
||||
|
||||
protected:
|
||||
InstructionSelector();
|
||||
|
||||
/// Execute a given matcher table and return true if the match was successful
|
||||
/// and false otherwise.
|
||||
template <class TgtInstructionSelector, class PredicateBitset,
|
||||
class ComplexMatcherMemFn, class CustomRendererFn>
|
||||
bool executeMatchTable(
|
||||
TgtInstructionSelector &ISel, NewMIVector &OutMIs, MatcherState &State,
|
||||
const ISelInfoTy<PredicateBitset, ComplexMatcherMemFn, CustomRendererFn>
|
||||
&ISelInfo,
|
||||
const int64_t *MatchTable, const TargetInstrInfo &TII,
|
||||
MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI,
|
||||
const RegisterBankInfo &RBI, const PredicateBitset &AvailableFeatures,
|
||||
CodeGenCoverage &CoverageInfo) const;
|
||||
|
||||
virtual const int64_t *getMatchTable() const {
|
||||
llvm_unreachable("Should have been overridden by tablegen if used");
|
||||
}
|
||||
|
||||
virtual bool testImmPredicate_I64(unsigned, int64_t) const {
|
||||
llvm_unreachable(
|
||||
"Subclasses must override this with a tablegen-erated function");
|
||||
}
|
||||
virtual bool testImmPredicate_APInt(unsigned, const APInt &) const {
|
||||
llvm_unreachable(
|
||||
"Subclasses must override this with a tablegen-erated function");
|
||||
}
|
||||
virtual bool testImmPredicate_APFloat(unsigned, const APFloat &) const {
|
||||
llvm_unreachable(
|
||||
"Subclasses must override this with a tablegen-erated function");
|
||||
}
|
||||
virtual bool testMIPredicate_MI(
|
||||
unsigned, const MachineInstr &,
|
||||
const std::array<const MachineOperand *, 3> &Operands) const {
|
||||
llvm_unreachable(
|
||||
"Subclasses must override this with a tablegen-erated function");
|
||||
}
|
||||
|
||||
bool isOperandImmEqual(const MachineOperand &MO, int64_t Value,
|
||||
const MachineRegisterInfo &MRI) const;
|
||||
|
||||
/// Return true if the specified operand is a G_PTR_ADD with a G_CONSTANT on the
|
||||
/// right-hand side. GlobalISel's separation of pointer and integer types
|
||||
/// means that we don't need to worry about G_OR with equivalent semantics.
|
||||
bool isBaseWithConstantOffset(const MachineOperand &Root,
|
||||
const MachineRegisterInfo &MRI) const;
|
||||
|
||||
/// Return true if MI can obviously be folded into IntoMI.
|
||||
/// MI and IntoMI do not need to be in the same basic blocks, but MI must
|
||||
/// precede IntoMI.
|
||||
bool isObviouslySafeToFold(MachineInstr &MI, MachineInstr &IntoMI) const;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_GLOBALISEL_INSTRUCTIONSELECTOR_H
|
||||
1157
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h
vendored
Normal file
1157
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/InstructionSelectorImpl.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
481
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/LegacyLegalizerInfo.h
vendored
Normal file
481
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/LegacyLegalizerInfo.h
vendored
Normal file
@@ -0,0 +1,481 @@
|
||||
//===- llvm/CodeGen/GlobalISel/LegacyLegalizerInfo.h ------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// Interface for Targets to specify which operations they can successfully
|
||||
/// select and how the others should be expanded most efficiently.
|
||||
/// This implementation has been deprecated for a long time but it still in use
|
||||
/// in a few places.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_LEGACYLEGALIZERINFO_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_LEGACYLEGALIZERINFO_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/CodeGen/TargetOpcodes.h"
|
||||
#include "llvm/Support/LowLevelTypeImpl.h"
|
||||
#include <unordered_map>
|
||||
|
||||
namespace llvm {
|
||||
struct LegalityQuery;
|
||||
|
||||
namespace LegacyLegalizeActions {
|
||||
enum LegacyLegalizeAction : std::uint8_t {
|
||||
/// The operation is expected to be selectable directly by the target, and
|
||||
/// no transformation is necessary.
|
||||
Legal,
|
||||
|
||||
/// The operation should be synthesized from multiple instructions acting on
|
||||
/// a narrower scalar base-type. For example a 64-bit add might be
|
||||
/// implemented in terms of 32-bit add-with-carry.
|
||||
NarrowScalar,
|
||||
|
||||
/// The operation should be implemented in terms of a wider scalar
|
||||
/// base-type. For example a <2 x s8> add could be implemented as a <2
|
||||
/// x s32> add (ignoring the high bits).
|
||||
WidenScalar,
|
||||
|
||||
/// The (vector) operation should be implemented by splitting it into
|
||||
/// sub-vectors where the operation is legal. For example a <8 x s64> add
|
||||
/// might be implemented as 4 separate <2 x s64> adds.
|
||||
FewerElements,
|
||||
|
||||
/// The (vector) operation should be implemented by widening the input
|
||||
/// vector and ignoring the lanes added by doing so. For example <2 x i8> is
|
||||
/// rarely legal, but you might perform an <8 x i8> and then only look at
|
||||
/// the first two results.
|
||||
MoreElements,
|
||||
|
||||
/// Perform the operation on a different, but equivalently sized type.
|
||||
Bitcast,
|
||||
|
||||
/// The operation itself must be expressed in terms of simpler actions on
|
||||
/// this target. E.g. a SREM replaced by an SDIV and subtraction.
|
||||
Lower,
|
||||
|
||||
/// The operation should be implemented as a call to some kind of runtime
|
||||
/// support library. For example this usually happens on machines that don't
|
||||
/// support floating-point operations natively.
|
||||
Libcall,
|
||||
|
||||
/// The target wants to do something special with this combination of
|
||||
/// operand and type. A callback will be issued when it is needed.
|
||||
Custom,
|
||||
|
||||
/// This operation is completely unsupported on the target. A programming
|
||||
/// error has occurred.
|
||||
Unsupported,
|
||||
|
||||
/// Sentinel value for when no action was found in the specified table.
|
||||
NotFound,
|
||||
};
|
||||
} // end namespace LegacyLegalizeActions
|
||||
raw_ostream &operator<<(raw_ostream &OS,
|
||||
LegacyLegalizeActions::LegacyLegalizeAction Action);
|
||||
|
||||
/// Legalization is decided based on an instruction's opcode, which type slot
|
||||
/// we're considering, and what the existing type is. These aspects are gathered
|
||||
/// together for convenience in the InstrAspect class.
|
||||
struct InstrAspect {
|
||||
unsigned Opcode;
|
||||
unsigned Idx = 0;
|
||||
LLT Type;
|
||||
|
||||
InstrAspect(unsigned Opcode, LLT Type) : Opcode(Opcode), Type(Type) {}
|
||||
InstrAspect(unsigned Opcode, unsigned Idx, LLT Type)
|
||||
: Opcode(Opcode), Idx(Idx), Type(Type) {}
|
||||
|
||||
bool operator==(const InstrAspect &RHS) const {
|
||||
return Opcode == RHS.Opcode && Idx == RHS.Idx && Type == RHS.Type;
|
||||
}
|
||||
};
|
||||
|
||||
/// The result of a query. It either indicates a final answer of Legal or
|
||||
/// Unsupported or describes an action that must be taken to make an operation
|
||||
/// more legal.
|
||||
struct LegacyLegalizeActionStep {
|
||||
/// The action to take or the final answer.
|
||||
LegacyLegalizeActions::LegacyLegalizeAction Action;
|
||||
/// If describing an action, the type index to change. Otherwise zero.
|
||||
unsigned TypeIdx;
|
||||
/// If describing an action, the new type for TypeIdx. Otherwise LLT{}.
|
||||
LLT NewType;
|
||||
|
||||
LegacyLegalizeActionStep(LegacyLegalizeActions::LegacyLegalizeAction Action,
|
||||
unsigned TypeIdx, const LLT NewType)
|
||||
: Action(Action), TypeIdx(TypeIdx), NewType(NewType) {}
|
||||
|
||||
bool operator==(const LegacyLegalizeActionStep &RHS) const {
|
||||
return std::tie(Action, TypeIdx, NewType) ==
|
||||
std::tie(RHS.Action, RHS.TypeIdx, RHS.NewType);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
class LegacyLegalizerInfo {
|
||||
public:
|
||||
using SizeAndAction =
|
||||
std::pair<uint16_t, LegacyLegalizeActions::LegacyLegalizeAction>;
|
||||
using SizeAndActionsVec = std::vector<SizeAndAction>;
|
||||
using SizeChangeStrategy =
|
||||
std::function<SizeAndActionsVec(const SizeAndActionsVec &v)>;
|
||||
|
||||
LegacyLegalizerInfo();
|
||||
|
||||
static bool needsLegalizingToDifferentSize(
|
||||
const LegacyLegalizeActions::LegacyLegalizeAction Action) {
|
||||
using namespace LegacyLegalizeActions;
|
||||
switch (Action) {
|
||||
case NarrowScalar:
|
||||
case WidenScalar:
|
||||
case FewerElements:
|
||||
case MoreElements:
|
||||
case Unsupported:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute any ancillary tables needed to quickly decide how an operation
|
||||
/// should be handled. This must be called after all "set*Action"methods but
|
||||
/// before any query is made or incorrect results may be returned.
|
||||
void computeTables();
|
||||
|
||||
/// More friendly way to set an action for common types that have an LLT
|
||||
/// representation.
|
||||
/// The LegacyLegalizeAction must be one for which
|
||||
/// NeedsLegalizingToDifferentSize returns false.
|
||||
void setAction(const InstrAspect &Aspect,
|
||||
LegacyLegalizeActions::LegacyLegalizeAction Action) {
|
||||
assert(!needsLegalizingToDifferentSize(Action));
|
||||
TablesInitialized = false;
|
||||
const unsigned OpcodeIdx = Aspect.Opcode - FirstOp;
|
||||
if (SpecifiedActions[OpcodeIdx].size() <= Aspect.Idx)
|
||||
SpecifiedActions[OpcodeIdx].resize(Aspect.Idx + 1);
|
||||
SpecifiedActions[OpcodeIdx][Aspect.Idx][Aspect.Type] = Action;
|
||||
}
|
||||
|
||||
/// The setAction calls record the non-size-changing legalization actions
|
||||
/// to take on specifically-sized types. The SizeChangeStrategy defines what
|
||||
/// to do when the size of the type needs to be changed to reach a legally
|
||||
/// sized type (i.e., one that was defined through a setAction call).
|
||||
/// e.g.
|
||||
/// setAction ({G_ADD, 0, LLT::scalar(32)}, Legal);
|
||||
/// setLegalizeScalarToDifferentSizeStrategy(
|
||||
/// G_ADD, 0, widenToLargerTypesAndNarrowToLargest);
|
||||
/// will end up defining getAction({G_ADD, 0, T}) to return the following
|
||||
/// actions for different scalar types T:
|
||||
/// LLT::scalar(1)..LLT::scalar(31): {WidenScalar, 0, LLT::scalar(32)}
|
||||
/// LLT::scalar(32): {Legal, 0, LLT::scalar(32)}
|
||||
/// LLT::scalar(33)..: {NarrowScalar, 0, LLT::scalar(32)}
|
||||
///
|
||||
/// If no SizeChangeAction gets defined, through this function,
|
||||
/// the default is unsupportedForDifferentSizes.
|
||||
void setLegalizeScalarToDifferentSizeStrategy(const unsigned Opcode,
|
||||
const unsigned TypeIdx,
|
||||
SizeChangeStrategy S) {
|
||||
const unsigned OpcodeIdx = Opcode - FirstOp;
|
||||
if (ScalarSizeChangeStrategies[OpcodeIdx].size() <= TypeIdx)
|
||||
ScalarSizeChangeStrategies[OpcodeIdx].resize(TypeIdx + 1);
|
||||
ScalarSizeChangeStrategies[OpcodeIdx][TypeIdx] = S;
|
||||
}
|
||||
|
||||
/// See also setLegalizeScalarToDifferentSizeStrategy.
|
||||
/// This function allows to set the SizeChangeStrategy for vector elements.
|
||||
void setLegalizeVectorElementToDifferentSizeStrategy(const unsigned Opcode,
|
||||
const unsigned TypeIdx,
|
||||
SizeChangeStrategy S) {
|
||||
const unsigned OpcodeIdx = Opcode - FirstOp;
|
||||
if (VectorElementSizeChangeStrategies[OpcodeIdx].size() <= TypeIdx)
|
||||
VectorElementSizeChangeStrategies[OpcodeIdx].resize(TypeIdx + 1);
|
||||
VectorElementSizeChangeStrategies[OpcodeIdx][TypeIdx] = S;
|
||||
}
|
||||
|
||||
/// A SizeChangeStrategy for the common case where legalization for a
|
||||
/// particular operation consists of only supporting a specific set of type
|
||||
/// sizes. E.g.
|
||||
/// setAction ({G_DIV, 0, LLT::scalar(32)}, Legal);
|
||||
/// setAction ({G_DIV, 0, LLT::scalar(64)}, Legal);
|
||||
/// setLegalizeScalarToDifferentSizeStrategy(
|
||||
/// G_DIV, 0, unsupportedForDifferentSizes);
|
||||
/// will result in getAction({G_DIV, 0, T}) to return Legal for s32 and s64,
|
||||
/// and Unsupported for all other scalar types T.
|
||||
static SizeAndActionsVec
|
||||
unsupportedForDifferentSizes(const SizeAndActionsVec &v) {
|
||||
using namespace LegacyLegalizeActions;
|
||||
return increaseToLargerTypesAndDecreaseToLargest(v, Unsupported,
|
||||
Unsupported);
|
||||
}
|
||||
|
||||
/// A SizeChangeStrategy for the common case where legalization for a
|
||||
/// particular operation consists of widening the type to a large legal type,
|
||||
/// unless there is no such type and then instead it should be narrowed to the
|
||||
/// largest legal type.
|
||||
static SizeAndActionsVec
|
||||
widenToLargerTypesAndNarrowToLargest(const SizeAndActionsVec &v) {
|
||||
using namespace LegacyLegalizeActions;
|
||||
assert(v.size() > 0 &&
|
||||
"At least one size that can be legalized towards is needed"
|
||||
" for this SizeChangeStrategy");
|
||||
return increaseToLargerTypesAndDecreaseToLargest(v, WidenScalar,
|
||||
NarrowScalar);
|
||||
}
|
||||
|
||||
static SizeAndActionsVec
|
||||
widenToLargerTypesUnsupportedOtherwise(const SizeAndActionsVec &v) {
|
||||
using namespace LegacyLegalizeActions;
|
||||
return increaseToLargerTypesAndDecreaseToLargest(v, WidenScalar,
|
||||
Unsupported);
|
||||
}
|
||||
|
||||
static SizeAndActionsVec
|
||||
narrowToSmallerAndUnsupportedIfTooSmall(const SizeAndActionsVec &v) {
|
||||
using namespace LegacyLegalizeActions;
|
||||
return decreaseToSmallerTypesAndIncreaseToSmallest(v, NarrowScalar,
|
||||
Unsupported);
|
||||
}
|
||||
|
||||
static SizeAndActionsVec
|
||||
narrowToSmallerAndWidenToSmallest(const SizeAndActionsVec &v) {
|
||||
using namespace LegacyLegalizeActions;
|
||||
assert(v.size() > 0 &&
|
||||
"At least one size that can be legalized towards is needed"
|
||||
" for this SizeChangeStrategy");
|
||||
return decreaseToSmallerTypesAndIncreaseToSmallest(v, NarrowScalar,
|
||||
WidenScalar);
|
||||
}
|
||||
|
||||
/// A SizeChangeStrategy for the common case where legalization for a
|
||||
/// particular vector operation consists of having more elements in the
|
||||
/// vector, to a type that is legal. Unless there is no such type and then
|
||||
/// instead it should be legalized towards the widest vector that's still
|
||||
/// legal. E.g.
|
||||
/// setAction({G_ADD, LLT::vector(8, 8)}, Legal);
|
||||
/// setAction({G_ADD, LLT::vector(16, 8)}, Legal);
|
||||
/// setAction({G_ADD, LLT::vector(2, 32)}, Legal);
|
||||
/// setAction({G_ADD, LLT::vector(4, 32)}, Legal);
|
||||
/// setLegalizeVectorElementToDifferentSizeStrategy(
|
||||
/// G_ADD, 0, moreToWiderTypesAndLessToWidest);
|
||||
/// will result in the following getAction results:
|
||||
/// * getAction({G_ADD, LLT::vector(8,8)}) returns
|
||||
/// (Legal, vector(8,8)).
|
||||
/// * getAction({G_ADD, LLT::vector(9,8)}) returns
|
||||
/// (MoreElements, vector(16,8)).
|
||||
/// * getAction({G_ADD, LLT::vector(8,32)}) returns
|
||||
/// (FewerElements, vector(4,32)).
|
||||
static SizeAndActionsVec
|
||||
moreToWiderTypesAndLessToWidest(const SizeAndActionsVec &v) {
|
||||
using namespace LegacyLegalizeActions;
|
||||
return increaseToLargerTypesAndDecreaseToLargest(v, MoreElements,
|
||||
FewerElements);
|
||||
}
|
||||
|
||||
/// Helper function to implement many typical SizeChangeStrategy functions.
|
||||
static SizeAndActionsVec increaseToLargerTypesAndDecreaseToLargest(
|
||||
const SizeAndActionsVec &v,
|
||||
LegacyLegalizeActions::LegacyLegalizeAction IncreaseAction,
|
||||
LegacyLegalizeActions::LegacyLegalizeAction DecreaseAction);
|
||||
/// Helper function to implement many typical SizeChangeStrategy functions.
|
||||
static SizeAndActionsVec decreaseToSmallerTypesAndIncreaseToSmallest(
|
||||
const SizeAndActionsVec &v,
|
||||
LegacyLegalizeActions::LegacyLegalizeAction DecreaseAction,
|
||||
LegacyLegalizeActions::LegacyLegalizeAction IncreaseAction);
|
||||
|
||||
LegacyLegalizeActionStep getAction(const LegalityQuery &Query) const;
|
||||
|
||||
unsigned getOpcodeIdxForOpcode(unsigned Opcode) const;
|
||||
|
||||
private:
|
||||
/// Determine what action should be taken to legalize the given generic
|
||||
/// instruction opcode, type-index and type. Requires computeTables to have
|
||||
/// been called.
|
||||
///
|
||||
/// \returns a pair consisting of the kind of legalization that should be
|
||||
/// performed and the destination type.
|
||||
std::pair<LegacyLegalizeActions::LegacyLegalizeAction, LLT>
|
||||
getAspectAction(const InstrAspect &Aspect) const;
|
||||
|
||||
/// The SizeAndActionsVec is a representation mapping between all natural
|
||||
/// numbers and an Action. The natural number represents the bit size of
|
||||
/// the InstrAspect. For example, for a target with native support for 32-bit
|
||||
/// and 64-bit additions, you'd express that as:
|
||||
/// setScalarAction(G_ADD, 0,
|
||||
/// {{1, WidenScalar}, // bit sizes [ 1, 31[
|
||||
/// {32, Legal}, // bit sizes [32, 33[
|
||||
/// {33, WidenScalar}, // bit sizes [33, 64[
|
||||
/// {64, Legal}, // bit sizes [64, 65[
|
||||
/// {65, NarrowScalar} // bit sizes [65, +inf[
|
||||
/// });
|
||||
/// It may be that only 64-bit pointers are supported on your target:
|
||||
/// setPointerAction(G_PTR_ADD, 0, LLT:pointer(1),
|
||||
/// {{1, Unsupported}, // bit sizes [ 1, 63[
|
||||
/// {64, Legal}, // bit sizes [64, 65[
|
||||
/// {65, Unsupported}, // bit sizes [65, +inf[
|
||||
/// });
|
||||
void setScalarAction(const unsigned Opcode, const unsigned TypeIndex,
|
||||
const SizeAndActionsVec &SizeAndActions) {
|
||||
const unsigned OpcodeIdx = Opcode - FirstOp;
|
||||
SmallVector<SizeAndActionsVec, 1> &Actions = ScalarActions[OpcodeIdx];
|
||||
setActions(TypeIndex, Actions, SizeAndActions);
|
||||
}
|
||||
void setPointerAction(const unsigned Opcode, const unsigned TypeIndex,
|
||||
const unsigned AddressSpace,
|
||||
const SizeAndActionsVec &SizeAndActions) {
|
||||
const unsigned OpcodeIdx = Opcode - FirstOp;
|
||||
if (AddrSpace2PointerActions[OpcodeIdx].find(AddressSpace) ==
|
||||
AddrSpace2PointerActions[OpcodeIdx].end())
|
||||
AddrSpace2PointerActions[OpcodeIdx][AddressSpace] = {{}};
|
||||
SmallVector<SizeAndActionsVec, 1> &Actions =
|
||||
AddrSpace2PointerActions[OpcodeIdx].find(AddressSpace)->second;
|
||||
setActions(TypeIndex, Actions, SizeAndActions);
|
||||
}
|
||||
|
||||
/// If an operation on a given vector type (say <M x iN>) isn't explicitly
|
||||
/// specified, we proceed in 2 stages. First we legalize the underlying scalar
|
||||
/// (so that there's at least one legal vector with that scalar), then we
|
||||
/// adjust the number of elements in the vector so that it is legal. The
|
||||
/// desired action in the first step is controlled by this function.
|
||||
void setScalarInVectorAction(const unsigned Opcode, const unsigned TypeIndex,
|
||||
const SizeAndActionsVec &SizeAndActions) {
|
||||
unsigned OpcodeIdx = Opcode - FirstOp;
|
||||
SmallVector<SizeAndActionsVec, 1> &Actions =
|
||||
ScalarInVectorActions[OpcodeIdx];
|
||||
setActions(TypeIndex, Actions, SizeAndActions);
|
||||
}
|
||||
|
||||
/// See also setScalarInVectorAction.
|
||||
/// This function let's you specify the number of elements in a vector that
|
||||
/// are legal for a legal element size.
|
||||
void setVectorNumElementAction(const unsigned Opcode,
|
||||
const unsigned TypeIndex,
|
||||
const unsigned ElementSize,
|
||||
const SizeAndActionsVec &SizeAndActions) {
|
||||
const unsigned OpcodeIdx = Opcode - FirstOp;
|
||||
if (NumElements2Actions[OpcodeIdx].find(ElementSize) ==
|
||||
NumElements2Actions[OpcodeIdx].end())
|
||||
NumElements2Actions[OpcodeIdx][ElementSize] = {{}};
|
||||
SmallVector<SizeAndActionsVec, 1> &Actions =
|
||||
NumElements2Actions[OpcodeIdx].find(ElementSize)->second;
|
||||
setActions(TypeIndex, Actions, SizeAndActions);
|
||||
}
|
||||
|
||||
/// A partial SizeAndActionsVec potentially doesn't cover all bit sizes,
|
||||
/// i.e. it's OK if it doesn't start from size 1.
|
||||
static void checkPartialSizeAndActionsVector(const SizeAndActionsVec& v) {
|
||||
using namespace LegacyLegalizeActions;
|
||||
#ifndef NDEBUG
|
||||
// The sizes should be in increasing order
|
||||
int prev_size = -1;
|
||||
for(auto SizeAndAction: v) {
|
||||
assert(SizeAndAction.first > prev_size);
|
||||
prev_size = SizeAndAction.first;
|
||||
}
|
||||
// - for every Widen action, there should be a larger bitsize that
|
||||
// can be legalized towards (e.g. Legal, Lower, Libcall or Custom
|
||||
// action).
|
||||
// - for every Narrow action, there should be a smaller bitsize that
|
||||
// can be legalized towards.
|
||||
int SmallestNarrowIdx = -1;
|
||||
int LargestWidenIdx = -1;
|
||||
int SmallestLegalizableToSameSizeIdx = -1;
|
||||
int LargestLegalizableToSameSizeIdx = -1;
|
||||
for(size_t i=0; i<v.size(); ++i) {
|
||||
switch (v[i].second) {
|
||||
case FewerElements:
|
||||
case NarrowScalar:
|
||||
if (SmallestNarrowIdx == -1)
|
||||
SmallestNarrowIdx = i;
|
||||
break;
|
||||
case WidenScalar:
|
||||
case MoreElements:
|
||||
LargestWidenIdx = i;
|
||||
break;
|
||||
case Unsupported:
|
||||
break;
|
||||
default:
|
||||
if (SmallestLegalizableToSameSizeIdx == -1)
|
||||
SmallestLegalizableToSameSizeIdx = i;
|
||||
LargestLegalizableToSameSizeIdx = i;
|
||||
}
|
||||
}
|
||||
if (SmallestNarrowIdx != -1) {
|
||||
assert(SmallestLegalizableToSameSizeIdx != -1);
|
||||
assert(SmallestNarrowIdx > SmallestLegalizableToSameSizeIdx);
|
||||
}
|
||||
if (LargestWidenIdx != -1)
|
||||
assert(LargestWidenIdx < LargestLegalizableToSameSizeIdx);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// A full SizeAndActionsVec must cover all bit sizes, i.e. must start with
|
||||
/// from size 1.
|
||||
static void checkFullSizeAndActionsVector(const SizeAndActionsVec& v) {
|
||||
#ifndef NDEBUG
|
||||
// Data structure invariant: The first bit size must be size 1.
|
||||
assert(v.size() >= 1);
|
||||
assert(v[0].first == 1);
|
||||
checkPartialSizeAndActionsVector(v);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Sets actions for all bit sizes on a particular generic opcode, type
|
||||
/// index and scalar or pointer type.
|
||||
void setActions(unsigned TypeIndex,
|
||||
SmallVector<SizeAndActionsVec, 1> &Actions,
|
||||
const SizeAndActionsVec &SizeAndActions) {
|
||||
checkFullSizeAndActionsVector(SizeAndActions);
|
||||
if (Actions.size() <= TypeIndex)
|
||||
Actions.resize(TypeIndex + 1);
|
||||
Actions[TypeIndex] = SizeAndActions;
|
||||
}
|
||||
|
||||
static SizeAndAction findAction(const SizeAndActionsVec &Vec,
|
||||
const uint32_t Size);
|
||||
|
||||
/// Returns the next action needed to get the scalar or pointer type closer
|
||||
/// to being legal
|
||||
/// E.g. findLegalAction({G_REM, 13}) should return
|
||||
/// (WidenScalar, 32). After that, findLegalAction({G_REM, 32}) will
|
||||
/// probably be called, which should return (Lower, 32).
|
||||
/// This is assuming the setScalarAction on G_REM was something like:
|
||||
/// setScalarAction(G_REM, 0,
|
||||
/// {{1, WidenScalar}, // bit sizes [ 1, 31[
|
||||
/// {32, Lower}, // bit sizes [32, 33[
|
||||
/// {33, NarrowScalar} // bit sizes [65, +inf[
|
||||
/// });
|
||||
std::pair<LegacyLegalizeActions::LegacyLegalizeAction, LLT>
|
||||
findScalarLegalAction(const InstrAspect &Aspect) const;
|
||||
|
||||
/// Returns the next action needed towards legalizing the vector type.
|
||||
std::pair<LegacyLegalizeActions::LegacyLegalizeAction, LLT>
|
||||
findVectorLegalAction(const InstrAspect &Aspect) const;
|
||||
|
||||
static const int FirstOp = TargetOpcode::PRE_ISEL_GENERIC_OPCODE_START;
|
||||
static const int LastOp = TargetOpcode::PRE_ISEL_GENERIC_OPCODE_END;
|
||||
|
||||
// Data structures used temporarily during construction of legality data:
|
||||
using TypeMap = DenseMap<LLT, LegacyLegalizeActions::LegacyLegalizeAction>;
|
||||
SmallVector<TypeMap, 1> SpecifiedActions[LastOp - FirstOp + 1];
|
||||
SmallVector<SizeChangeStrategy, 1>
|
||||
ScalarSizeChangeStrategies[LastOp - FirstOp + 1];
|
||||
SmallVector<SizeChangeStrategy, 1>
|
||||
VectorElementSizeChangeStrategies[LastOp - FirstOp + 1];
|
||||
bool TablesInitialized = false;
|
||||
|
||||
// Data structures used by getAction:
|
||||
SmallVector<SizeAndActionsVec, 1> ScalarActions[LastOp - FirstOp + 1];
|
||||
SmallVector<SizeAndActionsVec, 1> ScalarInVectorActions[LastOp - FirstOp + 1];
|
||||
std::unordered_map<uint16_t, SmallVector<SizeAndActionsVec, 1>>
|
||||
AddrSpace2PointerActions[LastOp - FirstOp + 1];
|
||||
std::unordered_map<uint16_t, SmallVector<SizeAndActionsVec, 1>>
|
||||
NumElements2Actions[LastOp - FirstOp + 1];
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_GLOBALISEL_LEGACYLEGALIZERINFO_H
|
||||
File diff suppressed because it is too large
Load Diff
76
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/Legalizer.h
vendored
Normal file
76
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/Legalizer.h
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
//== llvm/CodeGen/GlobalISel/Legalizer.h ---------------- -*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
/// \file A pass to convert the target-illegal operations created by IR -> MIR
|
||||
/// translation into ones the target expects to be able to select. This may
|
||||
/// occur in multiple phases, for example G_ADD <2 x i8> -> G_ADD <2 x i16> ->
|
||||
/// G_ADD <4 x i16>.
|
||||
///
|
||||
/// The LegalizeHelper class is where most of the work happens, and is designed
|
||||
/// to be callable from other passes that find themselves with an illegal
|
||||
/// instruction.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_LEGALIZER_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_LEGALIZER_H
|
||||
|
||||
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class LostDebugLocObserver;
|
||||
|
||||
class Legalizer : public MachineFunctionPass {
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
struct MFResult {
|
||||
bool Changed;
|
||||
const MachineInstr *FailedOn;
|
||||
};
|
||||
|
||||
private:
|
||||
/// Initialize the field members using \p MF.
|
||||
void init(MachineFunction &MF);
|
||||
|
||||
public:
|
||||
// Ctor, nothing fancy.
|
||||
Legalizer();
|
||||
|
||||
StringRef getPassName() const override { return "Legalizer"; }
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
MachineFunctionProperties getRequiredProperties() const override {
|
||||
return MachineFunctionProperties().set(
|
||||
MachineFunctionProperties::Property::IsSSA);
|
||||
}
|
||||
|
||||
MachineFunctionProperties getSetProperties() const override {
|
||||
return MachineFunctionProperties().set(
|
||||
MachineFunctionProperties::Property::Legalized);
|
||||
}
|
||||
|
||||
MachineFunctionProperties getClearedProperties() const override {
|
||||
return MachineFunctionProperties().set(
|
||||
MachineFunctionProperties::Property::NoPHIs);
|
||||
}
|
||||
|
||||
bool runOnMachineFunction(MachineFunction &MF) override;
|
||||
|
||||
static MFResult
|
||||
legalizeMachineFunction(MachineFunction &MF, const LegalizerInfo &LI,
|
||||
ArrayRef<GISelChangeObserver *> AuxObservers,
|
||||
LostDebugLocObserver &LocObserver,
|
||||
MachineIRBuilder &MIRBuilder);
|
||||
};
|
||||
} // End namespace llvm.
|
||||
|
||||
#endif
|
||||
431
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h
vendored
Normal file
431
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h
vendored
Normal file
@@ -0,0 +1,431 @@
|
||||
//== llvm/CodeGen/GlobalISel/LegalizerHelper.h ---------------- -*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
/// \file A pass to convert the target-illegal operations created by IR -> MIR
|
||||
/// translation into ones the target expects to be able to select. This may
|
||||
/// occur in multiple phases, for example G_ADD <2 x i8> -> G_ADD <2 x i16> ->
|
||||
/// G_ADD <4 x i16>.
|
||||
///
|
||||
/// The LegalizerHelper class is where most of the work happens, and is
|
||||
/// designed to be callable from other passes that find themselves with an
|
||||
/// illegal instruction.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_LEGALIZERHELPER_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_LEGALIZERHELPER_H
|
||||
|
||||
#include "llvm/CodeGen/GlobalISel/CallLowering.h"
|
||||
#include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
|
||||
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
|
||||
#include "llvm/CodeGen/LowLevelType.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/RuntimeLibcalls.h"
|
||||
|
||||
namespace llvm {
|
||||
// Forward declarations.
|
||||
class LegalizerInfo;
|
||||
class MachineRegisterInfo;
|
||||
class GISelChangeObserver;
|
||||
class LostDebugLocObserver;
|
||||
class TargetLowering;
|
||||
|
||||
class LegalizerHelper {
|
||||
public:
|
||||
/// Expose MIRBuilder so clients can set their own RecordInsertInstruction
|
||||
/// functions
|
||||
MachineIRBuilder &MIRBuilder;
|
||||
|
||||
/// To keep track of changes made by the LegalizerHelper.
|
||||
GISelChangeObserver &Observer;
|
||||
|
||||
private:
|
||||
MachineRegisterInfo &MRI;
|
||||
const LegalizerInfo &LI;
|
||||
const TargetLowering &TLI;
|
||||
|
||||
public:
|
||||
enum LegalizeResult {
|
||||
/// Instruction was already legal and no change was made to the
|
||||
/// MachineFunction.
|
||||
AlreadyLegal,
|
||||
|
||||
/// Instruction has been legalized and the MachineFunction changed.
|
||||
Legalized,
|
||||
|
||||
/// Some kind of error has occurred and we could not legalize this
|
||||
/// instruction.
|
||||
UnableToLegalize,
|
||||
};
|
||||
|
||||
/// Expose LegalizerInfo so the clients can re-use.
|
||||
const LegalizerInfo &getLegalizerInfo() const { return LI; }
|
||||
const TargetLowering &getTargetLowering() const { return TLI; }
|
||||
|
||||
LegalizerHelper(MachineFunction &MF, GISelChangeObserver &Observer,
|
||||
MachineIRBuilder &B);
|
||||
LegalizerHelper(MachineFunction &MF, const LegalizerInfo &LI,
|
||||
GISelChangeObserver &Observer, MachineIRBuilder &B);
|
||||
|
||||
/// Replace \p MI by a sequence of legal instructions that can implement the
|
||||
/// same operation. Note that this means \p MI may be deleted, so any iterator
|
||||
/// steps should be performed before calling this function. \p Helper should
|
||||
/// be initialized to the MachineFunction containing \p MI.
|
||||
///
|
||||
/// Considered as an opaque blob, the legal code will use and define the same
|
||||
/// registers as \p MI.
|
||||
LegalizeResult legalizeInstrStep(MachineInstr &MI,
|
||||
LostDebugLocObserver &LocObserver);
|
||||
|
||||
/// Legalize an instruction by emitting a runtime library call instead.
|
||||
LegalizeResult libcall(MachineInstr &MI, LostDebugLocObserver &LocObserver);
|
||||
|
||||
/// Legalize an instruction by reducing the width of the underlying scalar
|
||||
/// type.
|
||||
LegalizeResult narrowScalar(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy);
|
||||
|
||||
/// Legalize an instruction by performing the operation on a wider scalar type
|
||||
/// (for example a 16-bit addition can be safely performed at 32-bits
|
||||
/// precision, ignoring the unused bits).
|
||||
LegalizeResult widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy);
|
||||
|
||||
/// Legalize an instruction by replacing the value type
|
||||
LegalizeResult bitcast(MachineInstr &MI, unsigned TypeIdx, LLT Ty);
|
||||
|
||||
/// Legalize an instruction by splitting it into simpler parts, hopefully
|
||||
/// understood by the target.
|
||||
LegalizeResult lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty);
|
||||
|
||||
/// Legalize a vector instruction by splitting into multiple components, each
|
||||
/// acting on the same scalar type as the original but with fewer elements.
|
||||
LegalizeResult fewerElementsVector(MachineInstr &MI, unsigned TypeIdx,
|
||||
LLT NarrowTy);
|
||||
|
||||
/// Legalize a vector instruction by increasing the number of vector elements
|
||||
/// involved and ignoring the added elements later.
|
||||
LegalizeResult moreElementsVector(MachineInstr &MI, unsigned TypeIdx,
|
||||
LLT MoreTy);
|
||||
|
||||
/// Cast the given value to an LLT::scalar with an equivalent size. Returns
|
||||
/// the register to use if an instruction was inserted. Returns the original
|
||||
/// register if no coercion was necessary.
|
||||
//
|
||||
// This may also fail and return Register() if there is no legal way to cast.
|
||||
Register coerceToScalar(Register Val);
|
||||
|
||||
/// Legalize a single operand \p OpIdx of the machine instruction \p MI as a
|
||||
/// Use by extending the operand's type to \p WideTy using the specified \p
|
||||
/// ExtOpcode for the extension instruction, and replacing the vreg of the
|
||||
/// operand in place.
|
||||
void widenScalarSrc(MachineInstr &MI, LLT WideTy, unsigned OpIdx,
|
||||
unsigned ExtOpcode);
|
||||
|
||||
/// Legalize a single operand \p OpIdx of the machine instruction \p MI as a
|
||||
/// Use by truncating the operand's type to \p NarrowTy using G_TRUNC, and
|
||||
/// replacing the vreg of the operand in place.
|
||||
void narrowScalarSrc(MachineInstr &MI, LLT NarrowTy, unsigned OpIdx);
|
||||
|
||||
/// Legalize a single operand \p OpIdx of the machine instruction \p MI as a
|
||||
/// Def by extending the operand's type to \p WideTy and truncating it back
|
||||
/// with the \p TruncOpcode, and replacing the vreg of the operand in place.
|
||||
void widenScalarDst(MachineInstr &MI, LLT WideTy, unsigned OpIdx = 0,
|
||||
unsigned TruncOpcode = TargetOpcode::G_TRUNC);
|
||||
|
||||
// Legalize a single operand \p OpIdx of the machine instruction \p MI as a
|
||||
// Def by truncating the operand's type to \p NarrowTy, replacing in place and
|
||||
// extending back with \p ExtOpcode.
|
||||
void narrowScalarDst(MachineInstr &MI, LLT NarrowTy, unsigned OpIdx,
|
||||
unsigned ExtOpcode);
|
||||
/// Legalize a single operand \p OpIdx of the machine instruction \p MI as a
|
||||
/// Def by performing it with additional vector elements and extracting the
|
||||
/// result elements, and replacing the vreg of the operand in place.
|
||||
void moreElementsVectorDst(MachineInstr &MI, LLT MoreTy, unsigned OpIdx);
|
||||
|
||||
/// Legalize a single operand \p OpIdx of the machine instruction \p MI as a
|
||||
/// Use by producing a vector with undefined high elements, extracting the
|
||||
/// original vector type, and replacing the vreg of the operand in place.
|
||||
void moreElementsVectorSrc(MachineInstr &MI, LLT MoreTy, unsigned OpIdx);
|
||||
|
||||
/// Legalize a single operand \p OpIdx of the machine instruction \p MI as a
|
||||
/// use by inserting a G_BITCAST to \p CastTy
|
||||
void bitcastSrc(MachineInstr &MI, LLT CastTy, unsigned OpIdx);
|
||||
|
||||
/// Legalize a single operand \p OpIdx of the machine instruction \p MI as a
|
||||
/// def by inserting a G_BITCAST from \p CastTy
|
||||
void bitcastDst(MachineInstr &MI, LLT CastTy, unsigned OpIdx);
|
||||
|
||||
/// Widen \p OrigReg to \p WideTy by merging to a wider type, padding with
|
||||
/// G_IMPLICIT_DEF, and producing dead results.
|
||||
Register widenWithUnmerge(LLT WideTy, Register OrigReg);
|
||||
|
||||
private:
|
||||
LegalizeResult
|
||||
widenScalarMergeValues(MachineInstr &MI, unsigned TypeIdx, LLT WideTy);
|
||||
LegalizeResult
|
||||
widenScalarUnmergeValues(MachineInstr &MI, unsigned TypeIdx, LLT WideTy);
|
||||
LegalizeResult
|
||||
widenScalarExtract(MachineInstr &MI, unsigned TypeIdx, LLT WideTy);
|
||||
LegalizeResult
|
||||
widenScalarInsert(MachineInstr &MI, unsigned TypeIdx, LLT WideTy);
|
||||
LegalizeResult widenScalarAddSubOverflow(MachineInstr &MI, unsigned TypeIdx,
|
||||
LLT WideTy);
|
||||
LegalizeResult widenScalarAddSubShlSat(MachineInstr &MI, unsigned TypeIdx,
|
||||
LLT WideTy);
|
||||
LegalizeResult widenScalarMulo(MachineInstr &MI, unsigned TypeIdx,
|
||||
LLT WideTy);
|
||||
|
||||
/// Helper function to split a wide generic register into bitwise blocks with
|
||||
/// the given Type (which implies the number of blocks needed). The generic
|
||||
/// registers created are appended to Ops, starting at bit 0 of Reg.
|
||||
void extractParts(Register Reg, LLT Ty, int NumParts,
|
||||
SmallVectorImpl<Register> &VRegs);
|
||||
|
||||
/// Version which handles irregular splits.
|
||||
bool extractParts(Register Reg, LLT RegTy, LLT MainTy,
|
||||
LLT &LeftoverTy,
|
||||
SmallVectorImpl<Register> &VRegs,
|
||||
SmallVectorImpl<Register> &LeftoverVRegs);
|
||||
|
||||
/// Version which handles irregular sub-vector splits.
|
||||
void extractVectorParts(Register Reg, unsigned NumElst,
|
||||
SmallVectorImpl<Register> &VRegs);
|
||||
|
||||
/// Helper function to build a wide generic register \p DstReg of type \p
|
||||
/// RegTy from smaller parts. This will produce a G_MERGE_VALUES,
|
||||
/// G_BUILD_VECTOR, G_CONCAT_VECTORS, or sequence of G_INSERT as appropriate
|
||||
/// for the types.
|
||||
///
|
||||
/// \p PartRegs must be registers of type \p PartTy.
|
||||
///
|
||||
/// If \p ResultTy does not evenly break into \p PartTy sized pieces, the
|
||||
/// remainder must be specified with \p LeftoverRegs of type \p LeftoverTy.
|
||||
void insertParts(Register DstReg, LLT ResultTy,
|
||||
LLT PartTy, ArrayRef<Register> PartRegs,
|
||||
LLT LeftoverTy = LLT(), ArrayRef<Register> LeftoverRegs = {});
|
||||
|
||||
/// Merge \p PartRegs with different types into \p DstReg.
|
||||
void mergeMixedSubvectors(Register DstReg, ArrayRef<Register> PartRegs);
|
||||
|
||||
void appendVectorElts(SmallVectorImpl<Register> &Elts, Register Reg);
|
||||
|
||||
/// Unmerge \p SrcReg into smaller sized values, and append them to \p
|
||||
/// Parts. The elements of \p Parts will be the greatest common divisor type
|
||||
/// of \p DstTy, \p NarrowTy and the type of \p SrcReg. This will compute and
|
||||
/// return the GCD type.
|
||||
LLT extractGCDType(SmallVectorImpl<Register> &Parts, LLT DstTy,
|
||||
LLT NarrowTy, Register SrcReg);
|
||||
|
||||
/// Unmerge \p SrcReg into \p GCDTy typed registers. This will append all of
|
||||
/// the unpacked registers to \p Parts. This version is if the common unmerge
|
||||
/// type is already known.
|
||||
void extractGCDType(SmallVectorImpl<Register> &Parts, LLT GCDTy,
|
||||
Register SrcReg);
|
||||
|
||||
/// Produce a merge of values in \p VRegs to define \p DstReg. Perform a merge
|
||||
/// from the least common multiple type, and convert as appropriate to \p
|
||||
/// DstReg.
|
||||
///
|
||||
/// \p VRegs should each have type \p GCDTy. This type should be greatest
|
||||
/// common divisor type of \p DstReg, \p NarrowTy, and an undetermined source
|
||||
/// type.
|
||||
///
|
||||
/// \p NarrowTy is the desired result merge source type. If the source value
|
||||
/// needs to be widened to evenly cover \p DstReg, inserts high bits
|
||||
/// corresponding to the extension opcode \p PadStrategy.
|
||||
///
|
||||
/// \p VRegs will be cleared, and the result \p NarrowTy register pieces
|
||||
/// will replace it. Returns The complete LCMTy that \p VRegs will cover when
|
||||
/// merged.
|
||||
LLT buildLCMMergePieces(LLT DstTy, LLT NarrowTy, LLT GCDTy,
|
||||
SmallVectorImpl<Register> &VRegs,
|
||||
unsigned PadStrategy = TargetOpcode::G_ANYEXT);
|
||||
|
||||
/// Merge the values in \p RemergeRegs to an \p LCMTy typed value. Extract the
|
||||
/// low bits into \p DstReg. This is intended to use the outputs from
|
||||
/// buildLCMMergePieces after processing.
|
||||
void buildWidenedRemergeToDst(Register DstReg, LLT LCMTy,
|
||||
ArrayRef<Register> RemergeRegs);
|
||||
|
||||
/// Perform generic multiplication of values held in multiple registers.
|
||||
/// Generated instructions use only types NarrowTy and i1.
|
||||
/// Destination can be same or two times size of the source.
|
||||
void multiplyRegisters(SmallVectorImpl<Register> &DstRegs,
|
||||
ArrayRef<Register> Src1Regs,
|
||||
ArrayRef<Register> Src2Regs, LLT NarrowTy);
|
||||
|
||||
void changeOpcode(MachineInstr &MI, unsigned NewOpcode);
|
||||
|
||||
LegalizeResult tryNarrowPow2Reduction(MachineInstr &MI, Register SrcReg,
|
||||
LLT SrcTy, LLT NarrowTy,
|
||||
unsigned ScalarOpc);
|
||||
|
||||
// Memcpy family legalization helpers.
|
||||
LegalizeResult lowerMemset(MachineInstr &MI, Register Dst, Register Val,
|
||||
uint64_t KnownLen, Align Alignment,
|
||||
bool IsVolatile);
|
||||
LegalizeResult lowerMemcpyInline(MachineInstr &MI, Register Dst, Register Src,
|
||||
uint64_t KnownLen, Align DstAlign,
|
||||
Align SrcAlign, bool IsVolatile);
|
||||
LegalizeResult lowerMemcpy(MachineInstr &MI, Register Dst, Register Src,
|
||||
uint64_t KnownLen, uint64_t Limit, Align DstAlign,
|
||||
Align SrcAlign, bool IsVolatile);
|
||||
LegalizeResult lowerMemmove(MachineInstr &MI, Register Dst, Register Src,
|
||||
uint64_t KnownLen, Align DstAlign, Align SrcAlign,
|
||||
bool IsVolatile);
|
||||
|
||||
public:
|
||||
/// Return the alignment to use for a stack temporary object with the given
|
||||
/// type.
|
||||
Align getStackTemporaryAlignment(LLT Type, Align MinAlign = Align()) const;
|
||||
|
||||
/// Create a stack temporary based on the size in bytes and the alignment
|
||||
MachineInstrBuilder createStackTemporary(TypeSize Bytes, Align Alignment,
|
||||
MachinePointerInfo &PtrInfo);
|
||||
|
||||
/// Get a pointer to vector element \p Index located in memory for a vector of
|
||||
/// type \p VecTy starting at a base address of \p VecPtr. If \p Index is out
|
||||
/// of bounds the returned pointer is unspecified, but will be within the
|
||||
/// vector bounds.
|
||||
Register getVectorElementPointer(Register VecPtr, LLT VecTy, Register Index);
|
||||
|
||||
/// Handles most opcodes. Split \p MI into same instruction on sub-vectors or
|
||||
/// scalars with \p NumElts elements (1 for scalar). Supports uneven splits:
|
||||
/// there can be leftover sub-vector with fewer then \p NumElts or a leftover
|
||||
/// scalar. To avoid this use moreElements first and set MI number of elements
|
||||
/// to multiple of \p NumElts. Non-vector operands that should be used on all
|
||||
/// sub-instructions without split are listed in \p NonVecOpIndices.
|
||||
LegalizeResult fewerElementsVectorMultiEltType(
|
||||
GenericMachineInstr &MI, unsigned NumElts,
|
||||
std::initializer_list<unsigned> NonVecOpIndices = {});
|
||||
|
||||
LegalizeResult fewerElementsVectorPhi(GenericMachineInstr &MI,
|
||||
unsigned NumElts);
|
||||
|
||||
LegalizeResult moreElementsVectorPhi(MachineInstr &MI, unsigned TypeIdx,
|
||||
LLT MoreTy);
|
||||
LegalizeResult moreElementsVectorShuffle(MachineInstr &MI, unsigned TypeIdx,
|
||||
LLT MoreTy);
|
||||
|
||||
LegalizeResult fewerElementsVectorUnmergeValues(MachineInstr &MI,
|
||||
unsigned TypeIdx,
|
||||
LLT NarrowTy);
|
||||
LegalizeResult fewerElementsVectorMerge(MachineInstr &MI, unsigned TypeIdx,
|
||||
LLT NarrowTy);
|
||||
LegalizeResult fewerElementsVectorExtractInsertVectorElt(MachineInstr &MI,
|
||||
unsigned TypeIdx,
|
||||
LLT NarrowTy);
|
||||
|
||||
LegalizeResult reduceLoadStoreWidth(GLoadStore &MI, unsigned TypeIdx,
|
||||
LLT NarrowTy);
|
||||
|
||||
LegalizeResult fewerElementsVectorSextInReg(MachineInstr &MI, unsigned TypeIdx,
|
||||
LLT NarrowTy);
|
||||
|
||||
LegalizeResult narrowScalarShiftByConstant(MachineInstr &MI, const APInt &Amt,
|
||||
LLT HalfTy, LLT ShiftAmtTy);
|
||||
|
||||
LegalizeResult fewerElementsVectorReductions(MachineInstr &MI,
|
||||
unsigned TypeIdx, LLT NarrowTy);
|
||||
|
||||
LegalizeResult fewerElementsVectorShuffle(MachineInstr &MI, unsigned TypeIdx,
|
||||
LLT NarrowTy);
|
||||
|
||||
LegalizeResult narrowScalarShift(MachineInstr &MI, unsigned TypeIdx, LLT Ty);
|
||||
LegalizeResult narrowScalarAddSub(MachineInstr &MI, unsigned TypeIdx,
|
||||
LLT NarrowTy);
|
||||
LegalizeResult narrowScalarMul(MachineInstr &MI, LLT Ty);
|
||||
LegalizeResult narrowScalarFPTOI(MachineInstr &MI, unsigned TypeIdx, LLT Ty);
|
||||
LegalizeResult narrowScalarExtract(MachineInstr &MI, unsigned TypeIdx, LLT Ty);
|
||||
LegalizeResult narrowScalarInsert(MachineInstr &MI, unsigned TypeIdx, LLT Ty);
|
||||
|
||||
LegalizeResult narrowScalarBasic(MachineInstr &MI, unsigned TypeIdx, LLT Ty);
|
||||
LegalizeResult narrowScalarExt(MachineInstr &MI, unsigned TypeIdx, LLT Ty);
|
||||
LegalizeResult narrowScalarSelect(MachineInstr &MI, unsigned TypeIdx, LLT Ty);
|
||||
LegalizeResult narrowScalarCTLZ(MachineInstr &MI, unsigned TypeIdx, LLT Ty);
|
||||
LegalizeResult narrowScalarCTTZ(MachineInstr &MI, unsigned TypeIdx, LLT Ty);
|
||||
LegalizeResult narrowScalarCTPOP(MachineInstr &MI, unsigned TypeIdx, LLT Ty);
|
||||
|
||||
/// Perform Bitcast legalize action on G_EXTRACT_VECTOR_ELT.
|
||||
LegalizeResult bitcastExtractVectorElt(MachineInstr &MI, unsigned TypeIdx,
|
||||
LLT CastTy);
|
||||
|
||||
/// Perform Bitcast legalize action on G_INSERT_VECTOR_ELT.
|
||||
LegalizeResult bitcastInsertVectorElt(MachineInstr &MI, unsigned TypeIdx,
|
||||
LLT CastTy);
|
||||
|
||||
LegalizeResult lowerBitcast(MachineInstr &MI);
|
||||
LegalizeResult lowerLoad(GAnyLoad &MI);
|
||||
LegalizeResult lowerStore(GStore &MI);
|
||||
LegalizeResult lowerBitCount(MachineInstr &MI);
|
||||
LegalizeResult lowerFunnelShiftWithInverse(MachineInstr &MI);
|
||||
LegalizeResult lowerFunnelShiftAsShifts(MachineInstr &MI);
|
||||
LegalizeResult lowerFunnelShift(MachineInstr &MI);
|
||||
LegalizeResult lowerRotateWithReverseRotate(MachineInstr &MI);
|
||||
LegalizeResult lowerRotate(MachineInstr &MI);
|
||||
|
||||
LegalizeResult lowerU64ToF32BitOps(MachineInstr &MI);
|
||||
LegalizeResult lowerUITOFP(MachineInstr &MI);
|
||||
LegalizeResult lowerSITOFP(MachineInstr &MI);
|
||||
LegalizeResult lowerFPTOUI(MachineInstr &MI);
|
||||
LegalizeResult lowerFPTOSI(MachineInstr &MI);
|
||||
|
||||
LegalizeResult lowerFPTRUNC_F64_TO_F16(MachineInstr &MI);
|
||||
LegalizeResult lowerFPTRUNC(MachineInstr &MI);
|
||||
LegalizeResult lowerFPOWI(MachineInstr &MI);
|
||||
|
||||
LegalizeResult lowerMinMax(MachineInstr &MI);
|
||||
LegalizeResult lowerFCopySign(MachineInstr &MI);
|
||||
LegalizeResult lowerFMinNumMaxNum(MachineInstr &MI);
|
||||
LegalizeResult lowerFMad(MachineInstr &MI);
|
||||
LegalizeResult lowerIntrinsicRound(MachineInstr &MI);
|
||||
LegalizeResult lowerFFloor(MachineInstr &MI);
|
||||
LegalizeResult lowerMergeValues(MachineInstr &MI);
|
||||
LegalizeResult lowerUnmergeValues(MachineInstr &MI);
|
||||
LegalizeResult lowerExtractInsertVectorElt(MachineInstr &MI);
|
||||
LegalizeResult lowerShuffleVector(MachineInstr &MI);
|
||||
LegalizeResult lowerDynStackAlloc(MachineInstr &MI);
|
||||
LegalizeResult lowerExtract(MachineInstr &MI);
|
||||
LegalizeResult lowerInsert(MachineInstr &MI);
|
||||
LegalizeResult lowerSADDO_SSUBO(MachineInstr &MI);
|
||||
LegalizeResult lowerAddSubSatToMinMax(MachineInstr &MI);
|
||||
LegalizeResult lowerAddSubSatToAddoSubo(MachineInstr &MI);
|
||||
LegalizeResult lowerShlSat(MachineInstr &MI);
|
||||
LegalizeResult lowerBswap(MachineInstr &MI);
|
||||
LegalizeResult lowerBitreverse(MachineInstr &MI);
|
||||
LegalizeResult lowerReadWriteRegister(MachineInstr &MI);
|
||||
LegalizeResult lowerSMULH_UMULH(MachineInstr &MI);
|
||||
LegalizeResult lowerSelect(MachineInstr &MI);
|
||||
LegalizeResult lowerDIVREM(MachineInstr &MI);
|
||||
LegalizeResult lowerAbsToAddXor(MachineInstr &MI);
|
||||
LegalizeResult lowerAbsToMaxNeg(MachineInstr &MI);
|
||||
LegalizeResult lowerVectorReduction(MachineInstr &MI);
|
||||
LegalizeResult lowerMemcpyInline(MachineInstr &MI);
|
||||
LegalizeResult lowerMemCpyFamily(MachineInstr &MI, unsigned MaxLen = 0);
|
||||
};
|
||||
|
||||
/// Helper function that creates a libcall to the given \p Name using the given
|
||||
/// calling convention \p CC.
|
||||
LegalizerHelper::LegalizeResult
|
||||
createLibcall(MachineIRBuilder &MIRBuilder, const char *Name,
|
||||
const CallLowering::ArgInfo &Result,
|
||||
ArrayRef<CallLowering::ArgInfo> Args, CallingConv::ID CC);
|
||||
|
||||
/// Helper function that creates the given libcall.
|
||||
LegalizerHelper::LegalizeResult
|
||||
createLibcall(MachineIRBuilder &MIRBuilder, RTLIB::Libcall Libcall,
|
||||
const CallLowering::ArgInfo &Result,
|
||||
ArrayRef<CallLowering::ArgInfo> Args);
|
||||
|
||||
/// Create a libcall to memcpy et al.
|
||||
LegalizerHelper::LegalizeResult
|
||||
createMemLibcall(MachineIRBuilder &MIRBuilder, MachineRegisterInfo &MRI,
|
||||
MachineInstr &MI, LostDebugLocObserver &LocObserver);
|
||||
|
||||
} // End namespace llvm.
|
||||
|
||||
#endif
|
||||
1261
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h
vendored
Normal file
1261
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
164
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/LoadStoreOpt.h
vendored
Normal file
164
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/LoadStoreOpt.h
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
//== llvm/CodeGen/GlobalISel/LoadStoreOpt.h - LoadStoreOpt -------*- 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 is an optimization pass for GlobalISel generic memory operations.
|
||||
/// Specifically, it focuses on merging stores and loads to consecutive
|
||||
/// addresses.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_LOADSTOREOPT_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_LOADSTOREOPT_H
|
||||
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Analysis/AliasAnalysis.h"
|
||||
#include "llvm/CodeGen/GlobalISel/GenericMachineInstrs.h"
|
||||
#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
|
||||
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
|
||||
#include "llvm/CodeGen/GlobalISel/Utils.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
|
||||
|
||||
namespace llvm {
|
||||
// Forward declarations.
|
||||
class MachineRegisterInfo;
|
||||
namespace GISelAddressing {
|
||||
/// Helper struct to store a base, index and offset that forms an address
|
||||
struct BaseIndexOffset {
|
||||
Register BaseReg;
|
||||
Register IndexReg;
|
||||
int64_t Offset = 0;
|
||||
bool IsIndexSignExt = false;
|
||||
};
|
||||
|
||||
/// Returns a BaseIndexOffset which describes the pointer in \p Ptr.
|
||||
BaseIndexOffset getPointerInfo(Register Ptr, MachineRegisterInfo &MRI);
|
||||
|
||||
/// Compute whether or not a memory access at \p MI1 aliases with an access at
|
||||
/// \p MI2 \returns true if either alias/no-alias is known. Sets \p IsAlias
|
||||
/// accordingly.
|
||||
bool aliasIsKnownForLoadStore(const MachineInstr &MI1, const MachineInstr &MI2,
|
||||
bool &IsAlias, MachineRegisterInfo &MRI);
|
||||
|
||||
/// Returns true if the instruction \p MI may alias \p Other.
|
||||
/// This function uses multiple strategies to detect aliasing, whereas
|
||||
/// aliasIsKnownForLoadStore just looks at the addresses of load/stores and is
|
||||
/// tries to reason about base/index/offsets.
|
||||
bool instMayAlias(const MachineInstr &MI, const MachineInstr &Other,
|
||||
MachineRegisterInfo &MRI, AliasAnalysis *AA);
|
||||
} // namespace GISelAddressing
|
||||
|
||||
using namespace GISelAddressing;
|
||||
|
||||
class LoadStoreOpt : public MachineFunctionPass {
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
private:
|
||||
/// An input function to decide if the pass should run or not
|
||||
/// on the given MachineFunction.
|
||||
std::function<bool(const MachineFunction &)> DoNotRunPass;
|
||||
|
||||
MachineRegisterInfo *MRI;
|
||||
const TargetLowering *TLI;
|
||||
MachineFunction *MF;
|
||||
AliasAnalysis *AA;
|
||||
const LegalizerInfo *LI;
|
||||
|
||||
MachineIRBuilder Builder;
|
||||
|
||||
/// Initialize the field members using \p MF.
|
||||
void init(MachineFunction &MF);
|
||||
|
||||
class StoreMergeCandidate {
|
||||
public:
|
||||
// The base pointer used as the base for all stores in this candidate.
|
||||
Register BasePtr;
|
||||
// Our algorithm is very simple at the moment. We assume that in instruction
|
||||
// order stores are writing to incremeneting consecutive addresses. So when
|
||||
// we walk the block in reverse order, the next eligible store must write to
|
||||
// an offset one store width lower than CurrentLowestOffset.
|
||||
uint64_t CurrentLowestOffset;
|
||||
SmallVector<GStore *> Stores;
|
||||
// A vector of MachineInstr/unsigned pairs to denote potential aliases that
|
||||
// need to be checked before the candidate is considered safe to merge. The
|
||||
// unsigned value is an index into the Stores vector. The indexed store is
|
||||
// the highest-indexed store that has already been checked to not have an
|
||||
// alias with the instruction. We record this so we don't have to repeat
|
||||
// alias checks that have been already done, only those with stores added
|
||||
// after the potential alias is recorded.
|
||||
SmallVector<std::pair<MachineInstr *, unsigned>> PotentialAliases;
|
||||
|
||||
void addPotentialAlias(MachineInstr &MI);
|
||||
|
||||
/// Reset this candidate back to an empty one.
|
||||
void reset() {
|
||||
Stores.clear();
|
||||
PotentialAliases.clear();
|
||||
CurrentLowestOffset = 0;
|
||||
BasePtr = Register();
|
||||
}
|
||||
};
|
||||
|
||||
bool isLegalOrBeforeLegalizer(const LegalityQuery &Query,
|
||||
MachineFunction &MF) const;
|
||||
/// If the given store is valid to be a member of the candidate, add it and
|
||||
/// return true. Otherwise, returns false.
|
||||
bool addStoreToCandidate(GStore &MI, StoreMergeCandidate &C);
|
||||
/// Returns true if the instruction \p MI would potentially alias with any
|
||||
/// stores in the candidate \p C.
|
||||
bool operationAliasesWithCandidate(MachineInstr &MI, StoreMergeCandidate &C);
|
||||
/// Merges the stores in the given vector into a wide store.
|
||||
/// \p returns true if at least some of the stores were merged.
|
||||
/// This may decide not to merge stores if heuristics predict it will not be
|
||||
/// worth it.
|
||||
bool mergeStores(SmallVectorImpl<GStore *> &StoresToMerge);
|
||||
/// Perform a merge of all the stores in \p Stores into a single store.
|
||||
/// Erases the old stores from the block when finished.
|
||||
/// \returns true if merging was done. It may fail to perform a merge if
|
||||
/// there are issues with materializing legal wide values.
|
||||
bool doSingleStoreMerge(SmallVectorImpl<GStore *> &Stores);
|
||||
bool processMergeCandidate(StoreMergeCandidate &C);
|
||||
bool mergeBlockStores(MachineBasicBlock &MBB);
|
||||
bool mergeFunctionStores(MachineFunction &MF);
|
||||
|
||||
/// Initialize some target-specific data structures for the store merging
|
||||
/// optimization. \p AddrSpace indicates which address space to use when
|
||||
/// probing the legalizer info for legal stores.
|
||||
void initializeStoreMergeTargetInfo(unsigned AddrSpace = 0);
|
||||
/// A map between address space numbers and a bitvector of supported stores
|
||||
/// sizes. Each bit in the bitvector represents whether a store size of
|
||||
/// that bit's value is legal. E.g. if bit 64 is set, then 64 bit scalar
|
||||
/// stores are legal.
|
||||
DenseMap<unsigned, BitVector> LegalStoreSizes;
|
||||
bool IsPreLegalizer;
|
||||
/// Contains instructions to be erased at the end of a block scan.
|
||||
SmallSet<MachineInstr *, 16> InstsToErase;
|
||||
|
||||
public:
|
||||
LoadStoreOpt();
|
||||
LoadStoreOpt(std::function<bool(const MachineFunction &)>);
|
||||
|
||||
StringRef getPassName() const override { return "LoadStoreOpt"; }
|
||||
|
||||
MachineFunctionProperties getRequiredProperties() const override {
|
||||
return MachineFunctionProperties()
|
||||
.set(MachineFunctionProperties::Property::IsSSA);
|
||||
}
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
bool runOnMachineFunction(MachineFunction &MF) override;
|
||||
};
|
||||
|
||||
} // End namespace llvm.
|
||||
|
||||
#endif
|
||||
97
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/Localizer.h
vendored
Normal file
97
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/Localizer.h
vendored
Normal file
@@ -0,0 +1,97 @@
|
||||
//== llvm/CodeGen/GlobalISel/Localizer.h - Localizer -------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
/// \file This file describes the interface of the Localizer pass.
|
||||
/// This pass moves/duplicates constant-like instructions close to their uses.
|
||||
/// Its primarily goal is to workaround the deficiencies of the fast register
|
||||
/// allocator.
|
||||
/// With GlobalISel constants are all materialized in the entry block of
|
||||
/// a function. However, the fast allocator cannot rematerialize constants and
|
||||
/// has a lot more live-ranges to deal with and will most likely end up
|
||||
/// spilling a lot.
|
||||
/// By pushing the constants close to their use, we only create small
|
||||
/// live-ranges.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_LOCALIZER_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_LOCALIZER_H
|
||||
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
|
||||
namespace llvm {
|
||||
// Forward declarations.
|
||||
class MachineRegisterInfo;
|
||||
class TargetTransformInfo;
|
||||
|
||||
/// This pass implements the localization mechanism described at the
|
||||
/// top of this file. One specificity of the implementation is that
|
||||
/// it will materialize one and only one instance of a constant per
|
||||
/// basic block, thus enabling reuse of that constant within that block.
|
||||
/// Moreover, it only materializes constants in blocks where they
|
||||
/// are used. PHI uses are considered happening at the end of the
|
||||
/// related predecessor.
|
||||
class Localizer : public MachineFunctionPass {
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
private:
|
||||
/// An input function to decide if the pass should run or not
|
||||
/// on the given MachineFunction.
|
||||
std::function<bool(const MachineFunction &)> DoNotRunPass;
|
||||
|
||||
/// MRI contains all the register class/bank information that this
|
||||
/// pass uses and updates.
|
||||
MachineRegisterInfo *MRI;
|
||||
/// TTI used for getting remat costs for instructions.
|
||||
TargetTransformInfo *TTI;
|
||||
|
||||
/// Check if \p MOUse is used in the same basic block as \p Def.
|
||||
/// If the use is in the same block, we say it is local.
|
||||
/// When the use is not local, \p InsertMBB will contain the basic
|
||||
/// block when to insert \p Def to have a local use.
|
||||
static bool isLocalUse(MachineOperand &MOUse, const MachineInstr &Def,
|
||||
MachineBasicBlock *&InsertMBB);
|
||||
|
||||
/// Initialize the field members using \p MF.
|
||||
void init(MachineFunction &MF);
|
||||
|
||||
typedef SmallSetVector<MachineInstr *, 32> LocalizedSetVecT;
|
||||
|
||||
/// If \p Op is a phi operand and not unique in that phi, that is,
|
||||
/// there are other operands in the phi with the same register,
|
||||
/// return true.
|
||||
bool isNonUniquePhiValue(MachineOperand &Op) const;
|
||||
|
||||
/// Do inter-block localization from the entry block.
|
||||
bool localizeInterBlock(MachineFunction &MF,
|
||||
LocalizedSetVecT &LocalizedInstrs);
|
||||
|
||||
/// Do intra-block localization of already localized instructions.
|
||||
bool localizeIntraBlock(LocalizedSetVecT &LocalizedInstrs);
|
||||
|
||||
public:
|
||||
Localizer();
|
||||
Localizer(std::function<bool(const MachineFunction &)>);
|
||||
|
||||
StringRef getPassName() const override { return "Localizer"; }
|
||||
|
||||
MachineFunctionProperties getRequiredProperties() const override {
|
||||
return MachineFunctionProperties()
|
||||
.set(MachineFunctionProperties::Property::IsSSA);
|
||||
}
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
bool runOnMachineFunction(MachineFunction &MF) override;
|
||||
};
|
||||
|
||||
} // End namespace llvm.
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,50 @@
|
||||
//===----- llvm/CodeGen/GlobalISel/LostDebugLocObserver.h -------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// Tracks DebugLocs between checkpoints and verifies that they are transferred.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_LOSTDEBUGLOCOBSERVER_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_LOSTDEBUGLOCOBSERVER_H
|
||||
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/CodeGen/GlobalISel/GISelChangeObserver.h"
|
||||
|
||||
namespace llvm {
|
||||
class LostDebugLocObserver : public GISelChangeObserver {
|
||||
StringRef DebugType;
|
||||
SmallSet<DebugLoc, 4> LostDebugLocs;
|
||||
SmallPtrSet<MachineInstr *, 4> PotentialMIsForDebugLocs;
|
||||
unsigned NumLostDebugLocs = 0;
|
||||
|
||||
public:
|
||||
LostDebugLocObserver(StringRef DebugType) : DebugType(DebugType) {}
|
||||
|
||||
unsigned getNumLostDebugLocs() const { return NumLostDebugLocs; }
|
||||
|
||||
/// Call this to indicate that it's a good point to assess whether locations
|
||||
/// have been lost. Typically this will be when a logical change has been
|
||||
/// completed such as the caller has finished replacing some instructions with
|
||||
/// alternatives. When CheckDebugLocs is true, the locations will be checked
|
||||
/// to see if any have been lost since the last checkpoint. When
|
||||
/// CheckDebugLocs is false, it will just reset ready for the next checkpoint
|
||||
/// without checking anything. This can be helpful to limit the detection to
|
||||
/// easy-to-fix portions of an algorithm before allowing more difficult ones.
|
||||
void checkpoint(bool CheckDebugLocs = true);
|
||||
|
||||
void createdInstr(MachineInstr &MI) override;
|
||||
void erasingInstr(MachineInstr &MI) override;
|
||||
void changingInstr(MachineInstr &MI) override;
|
||||
void changedInstr(MachineInstr &MI) override;
|
||||
|
||||
private:
|
||||
void analyzeDebugLocations();
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
#endif // LLVM_CODEGEN_GLOBALISEL_LOSTDEBUGLOCOBSERVER_H
|
||||
661
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/MIPatternMatch.h
vendored
Normal file
661
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/MIPatternMatch.h
vendored
Normal file
@@ -0,0 +1,661 @@
|
||||
//==------ llvm/CodeGen/GlobalISel/MIPatternMatch.h -------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// Contains matchers for matching SSA Machine Instructions.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_MIPATTERNMATCH_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_MIPATTERNMATCH_H
|
||||
|
||||
#include "llvm/ADT/APInt.h"
|
||||
#include "llvm/CodeGen/GlobalISel/Utils.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/IR/InstrTypes.h"
|
||||
|
||||
namespace llvm {
|
||||
namespace MIPatternMatch {
|
||||
|
||||
template <typename Reg, typename Pattern>
|
||||
bool mi_match(Reg R, const MachineRegisterInfo &MRI, Pattern &&P) {
|
||||
return P.match(MRI, R);
|
||||
}
|
||||
|
||||
template <typename Pattern>
|
||||
bool mi_match(MachineInstr &MI, const MachineRegisterInfo &MRI, Pattern &&P) {
|
||||
return P.match(MRI, &MI);
|
||||
}
|
||||
|
||||
// TODO: Extend for N use.
|
||||
template <typename SubPatternT> struct OneUse_match {
|
||||
SubPatternT SubPat;
|
||||
OneUse_match(const SubPatternT &SP) : SubPat(SP) {}
|
||||
|
||||
bool match(const MachineRegisterInfo &MRI, Register Reg) {
|
||||
return MRI.hasOneUse(Reg) && SubPat.match(MRI, Reg);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename SubPat>
|
||||
inline OneUse_match<SubPat> m_OneUse(const SubPat &SP) {
|
||||
return SP;
|
||||
}
|
||||
|
||||
template <typename SubPatternT> struct OneNonDBGUse_match {
|
||||
SubPatternT SubPat;
|
||||
OneNonDBGUse_match(const SubPatternT &SP) : SubPat(SP) {}
|
||||
|
||||
bool match(const MachineRegisterInfo &MRI, Register Reg) {
|
||||
return MRI.hasOneNonDBGUse(Reg) && SubPat.match(MRI, Reg);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename SubPat>
|
||||
inline OneNonDBGUse_match<SubPat> m_OneNonDBGUse(const SubPat &SP) {
|
||||
return SP;
|
||||
}
|
||||
|
||||
template <typename ConstT>
|
||||
inline Optional<ConstT> matchConstant(Register, const MachineRegisterInfo &);
|
||||
|
||||
template <>
|
||||
inline Optional<APInt> matchConstant(Register Reg,
|
||||
const MachineRegisterInfo &MRI) {
|
||||
return getIConstantVRegVal(Reg, MRI);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline Optional<int64_t> matchConstant(Register Reg,
|
||||
const MachineRegisterInfo &MRI) {
|
||||
return getIConstantVRegSExtVal(Reg, MRI);
|
||||
}
|
||||
|
||||
template <typename ConstT> struct ConstantMatch {
|
||||
ConstT &CR;
|
||||
ConstantMatch(ConstT &C) : CR(C) {}
|
||||
bool match(const MachineRegisterInfo &MRI, Register Reg) {
|
||||
if (auto MaybeCst = matchConstant<ConstT>(Reg, MRI)) {
|
||||
CR = *MaybeCst;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
inline ConstantMatch<APInt> m_ICst(APInt &Cst) {
|
||||
return ConstantMatch<APInt>(Cst);
|
||||
}
|
||||
inline ConstantMatch<int64_t> m_ICst(int64_t &Cst) {
|
||||
return ConstantMatch<int64_t>(Cst);
|
||||
}
|
||||
|
||||
struct GCstAndRegMatch {
|
||||
Optional<ValueAndVReg> &ValReg;
|
||||
GCstAndRegMatch(Optional<ValueAndVReg> &ValReg) : ValReg(ValReg) {}
|
||||
bool match(const MachineRegisterInfo &MRI, Register Reg) {
|
||||
ValReg = getIConstantVRegValWithLookThrough(Reg, MRI);
|
||||
return ValReg ? true : false;
|
||||
}
|
||||
};
|
||||
|
||||
inline GCstAndRegMatch m_GCst(Optional<ValueAndVReg> &ValReg) {
|
||||
return GCstAndRegMatch(ValReg);
|
||||
}
|
||||
|
||||
struct GFCstAndRegMatch {
|
||||
Optional<FPValueAndVReg> &FPValReg;
|
||||
GFCstAndRegMatch(Optional<FPValueAndVReg> &FPValReg) : FPValReg(FPValReg) {}
|
||||
bool match(const MachineRegisterInfo &MRI, Register Reg) {
|
||||
FPValReg = getFConstantVRegValWithLookThrough(Reg, MRI);
|
||||
return FPValReg ? true : false;
|
||||
}
|
||||
};
|
||||
|
||||
inline GFCstAndRegMatch m_GFCst(Optional<FPValueAndVReg> &FPValReg) {
|
||||
return GFCstAndRegMatch(FPValReg);
|
||||
}
|
||||
|
||||
struct GFCstOrSplatGFCstMatch {
|
||||
Optional<FPValueAndVReg> &FPValReg;
|
||||
GFCstOrSplatGFCstMatch(Optional<FPValueAndVReg> &FPValReg)
|
||||
: FPValReg(FPValReg) {}
|
||||
bool match(const MachineRegisterInfo &MRI, Register Reg) {
|
||||
return (FPValReg = getFConstantSplat(Reg, MRI)) ||
|
||||
(FPValReg = getFConstantVRegValWithLookThrough(Reg, MRI));
|
||||
};
|
||||
};
|
||||
|
||||
inline GFCstOrSplatGFCstMatch
|
||||
m_GFCstOrSplat(Optional<FPValueAndVReg> &FPValReg) {
|
||||
return GFCstOrSplatGFCstMatch(FPValReg);
|
||||
}
|
||||
|
||||
/// Matcher for a specific constant value.
|
||||
struct SpecificConstantMatch {
|
||||
int64_t RequestedVal;
|
||||
SpecificConstantMatch(int64_t RequestedVal) : RequestedVal(RequestedVal) {}
|
||||
bool match(const MachineRegisterInfo &MRI, Register Reg) {
|
||||
int64_t MatchedVal;
|
||||
return mi_match(Reg, MRI, m_ICst(MatchedVal)) && MatchedVal == RequestedVal;
|
||||
}
|
||||
};
|
||||
|
||||
/// Matches a constant equal to \p RequestedValue.
|
||||
inline SpecificConstantMatch m_SpecificICst(int64_t RequestedValue) {
|
||||
return SpecificConstantMatch(RequestedValue);
|
||||
}
|
||||
|
||||
/// Matcher for a specific constant splat.
|
||||
struct SpecificConstantSplatMatch {
|
||||
int64_t RequestedVal;
|
||||
SpecificConstantSplatMatch(int64_t RequestedVal)
|
||||
: RequestedVal(RequestedVal) {}
|
||||
bool match(const MachineRegisterInfo &MRI, Register Reg) {
|
||||
return isBuildVectorConstantSplat(Reg, MRI, RequestedVal,
|
||||
/* AllowUndef */ false);
|
||||
}
|
||||
};
|
||||
|
||||
/// Matches a constant splat of \p RequestedValue.
|
||||
inline SpecificConstantSplatMatch m_SpecificICstSplat(int64_t RequestedValue) {
|
||||
return SpecificConstantSplatMatch(RequestedValue);
|
||||
}
|
||||
|
||||
/// Matcher for a specific constant or constant splat.
|
||||
struct SpecificConstantOrSplatMatch {
|
||||
int64_t RequestedVal;
|
||||
SpecificConstantOrSplatMatch(int64_t RequestedVal)
|
||||
: RequestedVal(RequestedVal) {}
|
||||
bool match(const MachineRegisterInfo &MRI, Register Reg) {
|
||||
int64_t MatchedVal;
|
||||
if (mi_match(Reg, MRI, m_ICst(MatchedVal)) && MatchedVal == RequestedVal)
|
||||
return true;
|
||||
return isBuildVectorConstantSplat(Reg, MRI, RequestedVal,
|
||||
/* AllowUndef */ false);
|
||||
}
|
||||
};
|
||||
|
||||
/// Matches a \p RequestedValue constant or a constant splat of \p
|
||||
/// RequestedValue.
|
||||
inline SpecificConstantOrSplatMatch
|
||||
m_SpecificICstOrSplat(int64_t RequestedValue) {
|
||||
return SpecificConstantOrSplatMatch(RequestedValue);
|
||||
}
|
||||
|
||||
///{
|
||||
/// Convenience matchers for specific integer values.
|
||||
inline SpecificConstantMatch m_ZeroInt() { return SpecificConstantMatch(0); }
|
||||
inline SpecificConstantMatch m_AllOnesInt() {
|
||||
return SpecificConstantMatch(-1);
|
||||
}
|
||||
///}
|
||||
|
||||
// TODO: Rework this for different kinds of MachineOperand.
|
||||
// Currently assumes the Src for a match is a register.
|
||||
// We might want to support taking in some MachineOperands and call getReg on
|
||||
// that.
|
||||
|
||||
struct operand_type_match {
|
||||
bool match(const MachineRegisterInfo &MRI, Register Reg) { return true; }
|
||||
bool match(const MachineRegisterInfo &MRI, MachineOperand *MO) {
|
||||
return MO->isReg();
|
||||
}
|
||||
};
|
||||
|
||||
inline operand_type_match m_Reg() { return operand_type_match(); }
|
||||
|
||||
/// Matching combinators.
|
||||
template <typename... Preds> struct And {
|
||||
template <typename MatchSrc>
|
||||
bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Pred, typename... Preds>
|
||||
struct And<Pred, Preds...> : And<Preds...> {
|
||||
Pred P;
|
||||
And(Pred &&p, Preds &&... preds)
|
||||
: And<Preds...>(std::forward<Preds>(preds)...), P(std::forward<Pred>(p)) {
|
||||
}
|
||||
template <typename MatchSrc>
|
||||
bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
|
||||
return P.match(MRI, src) && And<Preds...>::match(MRI, src);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... Preds> struct Or {
|
||||
template <typename MatchSrc>
|
||||
bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Pred, typename... Preds>
|
||||
struct Or<Pred, Preds...> : Or<Preds...> {
|
||||
Pred P;
|
||||
Or(Pred &&p, Preds &&... preds)
|
||||
: Or<Preds...>(std::forward<Preds>(preds)...), P(std::forward<Pred>(p)) {}
|
||||
template <typename MatchSrc>
|
||||
bool match(const MachineRegisterInfo &MRI, MatchSrc &&src) {
|
||||
return P.match(MRI, src) || Or<Preds...>::match(MRI, src);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename... Preds> And<Preds...> m_all_of(Preds &&... preds) {
|
||||
return And<Preds...>(std::forward<Preds>(preds)...);
|
||||
}
|
||||
|
||||
template <typename... Preds> Or<Preds...> m_any_of(Preds &&... preds) {
|
||||
return Or<Preds...>(std::forward<Preds>(preds)...);
|
||||
}
|
||||
|
||||
template <typename BindTy> struct bind_helper {
|
||||
static bool bind(const MachineRegisterInfo &MRI, BindTy &VR, BindTy &V) {
|
||||
VR = V;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct bind_helper<MachineInstr *> {
|
||||
static bool bind(const MachineRegisterInfo &MRI, MachineInstr *&MI,
|
||||
Register Reg) {
|
||||
MI = MRI.getVRegDef(Reg);
|
||||
if (MI)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
static bool bind(const MachineRegisterInfo &MRI, MachineInstr *&MI,
|
||||
MachineInstr *Inst) {
|
||||
MI = Inst;
|
||||
return MI;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct bind_helper<LLT> {
|
||||
static bool bind(const MachineRegisterInfo &MRI, LLT Ty, Register Reg) {
|
||||
Ty = MRI.getType(Reg);
|
||||
if (Ty.isValid())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct bind_helper<const ConstantFP *> {
|
||||
static bool bind(const MachineRegisterInfo &MRI, const ConstantFP *&F,
|
||||
Register Reg) {
|
||||
F = getConstantFPVRegVal(Reg, MRI);
|
||||
if (F)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Class> struct bind_ty {
|
||||
Class &VR;
|
||||
|
||||
bind_ty(Class &V) : VR(V) {}
|
||||
|
||||
template <typename ITy> bool match(const MachineRegisterInfo &MRI, ITy &&V) {
|
||||
return bind_helper<Class>::bind(MRI, VR, V);
|
||||
}
|
||||
};
|
||||
|
||||
inline bind_ty<Register> m_Reg(Register &R) { return R; }
|
||||
inline bind_ty<MachineInstr *> m_MInstr(MachineInstr *&MI) { return MI; }
|
||||
inline bind_ty<LLT> m_Type(LLT Ty) { return Ty; }
|
||||
inline bind_ty<CmpInst::Predicate> m_Pred(CmpInst::Predicate &P) { return P; }
|
||||
inline operand_type_match m_Pred() { return operand_type_match(); }
|
||||
|
||||
// Helper for matching G_FCONSTANT
|
||||
inline bind_ty<const ConstantFP *> m_GFCst(const ConstantFP *&C) { return C; }
|
||||
|
||||
// General helper for all the binary generic MI such as G_ADD/G_SUB etc
|
||||
template <typename LHS_P, typename RHS_P, unsigned Opcode,
|
||||
bool Commutable = false>
|
||||
struct BinaryOp_match {
|
||||
LHS_P L;
|
||||
RHS_P R;
|
||||
|
||||
BinaryOp_match(const LHS_P &LHS, const RHS_P &RHS) : L(LHS), R(RHS) {}
|
||||
template <typename OpTy>
|
||||
bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
|
||||
MachineInstr *TmpMI;
|
||||
if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
|
||||
if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 3) {
|
||||
return (L.match(MRI, TmpMI->getOperand(1).getReg()) &&
|
||||
R.match(MRI, TmpMI->getOperand(2).getReg())) ||
|
||||
(Commutable && (R.match(MRI, TmpMI->getOperand(1).getReg()) &&
|
||||
L.match(MRI, TmpMI->getOperand(2).getReg())));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// Helper for (commutative) binary generic MI that checks Opcode.
|
||||
template <typename LHS_P, typename RHS_P, bool Commutable = false>
|
||||
struct BinaryOpc_match {
|
||||
unsigned Opc;
|
||||
LHS_P L;
|
||||
RHS_P R;
|
||||
|
||||
BinaryOpc_match(unsigned Opcode, const LHS_P &LHS, const RHS_P &RHS)
|
||||
: Opc(Opcode), L(LHS), R(RHS) {}
|
||||
template <typename OpTy>
|
||||
bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
|
||||
MachineInstr *TmpMI;
|
||||
if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
|
||||
if (TmpMI->getOpcode() == Opc && TmpMI->getNumDefs() == 1 &&
|
||||
TmpMI->getNumOperands() == 3) {
|
||||
return (L.match(MRI, TmpMI->getOperand(1).getReg()) &&
|
||||
R.match(MRI, TmpMI->getOperand(2).getReg())) ||
|
||||
(Commutable && (R.match(MRI, TmpMI->getOperand(1).getReg()) &&
|
||||
L.match(MRI, TmpMI->getOperand(2).getReg())));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename LHS, typename RHS>
|
||||
inline BinaryOpc_match<LHS, RHS, false> m_BinOp(unsigned Opcode, const LHS &L,
|
||||
const RHS &R) {
|
||||
return BinaryOpc_match<LHS, RHS, false>(Opcode, L, R);
|
||||
}
|
||||
|
||||
template <typename LHS, typename RHS>
|
||||
inline BinaryOpc_match<LHS, RHS, true>
|
||||
m_CommutativeBinOp(unsigned Opcode, const LHS &L, const RHS &R) {
|
||||
return BinaryOpc_match<LHS, RHS, true>(Opcode, L, R);
|
||||
}
|
||||
|
||||
template <typename LHS, typename RHS>
|
||||
inline BinaryOp_match<LHS, RHS, TargetOpcode::G_ADD, true>
|
||||
m_GAdd(const LHS &L, const RHS &R) {
|
||||
return BinaryOp_match<LHS, RHS, TargetOpcode::G_ADD, true>(L, R);
|
||||
}
|
||||
|
||||
template <typename LHS, typename RHS>
|
||||
inline BinaryOp_match<LHS, RHS, TargetOpcode::G_PTR_ADD, false>
|
||||
m_GPtrAdd(const LHS &L, const RHS &R) {
|
||||
return BinaryOp_match<LHS, RHS, TargetOpcode::G_PTR_ADD, false>(L, R);
|
||||
}
|
||||
|
||||
template <typename LHS, typename RHS>
|
||||
inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SUB> m_GSub(const LHS &L,
|
||||
const RHS &R) {
|
||||
return BinaryOp_match<LHS, RHS, TargetOpcode::G_SUB>(L, R);
|
||||
}
|
||||
|
||||
template <typename LHS, typename RHS>
|
||||
inline BinaryOp_match<LHS, RHS, TargetOpcode::G_MUL, true>
|
||||
m_GMul(const LHS &L, const RHS &R) {
|
||||
return BinaryOp_match<LHS, RHS, TargetOpcode::G_MUL, true>(L, R);
|
||||
}
|
||||
|
||||
template <typename LHS, typename RHS>
|
||||
inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FADD, true>
|
||||
m_GFAdd(const LHS &L, const RHS &R) {
|
||||
return BinaryOp_match<LHS, RHS, TargetOpcode::G_FADD, true>(L, R);
|
||||
}
|
||||
|
||||
template <typename LHS, typename RHS>
|
||||
inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FMUL, true>
|
||||
m_GFMul(const LHS &L, const RHS &R) {
|
||||
return BinaryOp_match<LHS, RHS, TargetOpcode::G_FMUL, true>(L, R);
|
||||
}
|
||||
|
||||
template <typename LHS, typename RHS>
|
||||
inline BinaryOp_match<LHS, RHS, TargetOpcode::G_FSUB, false>
|
||||
m_GFSub(const LHS &L, const RHS &R) {
|
||||
return BinaryOp_match<LHS, RHS, TargetOpcode::G_FSUB, false>(L, R);
|
||||
}
|
||||
|
||||
template <typename LHS, typename RHS>
|
||||
inline BinaryOp_match<LHS, RHS, TargetOpcode::G_AND, true>
|
||||
m_GAnd(const LHS &L, const RHS &R) {
|
||||
return BinaryOp_match<LHS, RHS, TargetOpcode::G_AND, true>(L, R);
|
||||
}
|
||||
|
||||
template <typename LHS, typename RHS>
|
||||
inline BinaryOp_match<LHS, RHS, TargetOpcode::G_XOR, true>
|
||||
m_GXor(const LHS &L, const RHS &R) {
|
||||
return BinaryOp_match<LHS, RHS, TargetOpcode::G_XOR, true>(L, R);
|
||||
}
|
||||
|
||||
template <typename LHS, typename RHS>
|
||||
inline BinaryOp_match<LHS, RHS, TargetOpcode::G_OR, true> m_GOr(const LHS &L,
|
||||
const RHS &R) {
|
||||
return BinaryOp_match<LHS, RHS, TargetOpcode::G_OR, true>(L, R);
|
||||
}
|
||||
|
||||
template <typename LHS, typename RHS>
|
||||
inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SHL, false>
|
||||
m_GShl(const LHS &L, const RHS &R) {
|
||||
return BinaryOp_match<LHS, RHS, TargetOpcode::G_SHL, false>(L, R);
|
||||
}
|
||||
|
||||
template <typename LHS, typename RHS>
|
||||
inline BinaryOp_match<LHS, RHS, TargetOpcode::G_LSHR, false>
|
||||
m_GLShr(const LHS &L, const RHS &R) {
|
||||
return BinaryOp_match<LHS, RHS, TargetOpcode::G_LSHR, false>(L, R);
|
||||
}
|
||||
|
||||
template <typename LHS, typename RHS>
|
||||
inline BinaryOp_match<LHS, RHS, TargetOpcode::G_ASHR, false>
|
||||
m_GAShr(const LHS &L, const RHS &R) {
|
||||
return BinaryOp_match<LHS, RHS, TargetOpcode::G_ASHR, false>(L, R);
|
||||
}
|
||||
|
||||
template <typename LHS, typename RHS>
|
||||
inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SMAX, false>
|
||||
m_GSMax(const LHS &L, const RHS &R) {
|
||||
return BinaryOp_match<LHS, RHS, TargetOpcode::G_SMAX, false>(L, R);
|
||||
}
|
||||
|
||||
template <typename LHS, typename RHS>
|
||||
inline BinaryOp_match<LHS, RHS, TargetOpcode::G_SMIN, false>
|
||||
m_GSMin(const LHS &L, const RHS &R) {
|
||||
return BinaryOp_match<LHS, RHS, TargetOpcode::G_SMIN, false>(L, R);
|
||||
}
|
||||
|
||||
// Helper for unary instructions (G_[ZSA]EXT/G_TRUNC) etc
|
||||
template <typename SrcTy, unsigned Opcode> struct UnaryOp_match {
|
||||
SrcTy L;
|
||||
|
||||
UnaryOp_match(const SrcTy &LHS) : L(LHS) {}
|
||||
template <typename OpTy>
|
||||
bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
|
||||
MachineInstr *TmpMI;
|
||||
if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
|
||||
if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 2) {
|
||||
return L.match(MRI, TmpMI->getOperand(1).getReg());
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename SrcTy>
|
||||
inline UnaryOp_match<SrcTy, TargetOpcode::G_ANYEXT>
|
||||
m_GAnyExt(const SrcTy &Src) {
|
||||
return UnaryOp_match<SrcTy, TargetOpcode::G_ANYEXT>(Src);
|
||||
}
|
||||
|
||||
template <typename SrcTy>
|
||||
inline UnaryOp_match<SrcTy, TargetOpcode::G_SEXT> m_GSExt(const SrcTy &Src) {
|
||||
return UnaryOp_match<SrcTy, TargetOpcode::G_SEXT>(Src);
|
||||
}
|
||||
|
||||
template <typename SrcTy>
|
||||
inline UnaryOp_match<SrcTy, TargetOpcode::G_ZEXT> m_GZExt(const SrcTy &Src) {
|
||||
return UnaryOp_match<SrcTy, TargetOpcode::G_ZEXT>(Src);
|
||||
}
|
||||
|
||||
template <typename SrcTy>
|
||||
inline UnaryOp_match<SrcTy, TargetOpcode::G_FPEXT> m_GFPExt(const SrcTy &Src) {
|
||||
return UnaryOp_match<SrcTy, TargetOpcode::G_FPEXT>(Src);
|
||||
}
|
||||
|
||||
template <typename SrcTy>
|
||||
inline UnaryOp_match<SrcTy, TargetOpcode::G_TRUNC> m_GTrunc(const SrcTy &Src) {
|
||||
return UnaryOp_match<SrcTy, TargetOpcode::G_TRUNC>(Src);
|
||||
}
|
||||
|
||||
template <typename SrcTy>
|
||||
inline UnaryOp_match<SrcTy, TargetOpcode::G_BITCAST>
|
||||
m_GBitcast(const SrcTy &Src) {
|
||||
return UnaryOp_match<SrcTy, TargetOpcode::G_BITCAST>(Src);
|
||||
}
|
||||
|
||||
template <typename SrcTy>
|
||||
inline UnaryOp_match<SrcTy, TargetOpcode::G_PTRTOINT>
|
||||
m_GPtrToInt(const SrcTy &Src) {
|
||||
return UnaryOp_match<SrcTy, TargetOpcode::G_PTRTOINT>(Src);
|
||||
}
|
||||
|
||||
template <typename SrcTy>
|
||||
inline UnaryOp_match<SrcTy, TargetOpcode::G_INTTOPTR>
|
||||
m_GIntToPtr(const SrcTy &Src) {
|
||||
return UnaryOp_match<SrcTy, TargetOpcode::G_INTTOPTR>(Src);
|
||||
}
|
||||
|
||||
template <typename SrcTy>
|
||||
inline UnaryOp_match<SrcTy, TargetOpcode::G_FPTRUNC>
|
||||
m_GFPTrunc(const SrcTy &Src) {
|
||||
return UnaryOp_match<SrcTy, TargetOpcode::G_FPTRUNC>(Src);
|
||||
}
|
||||
|
||||
template <typename SrcTy>
|
||||
inline UnaryOp_match<SrcTy, TargetOpcode::G_FABS> m_GFabs(const SrcTy &Src) {
|
||||
return UnaryOp_match<SrcTy, TargetOpcode::G_FABS>(Src);
|
||||
}
|
||||
|
||||
template <typename SrcTy>
|
||||
inline UnaryOp_match<SrcTy, TargetOpcode::G_FNEG> m_GFNeg(const SrcTy &Src) {
|
||||
return UnaryOp_match<SrcTy, TargetOpcode::G_FNEG>(Src);
|
||||
}
|
||||
|
||||
template <typename SrcTy>
|
||||
inline UnaryOp_match<SrcTy, TargetOpcode::COPY> m_Copy(SrcTy &&Src) {
|
||||
return UnaryOp_match<SrcTy, TargetOpcode::COPY>(std::forward<SrcTy>(Src));
|
||||
}
|
||||
|
||||
template <typename SrcTy>
|
||||
inline UnaryOp_match<SrcTy, TargetOpcode::G_FSQRT> m_GFSqrt(const SrcTy &Src) {
|
||||
return UnaryOp_match<SrcTy, TargetOpcode::G_FSQRT>(Src);
|
||||
}
|
||||
|
||||
// General helper for generic MI compares, i.e. G_ICMP and G_FCMP
|
||||
// TODO: Allow checking a specific predicate.
|
||||
template <typename Pred_P, typename LHS_P, typename RHS_P, unsigned Opcode>
|
||||
struct CompareOp_match {
|
||||
Pred_P P;
|
||||
LHS_P L;
|
||||
RHS_P R;
|
||||
|
||||
CompareOp_match(const Pred_P &Pred, const LHS_P &LHS, const RHS_P &RHS)
|
||||
: P(Pred), L(LHS), R(RHS) {}
|
||||
|
||||
template <typename OpTy>
|
||||
bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
|
||||
MachineInstr *TmpMI;
|
||||
if (!mi_match(Op, MRI, m_MInstr(TmpMI)) || TmpMI->getOpcode() != Opcode)
|
||||
return false;
|
||||
|
||||
auto TmpPred =
|
||||
static_cast<CmpInst::Predicate>(TmpMI->getOperand(1).getPredicate());
|
||||
if (!P.match(MRI, TmpPred))
|
||||
return false;
|
||||
|
||||
return L.match(MRI, TmpMI->getOperand(2).getReg()) &&
|
||||
R.match(MRI, TmpMI->getOperand(3).getReg());
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Pred, typename LHS, typename RHS>
|
||||
inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP>
|
||||
m_GICmp(const Pred &P, const LHS &L, const RHS &R) {
|
||||
return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_ICMP>(P, L, R);
|
||||
}
|
||||
|
||||
template <typename Pred, typename LHS, typename RHS>
|
||||
inline CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP>
|
||||
m_GFCmp(const Pred &P, const LHS &L, const RHS &R) {
|
||||
return CompareOp_match<Pred, LHS, RHS, TargetOpcode::G_FCMP>(P, L, R);
|
||||
}
|
||||
|
||||
// Helper for checking if a Reg is of specific type.
|
||||
struct CheckType {
|
||||
LLT Ty;
|
||||
CheckType(const LLT Ty) : Ty(Ty) {}
|
||||
|
||||
bool match(const MachineRegisterInfo &MRI, Register Reg) {
|
||||
return MRI.getType(Reg) == Ty;
|
||||
}
|
||||
};
|
||||
|
||||
inline CheckType m_SpecificType(LLT Ty) { return Ty; }
|
||||
|
||||
template <typename Src0Ty, typename Src1Ty, typename Src2Ty, unsigned Opcode>
|
||||
struct TernaryOp_match {
|
||||
Src0Ty Src0;
|
||||
Src1Ty Src1;
|
||||
Src2Ty Src2;
|
||||
|
||||
TernaryOp_match(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2)
|
||||
: Src0(Src0), Src1(Src1), Src2(Src2) {}
|
||||
template <typename OpTy>
|
||||
bool match(const MachineRegisterInfo &MRI, OpTy &&Op) {
|
||||
MachineInstr *TmpMI;
|
||||
if (mi_match(Op, MRI, m_MInstr(TmpMI))) {
|
||||
if (TmpMI->getOpcode() == Opcode && TmpMI->getNumOperands() == 4) {
|
||||
return (Src0.match(MRI, TmpMI->getOperand(1).getReg()) &&
|
||||
Src1.match(MRI, TmpMI->getOperand(2).getReg()) &&
|
||||
Src2.match(MRI, TmpMI->getOperand(3).getReg()));
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
template <typename Src0Ty, typename Src1Ty, typename Src2Ty>
|
||||
inline TernaryOp_match<Src0Ty, Src1Ty, Src2Ty,
|
||||
TargetOpcode::G_INSERT_VECTOR_ELT>
|
||||
m_GInsertVecElt(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2) {
|
||||
return TernaryOp_match<Src0Ty, Src1Ty, Src2Ty,
|
||||
TargetOpcode::G_INSERT_VECTOR_ELT>(Src0, Src1, Src2);
|
||||
}
|
||||
|
||||
template <typename Src0Ty, typename Src1Ty, typename Src2Ty>
|
||||
inline TernaryOp_match<Src0Ty, Src1Ty, Src2Ty, TargetOpcode::G_SELECT>
|
||||
m_GISelect(const Src0Ty &Src0, const Src1Ty &Src1, const Src2Ty &Src2) {
|
||||
return TernaryOp_match<Src0Ty, Src1Ty, Src2Ty, TargetOpcode::G_SELECT>(
|
||||
Src0, Src1, Src2);
|
||||
}
|
||||
|
||||
/// Matches a register negated by a G_SUB.
|
||||
/// G_SUB 0, %negated_reg
|
||||
template <typename SrcTy>
|
||||
inline BinaryOp_match<SpecificConstantMatch, SrcTy, TargetOpcode::G_SUB>
|
||||
m_Neg(const SrcTy &&Src) {
|
||||
return m_GSub(m_ZeroInt(), Src);
|
||||
}
|
||||
|
||||
/// Matches a register not-ed by a G_XOR.
|
||||
/// G_XOR %not_reg, -1
|
||||
template <typename SrcTy>
|
||||
inline BinaryOp_match<SrcTy, SpecificConstantMatch, TargetOpcode::G_XOR, true>
|
||||
m_Not(const SrcTy &&Src) {
|
||||
return m_GXor(Src, m_AllOnesInt());
|
||||
}
|
||||
|
||||
} // namespace MIPatternMatch
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
1931
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
vendored
Normal file
1931
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/MachineIRBuilder.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
670
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/RegBankSelect.h
vendored
Normal file
670
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/RegBankSelect.h
vendored
Normal file
@@ -0,0 +1,670 @@
|
||||
//=- llvm/CodeGen/GlobalISel/RegBankSelect.h - Reg Bank Selector --*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
/// \file
|
||||
/// This file describes the interface of the MachineFunctionPass
|
||||
/// responsible for assigning the generic virtual registers to register bank.
|
||||
///
|
||||
/// By default, the reg bank selector relies on local decisions to
|
||||
/// assign the register bank. In other words, it looks at one instruction
|
||||
/// at a time to decide where the operand of that instruction should live.
|
||||
///
|
||||
/// At higher optimization level, we could imagine that the reg bank selector
|
||||
/// would use more global analysis and do crazier thing like duplicating
|
||||
/// instructions and so on. This is future work.
|
||||
///
|
||||
/// For now, the pass uses a greedy algorithm to decide where the operand
|
||||
/// of an instruction should live. It asks the target which banks may be
|
||||
/// used for each operand of the instruction and what is the cost. Then,
|
||||
/// it chooses the solution which minimize the cost of the instruction plus
|
||||
/// the cost of any move that may be needed to the values into the right
|
||||
/// register bank.
|
||||
/// In other words, the cost for an instruction on a register bank RegBank
|
||||
/// is: Cost of I on RegBank plus the sum of the cost for bringing the
|
||||
/// input operands from their current register bank to RegBank.
|
||||
/// Thus, the following formula:
|
||||
/// cost(I, RegBank) = cost(I.Opcode, RegBank) +
|
||||
/// sum(for each arg in I.arguments: costCrossCopy(arg.RegBank, RegBank))
|
||||
///
|
||||
/// E.g., Let say we are assigning the register bank for the instruction
|
||||
/// defining v2.
|
||||
/// v0(A_REGBANK) = ...
|
||||
/// v1(A_REGBANK) = ...
|
||||
/// v2 = G_ADD i32 v0, v1 <-- MI
|
||||
///
|
||||
/// The target may say it can generate G_ADD i32 on register bank A and B
|
||||
/// with a cost of respectively 5 and 1.
|
||||
/// Then, let say the cost of a cross register bank copies from A to B is 1.
|
||||
/// The reg bank selector would compare the following two costs:
|
||||
/// cost(MI, A_REGBANK) = cost(G_ADD, A_REGBANK) + cost(v0.RegBank, A_REGBANK) +
|
||||
/// cost(v1.RegBank, A_REGBANK)
|
||||
/// = 5 + cost(A_REGBANK, A_REGBANK) + cost(A_REGBANK,
|
||||
/// A_REGBANK)
|
||||
/// = 5 + 0 + 0 = 5
|
||||
/// cost(MI, B_REGBANK) = cost(G_ADD, B_REGBANK) + cost(v0.RegBank, B_REGBANK) +
|
||||
/// cost(v1.RegBank, B_REGBANK)
|
||||
/// = 1 + cost(A_REGBANK, B_REGBANK) + cost(A_REGBANK,
|
||||
/// B_REGBANK)
|
||||
/// = 1 + 1 + 1 = 3
|
||||
/// Therefore, in this specific example, the reg bank selector would choose
|
||||
/// bank B for MI.
|
||||
/// v0(A_REGBANK) = ...
|
||||
/// v1(A_REGBANK) = ...
|
||||
/// tmp0(B_REGBANK) = COPY v0
|
||||
/// tmp1(B_REGBANK) = COPY v1
|
||||
/// v2(B_REGBANK) = G_ADD i32 tmp0, tmp1
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_REGBANKSELECT_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_REGBANKSELECT_H
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
|
||||
#include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class BlockFrequency;
|
||||
class MachineBlockFrequencyInfo;
|
||||
class MachineBranchProbabilityInfo;
|
||||
class MachineOperand;
|
||||
class MachineRegisterInfo;
|
||||
class Pass;
|
||||
class raw_ostream;
|
||||
class TargetPassConfig;
|
||||
class TargetRegisterInfo;
|
||||
|
||||
/// This pass implements the reg bank selector pass used in the GlobalISel
|
||||
/// pipeline. At the end of this pass, all register operands have been assigned
|
||||
class RegBankSelect : public MachineFunctionPass {
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
/// List of the modes supported by the RegBankSelect pass.
|
||||
enum Mode {
|
||||
/// Assign the register banks as fast as possible (default).
|
||||
Fast,
|
||||
/// Greedily minimize the cost of assigning register banks.
|
||||
/// This should produce code of greater quality, but will
|
||||
/// require more compile time.
|
||||
Greedy
|
||||
};
|
||||
|
||||
/// Abstract class used to represent an insertion point in a CFG.
|
||||
/// This class records an insertion point and materializes it on
|
||||
/// demand.
|
||||
/// It allows to reason about the frequency of this insertion point,
|
||||
/// without having to logically materialize it (e.g., on an edge),
|
||||
/// before we actually need to insert something.
|
||||
class InsertPoint {
|
||||
protected:
|
||||
/// Tell if the insert point has already been materialized.
|
||||
bool WasMaterialized = false;
|
||||
|
||||
/// Materialize the insertion point.
|
||||
///
|
||||
/// If isSplit() is true, this involves actually splitting
|
||||
/// the block or edge.
|
||||
///
|
||||
/// \post getPointImpl() returns a valid iterator.
|
||||
/// \post getInsertMBBImpl() returns a valid basic block.
|
||||
/// \post isSplit() == false ; no more splitting should be required.
|
||||
virtual void materialize() = 0;
|
||||
|
||||
/// Return the materialized insertion basic block.
|
||||
/// Code will be inserted into that basic block.
|
||||
///
|
||||
/// \pre ::materialize has been called.
|
||||
virtual MachineBasicBlock &getInsertMBBImpl() = 0;
|
||||
|
||||
/// Return the materialized insertion point.
|
||||
/// Code will be inserted before that point.
|
||||
///
|
||||
/// \pre ::materialize has been called.
|
||||
virtual MachineBasicBlock::iterator getPointImpl() = 0;
|
||||
|
||||
public:
|
||||
virtual ~InsertPoint() = default;
|
||||
|
||||
/// The first call to this method will cause the splitting to
|
||||
/// happen if need be, then sub sequent calls just return
|
||||
/// the iterator to that point. I.e., no more splitting will
|
||||
/// occur.
|
||||
///
|
||||
/// \return The iterator that should be used with
|
||||
/// MachineBasicBlock::insert. I.e., additional code happens
|
||||
/// before that point.
|
||||
MachineBasicBlock::iterator getPoint() {
|
||||
if (!WasMaterialized) {
|
||||
WasMaterialized = true;
|
||||
assert(canMaterialize() && "Impossible to materialize this point");
|
||||
materialize();
|
||||
}
|
||||
// When we materialized the point we should have done the splitting.
|
||||
assert(!isSplit() && "Wrong pre-condition");
|
||||
return getPointImpl();
|
||||
}
|
||||
|
||||
/// The first call to this method will cause the splitting to
|
||||
/// happen if need be, then sub sequent calls just return
|
||||
/// the basic block that contains the insertion point.
|
||||
/// I.e., no more splitting will occur.
|
||||
///
|
||||
/// \return The basic block should be used with
|
||||
/// MachineBasicBlock::insert and ::getPoint. The new code should
|
||||
/// happen before that point.
|
||||
MachineBasicBlock &getInsertMBB() {
|
||||
if (!WasMaterialized) {
|
||||
WasMaterialized = true;
|
||||
assert(canMaterialize() && "Impossible to materialize this point");
|
||||
materialize();
|
||||
}
|
||||
// When we materialized the point we should have done the splitting.
|
||||
assert(!isSplit() && "Wrong pre-condition");
|
||||
return getInsertMBBImpl();
|
||||
}
|
||||
|
||||
/// Insert \p MI in the just before ::getPoint()
|
||||
MachineBasicBlock::iterator insert(MachineInstr &MI) {
|
||||
return getInsertMBB().insert(getPoint(), &MI);
|
||||
}
|
||||
|
||||
/// Does this point involve splitting an edge or block?
|
||||
/// As soon as ::getPoint is called and thus, the point
|
||||
/// materialized, the point will not require splitting anymore,
|
||||
/// i.e., this will return false.
|
||||
virtual bool isSplit() const { return false; }
|
||||
|
||||
/// Frequency of the insertion point.
|
||||
/// \p P is used to access the various analysis that will help to
|
||||
/// get that information, like MachineBlockFrequencyInfo. If \p P
|
||||
/// does not contain enough enough to return the actual frequency,
|
||||
/// this returns 1.
|
||||
virtual uint64_t frequency(const Pass &P) const { return 1; }
|
||||
|
||||
/// Check whether this insertion point can be materialized.
|
||||
/// As soon as ::getPoint is called and thus, the point materialized
|
||||
/// calling this method does not make sense.
|
||||
virtual bool canMaterialize() const { return false; }
|
||||
};
|
||||
|
||||
/// Insertion point before or after an instruction.
|
||||
class InstrInsertPoint : public InsertPoint {
|
||||
private:
|
||||
/// Insertion point.
|
||||
MachineInstr &Instr;
|
||||
|
||||
/// Does the insertion point is before or after Instr.
|
||||
bool Before;
|
||||
|
||||
void materialize() override;
|
||||
|
||||
MachineBasicBlock::iterator getPointImpl() override {
|
||||
if (Before)
|
||||
return Instr;
|
||||
return Instr.getNextNode() ? *Instr.getNextNode()
|
||||
: Instr.getParent()->end();
|
||||
}
|
||||
|
||||
MachineBasicBlock &getInsertMBBImpl() override {
|
||||
return *Instr.getParent();
|
||||
}
|
||||
|
||||
public:
|
||||
/// Create an insertion point before (\p Before=true) or after \p Instr.
|
||||
InstrInsertPoint(MachineInstr &Instr, bool Before = true);
|
||||
|
||||
bool isSplit() const override;
|
||||
uint64_t frequency(const Pass &P) const override;
|
||||
|
||||
// Worst case, we need to slice the basic block, but that is still doable.
|
||||
bool canMaterialize() const override { return true; }
|
||||
};
|
||||
|
||||
/// Insertion point at the beginning or end of a basic block.
|
||||
class MBBInsertPoint : public InsertPoint {
|
||||
private:
|
||||
/// Insertion point.
|
||||
MachineBasicBlock &MBB;
|
||||
|
||||
/// Does the insertion point is at the beginning or end of MBB.
|
||||
bool Beginning;
|
||||
|
||||
void materialize() override { /*Nothing to do to materialize*/
|
||||
}
|
||||
|
||||
MachineBasicBlock::iterator getPointImpl() override {
|
||||
return Beginning ? MBB.begin() : MBB.end();
|
||||
}
|
||||
|
||||
MachineBasicBlock &getInsertMBBImpl() override { return MBB; }
|
||||
|
||||
public:
|
||||
MBBInsertPoint(MachineBasicBlock &MBB, bool Beginning = true)
|
||||
: MBB(MBB), Beginning(Beginning) {
|
||||
// If we try to insert before phis, we should use the insertion
|
||||
// points on the incoming edges.
|
||||
assert((!Beginning || MBB.getFirstNonPHI() == MBB.begin()) &&
|
||||
"Invalid beginning point");
|
||||
// If we try to insert after the terminators, we should use the
|
||||
// points on the outcoming edges.
|
||||
assert((Beginning || MBB.getFirstTerminator() == MBB.end()) &&
|
||||
"Invalid end point");
|
||||
}
|
||||
|
||||
bool isSplit() const override { return false; }
|
||||
uint64_t frequency(const Pass &P) const override;
|
||||
bool canMaterialize() const override { return true; };
|
||||
};
|
||||
|
||||
/// Insertion point on an edge.
|
||||
class EdgeInsertPoint : public InsertPoint {
|
||||
private:
|
||||
/// Source of the edge.
|
||||
MachineBasicBlock &Src;
|
||||
|
||||
/// Destination of the edge.
|
||||
/// After the materialization is done, this hold the basic block
|
||||
/// that resulted from the splitting.
|
||||
MachineBasicBlock *DstOrSplit;
|
||||
|
||||
/// P is used to update the analysis passes as applicable.
|
||||
Pass &P;
|
||||
|
||||
void materialize() override;
|
||||
|
||||
MachineBasicBlock::iterator getPointImpl() override {
|
||||
// DstOrSplit should be the Split block at this point.
|
||||
// I.e., it should have one predecessor, Src, and one successor,
|
||||
// the original Dst.
|
||||
assert(DstOrSplit && DstOrSplit->isPredecessor(&Src) &&
|
||||
DstOrSplit->pred_size() == 1 && DstOrSplit->succ_size() == 1 &&
|
||||
"Did not split?!");
|
||||
return DstOrSplit->begin();
|
||||
}
|
||||
|
||||
MachineBasicBlock &getInsertMBBImpl() override { return *DstOrSplit; }
|
||||
|
||||
public:
|
||||
EdgeInsertPoint(MachineBasicBlock &Src, MachineBasicBlock &Dst, Pass &P)
|
||||
: Src(Src), DstOrSplit(&Dst), P(P) {}
|
||||
|
||||
bool isSplit() const override {
|
||||
return Src.succ_size() > 1 && DstOrSplit->pred_size() > 1;
|
||||
}
|
||||
|
||||
uint64_t frequency(const Pass &P) const override;
|
||||
bool canMaterialize() const override;
|
||||
};
|
||||
|
||||
/// Struct used to represent the placement of a repairing point for
|
||||
/// a given operand.
|
||||
class RepairingPlacement {
|
||||
public:
|
||||
/// Define the kind of action this repairing needs.
|
||||
enum RepairingKind {
|
||||
/// Nothing to repair, just drop this action.
|
||||
None,
|
||||
/// Reparing code needs to happen before InsertPoints.
|
||||
Insert,
|
||||
/// (Re)assign the register bank of the operand.
|
||||
Reassign,
|
||||
/// Mark this repairing placement as impossible.
|
||||
Impossible
|
||||
};
|
||||
|
||||
/// \name Convenient types for a list of insertion points.
|
||||
/// @{
|
||||
using InsertionPoints = SmallVector<std::unique_ptr<InsertPoint>, 2>;
|
||||
using insertpt_iterator = InsertionPoints::iterator;
|
||||
using const_insertpt_iterator = InsertionPoints::const_iterator;
|
||||
/// @}
|
||||
|
||||
private:
|
||||
/// Kind of repairing.
|
||||
RepairingKind Kind;
|
||||
/// Index of the operand that will be repaired.
|
||||
unsigned OpIdx;
|
||||
/// Are all the insert points materializeable?
|
||||
bool CanMaterialize;
|
||||
/// Is there any of the insert points needing splitting?
|
||||
bool HasSplit = false;
|
||||
/// Insertion point for the repair code.
|
||||
/// The repairing code needs to happen just before these points.
|
||||
InsertionPoints InsertPoints;
|
||||
/// Some insertion points may need to update the liveness and such.
|
||||
Pass &P;
|
||||
|
||||
public:
|
||||
/// Create a repairing placement for the \p OpIdx-th operand of
|
||||
/// \p MI. \p TRI is used to make some checks on the register aliases
|
||||
/// if the machine operand is a physical register. \p P is used to
|
||||
/// to update liveness information and such when materializing the
|
||||
/// points.
|
||||
RepairingPlacement(MachineInstr &MI, unsigned OpIdx,
|
||||
const TargetRegisterInfo &TRI, Pass &P,
|
||||
RepairingKind Kind = RepairingKind::Insert);
|
||||
|
||||
/// \name Getters.
|
||||
/// @{
|
||||
RepairingKind getKind() const { return Kind; }
|
||||
unsigned getOpIdx() const { return OpIdx; }
|
||||
bool canMaterialize() const { return CanMaterialize; }
|
||||
bool hasSplit() { return HasSplit; }
|
||||
/// @}
|
||||
|
||||
/// \name Overloaded methods to add an insertion point.
|
||||
/// @{
|
||||
/// Add a MBBInsertionPoint to the list of InsertPoints.
|
||||
void addInsertPoint(MachineBasicBlock &MBB, bool Beginning);
|
||||
/// Add a InstrInsertionPoint to the list of InsertPoints.
|
||||
void addInsertPoint(MachineInstr &MI, bool Before);
|
||||
/// Add an EdgeInsertionPoint (\p Src, \p Dst) to the list of InsertPoints.
|
||||
void addInsertPoint(MachineBasicBlock &Src, MachineBasicBlock &Dst);
|
||||
/// Add an InsertPoint to the list of insert points.
|
||||
/// This method takes the ownership of &\p Point.
|
||||
void addInsertPoint(InsertPoint &Point);
|
||||
/// @}
|
||||
|
||||
/// \name Accessors related to the insertion points.
|
||||
/// @{
|
||||
insertpt_iterator begin() { return InsertPoints.begin(); }
|
||||
insertpt_iterator end() { return InsertPoints.end(); }
|
||||
|
||||
const_insertpt_iterator begin() const { return InsertPoints.begin(); }
|
||||
const_insertpt_iterator end() const { return InsertPoints.end(); }
|
||||
|
||||
unsigned getNumInsertPoints() const { return InsertPoints.size(); }
|
||||
/// @}
|
||||
|
||||
/// Change the type of this repairing placement to \p NewKind.
|
||||
/// It is not possible to switch a repairing placement to the
|
||||
/// RepairingKind::Insert. There is no fundamental problem with
|
||||
/// that, but no uses as well, so do not support it for now.
|
||||
///
|
||||
/// \pre NewKind != RepairingKind::Insert
|
||||
/// \post getKind() == NewKind
|
||||
void switchTo(RepairingKind NewKind) {
|
||||
assert(NewKind != Kind && "Already of the right Kind");
|
||||
Kind = NewKind;
|
||||
InsertPoints.clear();
|
||||
CanMaterialize = NewKind != RepairingKind::Impossible;
|
||||
HasSplit = false;
|
||||
assert(NewKind != RepairingKind::Insert &&
|
||||
"We would need more MI to switch to Insert");
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
/// Helper class used to represent the cost for mapping an instruction.
|
||||
/// When mapping an instruction, we may introduce some repairing code.
|
||||
/// In most cases, the repairing code is local to the instruction,
|
||||
/// thus, we can omit the basic block frequency from the cost.
|
||||
/// However, some alternatives may produce non-local cost, e.g., when
|
||||
/// repairing a phi, and thus we then need to scale the local cost
|
||||
/// to the non-local cost. This class does this for us.
|
||||
/// \note: We could simply always scale the cost. The problem is that
|
||||
/// there are higher chances that we saturate the cost easier and end
|
||||
/// up having the same cost for actually different alternatives.
|
||||
/// Another option would be to use APInt everywhere.
|
||||
class MappingCost {
|
||||
private:
|
||||
/// Cost of the local instructions.
|
||||
/// This cost is free of basic block frequency.
|
||||
uint64_t LocalCost = 0;
|
||||
/// Cost of the non-local instructions.
|
||||
/// This cost should include the frequency of the related blocks.
|
||||
uint64_t NonLocalCost = 0;
|
||||
/// Frequency of the block where the local instructions live.
|
||||
uint64_t LocalFreq;
|
||||
|
||||
MappingCost(uint64_t LocalCost, uint64_t NonLocalCost, uint64_t LocalFreq)
|
||||
: LocalCost(LocalCost), NonLocalCost(NonLocalCost),
|
||||
LocalFreq(LocalFreq) {}
|
||||
|
||||
/// Check if this cost is saturated.
|
||||
bool isSaturated() const;
|
||||
|
||||
public:
|
||||
/// Create a MappingCost assuming that most of the instructions
|
||||
/// will occur in a basic block with \p LocalFreq frequency.
|
||||
MappingCost(const BlockFrequency &LocalFreq);
|
||||
|
||||
/// Add \p Cost to the local cost.
|
||||
/// \return true if this cost is saturated, false otherwise.
|
||||
bool addLocalCost(uint64_t Cost);
|
||||
|
||||
/// Add \p Cost to the non-local cost.
|
||||
/// Non-local cost should reflect the frequency of their placement.
|
||||
/// \return true if this cost is saturated, false otherwise.
|
||||
bool addNonLocalCost(uint64_t Cost);
|
||||
|
||||
/// Saturate the cost to the maximal representable value.
|
||||
void saturate();
|
||||
|
||||
/// Return an instance of MappingCost that represents an
|
||||
/// impossible mapping.
|
||||
static MappingCost ImpossibleCost();
|
||||
|
||||
/// Check if this is less than \p Cost.
|
||||
bool operator<(const MappingCost &Cost) const;
|
||||
/// Check if this is equal to \p Cost.
|
||||
bool operator==(const MappingCost &Cost) const;
|
||||
/// Check if this is not equal to \p Cost.
|
||||
bool operator!=(const MappingCost &Cost) const { return !(*this == Cost); }
|
||||
/// Check if this is greater than \p Cost.
|
||||
bool operator>(const MappingCost &Cost) const {
|
||||
return *this != Cost && Cost < *this;
|
||||
}
|
||||
|
||||
/// Print this on dbgs() stream.
|
||||
void dump() const;
|
||||
|
||||
/// Print this on \p OS;
|
||||
void print(raw_ostream &OS) const;
|
||||
|
||||
/// Overload the stream operator for easy debug printing.
|
||||
friend raw_ostream &operator<<(raw_ostream &OS, const MappingCost &Cost) {
|
||||
Cost.print(OS);
|
||||
return OS;
|
||||
}
|
||||
};
|
||||
|
||||
/// Interface to the target lowering info related
|
||||
/// to register banks.
|
||||
const RegisterBankInfo *RBI = nullptr;
|
||||
|
||||
/// MRI contains all the register class/bank information that this
|
||||
/// pass uses and updates.
|
||||
MachineRegisterInfo *MRI = nullptr;
|
||||
|
||||
/// Information on the register classes for the current function.
|
||||
const TargetRegisterInfo *TRI = nullptr;
|
||||
|
||||
/// Get the frequency of blocks.
|
||||
/// This is required for non-fast mode.
|
||||
MachineBlockFrequencyInfo *MBFI = nullptr;
|
||||
|
||||
/// Get the frequency of the edges.
|
||||
/// This is required for non-fast mode.
|
||||
MachineBranchProbabilityInfo *MBPI = nullptr;
|
||||
|
||||
/// Current optimization remark emitter. Used to report failures.
|
||||
std::unique_ptr<MachineOptimizationRemarkEmitter> MORE;
|
||||
|
||||
/// Helper class used for every code morphing.
|
||||
MachineIRBuilder MIRBuilder;
|
||||
|
||||
/// Optimization mode of the pass.
|
||||
Mode OptMode;
|
||||
|
||||
/// Current target configuration. Controls how the pass handles errors.
|
||||
const TargetPassConfig *TPC;
|
||||
|
||||
/// Assign the register bank of each operand of \p MI.
|
||||
/// \return True on success, false otherwise.
|
||||
bool assignInstr(MachineInstr &MI);
|
||||
|
||||
/// Initialize the field members using \p MF.
|
||||
void init(MachineFunction &MF);
|
||||
|
||||
/// Check if \p Reg is already assigned what is described by \p ValMapping.
|
||||
/// \p OnlyAssign == true means that \p Reg just needs to be assigned a
|
||||
/// register bank. I.e., no repairing is necessary to have the
|
||||
/// assignment match.
|
||||
bool assignmentMatch(Register Reg,
|
||||
const RegisterBankInfo::ValueMapping &ValMapping,
|
||||
bool &OnlyAssign) const;
|
||||
|
||||
/// Insert repairing code for \p Reg as specified by \p ValMapping.
|
||||
/// The repairing placement is specified by \p RepairPt.
|
||||
/// \p NewVRegs contains all the registers required to remap \p Reg.
|
||||
/// In other words, the number of registers in NewVRegs must be equal
|
||||
/// to ValMapping.BreakDown.size().
|
||||
///
|
||||
/// The transformation could be sketched as:
|
||||
/// \code
|
||||
/// ... = op Reg
|
||||
/// \endcode
|
||||
/// Becomes
|
||||
/// \code
|
||||
/// <NewRegs> = COPY or extract Reg
|
||||
/// ... = op Reg
|
||||
/// \endcode
|
||||
///
|
||||
/// and
|
||||
/// \code
|
||||
/// Reg = op ...
|
||||
/// \endcode
|
||||
/// Becomes
|
||||
/// \code
|
||||
/// Reg = op ...
|
||||
/// Reg = COPY or build_sequence <NewRegs>
|
||||
/// \endcode
|
||||
///
|
||||
/// \pre NewVRegs.size() == ValMapping.BreakDown.size()
|
||||
///
|
||||
/// \note The caller is supposed to do the rewriting of op if need be.
|
||||
/// I.e., Reg = op ... => <NewRegs> = NewOp ...
|
||||
///
|
||||
/// \return True if the repairing worked, false otherwise.
|
||||
bool repairReg(MachineOperand &MO,
|
||||
const RegisterBankInfo::ValueMapping &ValMapping,
|
||||
RegBankSelect::RepairingPlacement &RepairPt,
|
||||
const iterator_range<SmallVectorImpl<Register>::const_iterator>
|
||||
&NewVRegs);
|
||||
|
||||
/// Return the cost of the instruction needed to map \p MO to \p ValMapping.
|
||||
/// The cost is free of basic block frequencies.
|
||||
/// \pre MO.isReg()
|
||||
/// \pre MO is assigned to a register bank.
|
||||
/// \pre ValMapping is a valid mapping for MO.
|
||||
uint64_t
|
||||
getRepairCost(const MachineOperand &MO,
|
||||
const RegisterBankInfo::ValueMapping &ValMapping) const;
|
||||
|
||||
/// Find the best mapping for \p MI from \p PossibleMappings.
|
||||
/// \return a reference on the best mapping in \p PossibleMappings.
|
||||
const RegisterBankInfo::InstructionMapping &
|
||||
findBestMapping(MachineInstr &MI,
|
||||
RegisterBankInfo::InstructionMappings &PossibleMappings,
|
||||
SmallVectorImpl<RepairingPlacement> &RepairPts);
|
||||
|
||||
/// Compute the cost of mapping \p MI with \p InstrMapping and
|
||||
/// compute the repairing placement for such mapping in \p
|
||||
/// RepairPts.
|
||||
/// \p BestCost is used to specify when the cost becomes too high
|
||||
/// and thus it is not worth computing the RepairPts. Moreover if
|
||||
/// \p BestCost == nullptr, the mapping cost is actually not
|
||||
/// computed.
|
||||
MappingCost
|
||||
computeMapping(MachineInstr &MI,
|
||||
const RegisterBankInfo::InstructionMapping &InstrMapping,
|
||||
SmallVectorImpl<RepairingPlacement> &RepairPts,
|
||||
const MappingCost *BestCost = nullptr);
|
||||
|
||||
/// When \p RepairPt involves splitting to repair \p MO for the
|
||||
/// given \p ValMapping, try to change the way we repair such that
|
||||
/// the splitting is not required anymore.
|
||||
///
|
||||
/// \pre \p RepairPt.hasSplit()
|
||||
/// \pre \p MO == MO.getParent()->getOperand(\p RepairPt.getOpIdx())
|
||||
/// \pre \p ValMapping is the mapping of \p MO for MO.getParent()
|
||||
/// that implied \p RepairPt.
|
||||
void tryAvoidingSplit(RegBankSelect::RepairingPlacement &RepairPt,
|
||||
const MachineOperand &MO,
|
||||
const RegisterBankInfo::ValueMapping &ValMapping) const;
|
||||
|
||||
/// Apply \p Mapping to \p MI. \p RepairPts represents the different
|
||||
/// mapping action that need to happen for the mapping to be
|
||||
/// applied.
|
||||
/// \return True if the mapping was applied successfully, false otherwise.
|
||||
bool applyMapping(MachineInstr &MI,
|
||||
const RegisterBankInfo::InstructionMapping &InstrMapping,
|
||||
SmallVectorImpl<RepairingPlacement> &RepairPts);
|
||||
|
||||
public:
|
||||
/// Create a RegBankSelect pass with the specified \p RunningMode.
|
||||
RegBankSelect(Mode RunningMode = Fast);
|
||||
|
||||
StringRef getPassName() const override { return "RegBankSelect"; }
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
MachineFunctionProperties getRequiredProperties() const override {
|
||||
return MachineFunctionProperties()
|
||||
.set(MachineFunctionProperties::Property::IsSSA)
|
||||
.set(MachineFunctionProperties::Property::Legalized);
|
||||
}
|
||||
|
||||
MachineFunctionProperties getSetProperties() const override {
|
||||
return MachineFunctionProperties().set(
|
||||
MachineFunctionProperties::Property::RegBankSelected);
|
||||
}
|
||||
|
||||
MachineFunctionProperties getClearedProperties() const override {
|
||||
return MachineFunctionProperties()
|
||||
.set(MachineFunctionProperties::Property::NoPHIs);
|
||||
}
|
||||
|
||||
/// Walk through \p MF and assign a register bank to every virtual register
|
||||
/// that are still mapped to nothing.
|
||||
/// The target needs to provide a RegisterBankInfo and in particular
|
||||
/// override RegisterBankInfo::getInstrMapping.
|
||||
///
|
||||
/// Simplified algo:
|
||||
/// \code
|
||||
/// RBI = MF.subtarget.getRegBankInfo()
|
||||
/// MIRBuilder.setMF(MF)
|
||||
/// for each bb in MF
|
||||
/// for each inst in bb
|
||||
/// MIRBuilder.setInstr(inst)
|
||||
/// MappingCosts = RBI.getMapping(inst);
|
||||
/// Idx = findIdxOfMinCost(MappingCosts)
|
||||
/// CurRegBank = MappingCosts[Idx].RegBank
|
||||
/// MRI.setRegBank(inst.getOperand(0).getReg(), CurRegBank)
|
||||
/// for each argument in inst
|
||||
/// if (CurRegBank != argument.RegBank)
|
||||
/// ArgReg = argument.getReg()
|
||||
/// Tmp = MRI.createNewVirtual(MRI.getSize(ArgReg), CurRegBank)
|
||||
/// MIRBuilder.buildInstr(COPY, Tmp, ArgReg)
|
||||
/// inst.getOperand(argument.getOperandNo()).setReg(Tmp)
|
||||
/// \endcode
|
||||
bool runOnMachineFunction(MachineFunction &MF) override;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_GLOBALISEL_REGBANKSELECT_H
|
||||
98
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/RegisterBank.h
vendored
Normal file
98
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/RegisterBank.h
vendored
Normal file
@@ -0,0 +1,98 @@
|
||||
//==-- llvm/CodeGen/GlobalISel/RegisterBank.h - Register Bank ----*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
/// \file This file declares the API of register banks.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_REGISTERBANK_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_REGISTERBANK_H
|
||||
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
|
||||
namespace llvm {
|
||||
// Forward declarations.
|
||||
class RegisterBankInfo;
|
||||
class raw_ostream;
|
||||
class TargetRegisterClass;
|
||||
class TargetRegisterInfo;
|
||||
|
||||
/// This class implements the register bank concept.
|
||||
/// Two instances of RegisterBank must have different ID.
|
||||
/// This property is enforced by the RegisterBankInfo class.
|
||||
class RegisterBank {
|
||||
private:
|
||||
unsigned ID;
|
||||
const char *Name;
|
||||
unsigned Size;
|
||||
BitVector ContainedRegClasses;
|
||||
|
||||
/// Sentinel value used to recognize register bank not properly
|
||||
/// initialized yet.
|
||||
static const unsigned InvalidID;
|
||||
|
||||
/// Only the RegisterBankInfo can initialize RegisterBank properly.
|
||||
friend RegisterBankInfo;
|
||||
|
||||
public:
|
||||
RegisterBank(unsigned ID, const char *Name, unsigned Size,
|
||||
const uint32_t *CoveredClasses, unsigned NumRegClasses);
|
||||
|
||||
/// Get the identifier of this register bank.
|
||||
unsigned getID() const { return ID; }
|
||||
|
||||
/// Get a user friendly name of this register bank.
|
||||
/// Should be used only for debugging purposes.
|
||||
const char *getName() const { return Name; }
|
||||
|
||||
/// Get the maximal size in bits that fits in this register bank.
|
||||
unsigned getSize() const { return Size; }
|
||||
|
||||
/// Check whether this instance is ready to be used.
|
||||
bool isValid() const;
|
||||
|
||||
/// Check if this register bank is valid. In other words,
|
||||
/// if it has been properly constructed.
|
||||
///
|
||||
/// \note This method does not check anything when assertions are disabled.
|
||||
///
|
||||
/// \return True is the check was successful.
|
||||
bool verify(const TargetRegisterInfo &TRI) const;
|
||||
|
||||
/// Check whether this register bank covers \p RC.
|
||||
/// In other words, check if this register bank fully covers
|
||||
/// the registers that \p RC contains.
|
||||
/// \pre isValid()
|
||||
bool covers(const TargetRegisterClass &RC) const;
|
||||
|
||||
/// Check whether \p OtherRB is the same as this.
|
||||
bool operator==(const RegisterBank &OtherRB) const;
|
||||
bool operator!=(const RegisterBank &OtherRB) const {
|
||||
return !this->operator==(OtherRB);
|
||||
}
|
||||
|
||||
/// Dump the register mask on dbgs() stream.
|
||||
/// The dump is verbose.
|
||||
void dump(const TargetRegisterInfo *TRI = nullptr) const;
|
||||
|
||||
/// Print the register mask on OS.
|
||||
/// If IsForDebug is false, then only the name of the register bank
|
||||
/// is printed. Otherwise, all the fields are printing.
|
||||
/// TRI is then used to print the name of the register classes that
|
||||
/// this register bank covers.
|
||||
void print(raw_ostream &OS, bool IsForDebug = false,
|
||||
const TargetRegisterInfo *TRI = nullptr) const;
|
||||
};
|
||||
|
||||
inline raw_ostream &operator<<(raw_ostream &OS, const RegisterBank &RegBank) {
|
||||
RegBank.print(OS);
|
||||
return OS;
|
||||
}
|
||||
} // End namespace llvm.
|
||||
|
||||
#endif
|
||||
775
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/RegisterBankInfo.h
vendored
Normal file
775
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/RegisterBankInfo.h
vendored
Normal file
@@ -0,0 +1,775 @@
|
||||
//===- llvm/CodeGen/GlobalISel/RegisterBankInfo.h ---------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
/// \file This file declares the API for the register bank info.
|
||||
/// This API is responsible for handling the register banks.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_REGISTERBANKINFO_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_REGISTERBANKINFO_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/Hashing.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/iterator_range.h"
|
||||
#include "llvm/CodeGen/Register.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include "llvm/Support/LowLevelTypeImpl.h"
|
||||
#include <cassert>
|
||||
#include <initializer_list>
|
||||
#include <memory>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MachineInstr;
|
||||
class MachineRegisterInfo;
|
||||
class raw_ostream;
|
||||
class RegisterBank;
|
||||
class TargetInstrInfo;
|
||||
class TargetRegisterClass;
|
||||
class TargetRegisterInfo;
|
||||
|
||||
/// Holds all the information related to register banks.
|
||||
class RegisterBankInfo {
|
||||
public:
|
||||
/// Helper struct that represents how a value is partially mapped
|
||||
/// into a register.
|
||||
/// The StartIdx and Length represent what region of the original
|
||||
/// value this partial mapping covers.
|
||||
/// This can be represented as a Mask of contiguous bit starting
|
||||
/// at StartIdx bit and spanning Length bits.
|
||||
/// StartIdx is the number of bits from the less significant bits.
|
||||
struct PartialMapping {
|
||||
/// Number of bits at which this partial mapping starts in the
|
||||
/// original value. The bits are counted from less significant
|
||||
/// bits to most significant bits.
|
||||
unsigned StartIdx;
|
||||
|
||||
/// Length of this mapping in bits. This is how many bits this
|
||||
/// partial mapping covers in the original value:
|
||||
/// from StartIdx to StartIdx + Length -1.
|
||||
unsigned Length;
|
||||
|
||||
/// Register bank where the partial value lives.
|
||||
const RegisterBank *RegBank;
|
||||
|
||||
PartialMapping() = default;
|
||||
|
||||
/// Provide a shortcut for quickly building PartialMapping.
|
||||
PartialMapping(unsigned StartIdx, unsigned Length,
|
||||
const RegisterBank &RegBank)
|
||||
: StartIdx(StartIdx), Length(Length), RegBank(&RegBank) {}
|
||||
|
||||
/// \return the index of in the original value of the most
|
||||
/// significant bit that this partial mapping covers.
|
||||
unsigned getHighBitIdx() const { return StartIdx + Length - 1; }
|
||||
|
||||
/// Print this partial mapping on dbgs() stream.
|
||||
void dump() const;
|
||||
|
||||
/// Print this partial mapping on \p OS;
|
||||
void print(raw_ostream &OS) const;
|
||||
|
||||
/// Check that the Mask is compatible with the RegBank.
|
||||
/// Indeed, if the RegBank cannot accommodate the "active bits" of the mask,
|
||||
/// there is no way this mapping is valid.
|
||||
///
|
||||
/// \note This method does not check anything when assertions are disabled.
|
||||
///
|
||||
/// \return True is the check was successful.
|
||||
bool verify() const;
|
||||
};
|
||||
|
||||
/// Helper struct that represents how a value is mapped through
|
||||
/// different register banks.
|
||||
///
|
||||
/// \note: So far we do not have any users of the complex mappings
|
||||
/// (mappings with more than one partial mapping), but when we do,
|
||||
/// we would have needed to duplicate partial mappings.
|
||||
/// The alternative could be to use an array of pointers of partial
|
||||
/// mapping (i.e., PartialMapping **BreakDown) and duplicate the
|
||||
/// pointers instead.
|
||||
///
|
||||
/// E.g.,
|
||||
/// Let say we have a 32-bit add and a <2 x 32-bit> vadd. We
|
||||
/// can expand the
|
||||
/// <2 x 32-bit> add into 2 x 32-bit add.
|
||||
///
|
||||
/// Currently the TableGen-like file would look like:
|
||||
/// \code
|
||||
/// PartialMapping[] = {
|
||||
/// /*32-bit add*/ {0, 32, GPR}, // Scalar entry repeated for first
|
||||
/// // vec elt.
|
||||
/// /*2x32-bit add*/ {0, 32, GPR}, {32, 32, GPR},
|
||||
/// /*<2x32-bit> vadd*/ {0, 64, VPR}
|
||||
/// }; // PartialMapping duplicated.
|
||||
///
|
||||
/// ValueMapping[] {
|
||||
/// /*plain 32-bit add*/ {&PartialMapping[0], 1},
|
||||
/// /*expanded vadd on 2xadd*/ {&PartialMapping[1], 2},
|
||||
/// /*plain <2x32-bit> vadd*/ {&PartialMapping[3], 1}
|
||||
/// };
|
||||
/// \endcode
|
||||
///
|
||||
/// With the array of pointer, we would have:
|
||||
/// \code
|
||||
/// PartialMapping[] = {
|
||||
/// /*32-bit add lower */ { 0, 32, GPR},
|
||||
/// /*32-bit add upper */ {32, 32, GPR},
|
||||
/// /*<2x32-bit> vadd */ { 0, 64, VPR}
|
||||
/// }; // No more duplication.
|
||||
///
|
||||
/// BreakDowns[] = {
|
||||
/// /*AddBreakDown*/ &PartialMapping[0],
|
||||
/// /*2xAddBreakDown*/ &PartialMapping[0], &PartialMapping[1],
|
||||
/// /*VAddBreakDown*/ &PartialMapping[2]
|
||||
/// }; // Addresses of PartialMapping duplicated (smaller).
|
||||
///
|
||||
/// ValueMapping[] {
|
||||
/// /*plain 32-bit add*/ {&BreakDowns[0], 1},
|
||||
/// /*expanded vadd on 2xadd*/ {&BreakDowns[1], 2},
|
||||
/// /*plain <2x32-bit> vadd*/ {&BreakDowns[3], 1}
|
||||
/// };
|
||||
/// \endcode
|
||||
///
|
||||
/// Given that a PartialMapping is actually small, the code size
|
||||
/// impact is actually a degradation. Moreover the compile time will
|
||||
/// be hit by the additional indirection.
|
||||
/// If PartialMapping gets bigger we may reconsider.
|
||||
struct ValueMapping {
|
||||
/// How the value is broken down between the different register banks.
|
||||
const PartialMapping *BreakDown;
|
||||
|
||||
/// Number of partial mapping to break down this value.
|
||||
unsigned NumBreakDowns;
|
||||
|
||||
/// The default constructor creates an invalid (isValid() == false)
|
||||
/// instance.
|
||||
ValueMapping() : ValueMapping(nullptr, 0) {}
|
||||
|
||||
/// Initialize a ValueMapping with the given parameter.
|
||||
/// \p BreakDown needs to have a life time at least as long
|
||||
/// as this instance.
|
||||
ValueMapping(const PartialMapping *BreakDown, unsigned NumBreakDowns)
|
||||
: BreakDown(BreakDown), NumBreakDowns(NumBreakDowns) {}
|
||||
|
||||
/// Iterators through the PartialMappings.
|
||||
const PartialMapping *begin() const { return BreakDown; }
|
||||
const PartialMapping *end() const { return BreakDown + NumBreakDowns; }
|
||||
|
||||
/// \return true if all partial mappings are the same size and register
|
||||
/// bank.
|
||||
bool partsAllUniform() const;
|
||||
|
||||
/// Check if this ValueMapping is valid.
|
||||
bool isValid() const { return BreakDown && NumBreakDowns; }
|
||||
|
||||
/// Verify that this mapping makes sense for a value of
|
||||
/// \p MeaningfulBitWidth.
|
||||
/// \note This method does not check anything when assertions are disabled.
|
||||
///
|
||||
/// \return True is the check was successful.
|
||||
bool verify(unsigned MeaningfulBitWidth) const;
|
||||
|
||||
/// Print this on dbgs() stream.
|
||||
void dump() const;
|
||||
|
||||
/// Print this on \p OS;
|
||||
void print(raw_ostream &OS) const;
|
||||
};
|
||||
|
||||
/// Helper class that represents how the value of an instruction may be
|
||||
/// mapped and what is the related cost of such mapping.
|
||||
class InstructionMapping {
|
||||
/// Identifier of the mapping.
|
||||
/// This is used to communicate between the target and the optimizers
|
||||
/// which mapping should be realized.
|
||||
unsigned ID = InvalidMappingID;
|
||||
|
||||
/// Cost of this mapping.
|
||||
unsigned Cost = 0;
|
||||
|
||||
/// Mapping of all the operands.
|
||||
const ValueMapping *OperandsMapping = nullptr;
|
||||
|
||||
/// Number of operands.
|
||||
unsigned NumOperands = 0;
|
||||
|
||||
const ValueMapping &getOperandMapping(unsigned i) {
|
||||
assert(i < getNumOperands() && "Out of bound operand");
|
||||
return OperandsMapping[i];
|
||||
}
|
||||
|
||||
public:
|
||||
/// Constructor for the mapping of an instruction.
|
||||
/// \p NumOperands must be equal to number of all the operands of
|
||||
/// the related instruction.
|
||||
/// The rationale is that it is more efficient for the optimizers
|
||||
/// to be able to assume that the mapping of the ith operand is
|
||||
/// at the index i.
|
||||
InstructionMapping(unsigned ID, unsigned Cost,
|
||||
const ValueMapping *OperandsMapping,
|
||||
unsigned NumOperands)
|
||||
: ID(ID), Cost(Cost), OperandsMapping(OperandsMapping),
|
||||
NumOperands(NumOperands) {
|
||||
}
|
||||
|
||||
/// Default constructor.
|
||||
/// Use this constructor to express that the mapping is invalid.
|
||||
InstructionMapping() = default;
|
||||
|
||||
/// Get the cost.
|
||||
unsigned getCost() const { return Cost; }
|
||||
|
||||
/// Get the ID.
|
||||
unsigned getID() const { return ID; }
|
||||
|
||||
/// Get the number of operands.
|
||||
unsigned getNumOperands() const { return NumOperands; }
|
||||
|
||||
/// Get the value mapping of the ith operand.
|
||||
/// \pre The mapping for the ith operand has been set.
|
||||
/// \pre The ith operand is a register.
|
||||
const ValueMapping &getOperandMapping(unsigned i) const {
|
||||
const ValueMapping &ValMapping =
|
||||
const_cast<InstructionMapping *>(this)->getOperandMapping(i);
|
||||
return ValMapping;
|
||||
}
|
||||
|
||||
/// Set the mapping for all the operands.
|
||||
/// In other words, OpdsMapping should hold at least getNumOperands
|
||||
/// ValueMapping.
|
||||
void setOperandsMapping(const ValueMapping *OpdsMapping) {
|
||||
OperandsMapping = OpdsMapping;
|
||||
}
|
||||
|
||||
/// Check whether this object is valid.
|
||||
/// This is a lightweight check for obvious wrong instance.
|
||||
bool isValid() const {
|
||||
return getID() != InvalidMappingID && OperandsMapping;
|
||||
}
|
||||
|
||||
/// Verify that this mapping makes sense for \p MI.
|
||||
/// \pre \p MI must be connected to a MachineFunction.
|
||||
///
|
||||
/// \note This method does not check anything when assertions are disabled.
|
||||
///
|
||||
/// \return True is the check was successful.
|
||||
bool verify(const MachineInstr &MI) const;
|
||||
|
||||
/// Print this on dbgs() stream.
|
||||
void dump() const;
|
||||
|
||||
/// Print this on \p OS;
|
||||
void print(raw_ostream &OS) const;
|
||||
};
|
||||
|
||||
/// Convenient type to represent the alternatives for mapping an
|
||||
/// instruction.
|
||||
/// \todo When we move to TableGen this should be an array ref.
|
||||
using InstructionMappings = SmallVector<const InstructionMapping *, 4>;
|
||||
|
||||
/// Helper class used to get/create the virtual registers that will be used
|
||||
/// to replace the MachineOperand when applying a mapping.
|
||||
class OperandsMapper {
|
||||
/// The OpIdx-th cell contains the index in NewVRegs where the VRegs of the
|
||||
/// OpIdx-th operand starts. -1 means we do not have such mapping yet.
|
||||
/// Note: We use a SmallVector to avoid heap allocation for most cases.
|
||||
SmallVector<int, 8> OpToNewVRegIdx;
|
||||
|
||||
/// Hold the registers that will be used to map MI with InstrMapping.
|
||||
SmallVector<Register, 8> NewVRegs;
|
||||
|
||||
/// Current MachineRegisterInfo, used to create new virtual registers.
|
||||
MachineRegisterInfo &MRI;
|
||||
|
||||
/// Instruction being remapped.
|
||||
MachineInstr &MI;
|
||||
|
||||
/// New mapping of the instruction.
|
||||
const InstructionMapping &InstrMapping;
|
||||
|
||||
/// Constant value identifying that the index in OpToNewVRegIdx
|
||||
/// for an operand has not been set yet.
|
||||
static const int DontKnowIdx;
|
||||
|
||||
/// Get the range in NewVRegs to store all the partial
|
||||
/// values for the \p OpIdx-th operand.
|
||||
///
|
||||
/// \return The iterator range for the space created.
|
||||
//
|
||||
/// \pre getMI().getOperand(OpIdx).isReg()
|
||||
iterator_range<SmallVectorImpl<Register>::iterator>
|
||||
getVRegsMem(unsigned OpIdx);
|
||||
|
||||
/// Get the end iterator for a range starting at \p StartIdx and
|
||||
/// spannig \p NumVal in NewVRegs.
|
||||
/// \pre StartIdx + NumVal <= NewVRegs.size()
|
||||
SmallVectorImpl<Register>::const_iterator
|
||||
getNewVRegsEnd(unsigned StartIdx, unsigned NumVal) const;
|
||||
SmallVectorImpl<Register>::iterator getNewVRegsEnd(unsigned StartIdx,
|
||||
unsigned NumVal);
|
||||
|
||||
public:
|
||||
/// Create an OperandsMapper that will hold the information to apply \p
|
||||
/// InstrMapping to \p MI.
|
||||
/// \pre InstrMapping.verify(MI)
|
||||
OperandsMapper(MachineInstr &MI, const InstructionMapping &InstrMapping,
|
||||
MachineRegisterInfo &MRI);
|
||||
|
||||
/// \name Getters.
|
||||
/// @{
|
||||
/// The MachineInstr being remapped.
|
||||
MachineInstr &getMI() const { return MI; }
|
||||
|
||||
/// The final mapping of the instruction.
|
||||
const InstructionMapping &getInstrMapping() const { return InstrMapping; }
|
||||
|
||||
/// The MachineRegisterInfo we used to realize the mapping.
|
||||
MachineRegisterInfo &getMRI() const { return MRI; }
|
||||
/// @}
|
||||
|
||||
/// Create as many new virtual registers as needed for the mapping of the \p
|
||||
/// OpIdx-th operand.
|
||||
/// The number of registers is determined by the number of breakdown for the
|
||||
/// related operand in the instruction mapping.
|
||||
/// The type of the new registers is a plain scalar of the right size.
|
||||
/// The proper type is expected to be set when the mapping is applied to
|
||||
/// the instruction(s) that realizes the mapping.
|
||||
///
|
||||
/// \pre getMI().getOperand(OpIdx).isReg()
|
||||
///
|
||||
/// \post All the partial mapping of the \p OpIdx-th operand have been
|
||||
/// assigned a new virtual register.
|
||||
void createVRegs(unsigned OpIdx);
|
||||
|
||||
/// Set the virtual register of the \p PartialMapIdx-th partial mapping of
|
||||
/// the OpIdx-th operand to \p NewVReg.
|
||||
///
|
||||
/// \pre getMI().getOperand(OpIdx).isReg()
|
||||
/// \pre getInstrMapping().getOperandMapping(OpIdx).BreakDown.size() >
|
||||
/// PartialMapIdx
|
||||
/// \pre NewReg != 0
|
||||
///
|
||||
/// \post the \p PartialMapIdx-th register of the value mapping of the \p
|
||||
/// OpIdx-th operand has been set.
|
||||
void setVRegs(unsigned OpIdx, unsigned PartialMapIdx, Register NewVReg);
|
||||
|
||||
/// Get all the virtual registers required to map the \p OpIdx-th operand of
|
||||
/// the instruction.
|
||||
///
|
||||
/// This return an empty range when createVRegs or setVRegs has not been
|
||||
/// called.
|
||||
/// The iterator may be invalidated by a call to setVRegs or createVRegs.
|
||||
///
|
||||
/// When \p ForDebug is true, we will not check that the list of new virtual
|
||||
/// registers does not contain uninitialized values.
|
||||
///
|
||||
/// \pre getMI().getOperand(OpIdx).isReg()
|
||||
/// \pre ForDebug || All partial mappings have been set a register
|
||||
iterator_range<SmallVectorImpl<Register>::const_iterator>
|
||||
getVRegs(unsigned OpIdx, bool ForDebug = false) const;
|
||||
|
||||
/// Print this operands mapper on dbgs() stream.
|
||||
void dump() const;
|
||||
|
||||
/// Print this operands mapper on \p OS stream.
|
||||
void print(raw_ostream &OS, bool ForDebug = false) const;
|
||||
};
|
||||
|
||||
protected:
|
||||
/// Hold the set of supported register banks.
|
||||
RegisterBank **RegBanks;
|
||||
|
||||
/// Total number of register banks.
|
||||
unsigned NumRegBanks;
|
||||
|
||||
/// Keep dynamically allocated PartialMapping in a separate map.
|
||||
/// This shouldn't be needed when everything gets TableGen'ed.
|
||||
mutable DenseMap<unsigned, std::unique_ptr<const PartialMapping>>
|
||||
MapOfPartialMappings;
|
||||
|
||||
/// Keep dynamically allocated ValueMapping in a separate map.
|
||||
/// This shouldn't be needed when everything gets TableGen'ed.
|
||||
mutable DenseMap<unsigned, std::unique_ptr<const ValueMapping>>
|
||||
MapOfValueMappings;
|
||||
|
||||
/// Keep dynamically allocated array of ValueMapping in a separate map.
|
||||
/// This shouldn't be needed when everything gets TableGen'ed.
|
||||
mutable DenseMap<unsigned, std::unique_ptr<ValueMapping[]>>
|
||||
MapOfOperandsMappings;
|
||||
|
||||
/// Keep dynamically allocated InstructionMapping in a separate map.
|
||||
/// This shouldn't be needed when everything gets TableGen'ed.
|
||||
mutable DenseMap<unsigned, std::unique_ptr<const InstructionMapping>>
|
||||
MapOfInstructionMappings;
|
||||
|
||||
/// Getting the minimal register class of a physreg is expensive.
|
||||
/// Cache this information as we get it.
|
||||
mutable DenseMap<unsigned, const TargetRegisterClass *> PhysRegMinimalRCs;
|
||||
|
||||
/// Create a RegisterBankInfo that can accommodate up to \p NumRegBanks
|
||||
/// RegisterBank instances.
|
||||
RegisterBankInfo(RegisterBank **RegBanks, unsigned NumRegBanks);
|
||||
|
||||
/// This constructor is meaningless.
|
||||
/// It just provides a default constructor that can be used at link time
|
||||
/// when GlobalISel is not built.
|
||||
/// That way, targets can still inherit from this class without doing
|
||||
/// crazy gymnastic to avoid link time failures.
|
||||
/// \note That works because the constructor is inlined.
|
||||
RegisterBankInfo() {
|
||||
llvm_unreachable("This constructor should not be executed");
|
||||
}
|
||||
|
||||
/// Get the register bank identified by \p ID.
|
||||
RegisterBank &getRegBank(unsigned ID) {
|
||||
assert(ID < getNumRegBanks() && "Accessing an unknown register bank");
|
||||
return *RegBanks[ID];
|
||||
}
|
||||
|
||||
/// Get the MinimalPhysRegClass for Reg.
|
||||
/// \pre Reg is a physical register.
|
||||
const TargetRegisterClass &
|
||||
getMinimalPhysRegClass(Register Reg, const TargetRegisterInfo &TRI) const;
|
||||
|
||||
/// Try to get the mapping of \p MI.
|
||||
/// See getInstrMapping for more details on what a mapping represents.
|
||||
///
|
||||
/// Unlike getInstrMapping the returned InstructionMapping may be invalid
|
||||
/// (isValid() == false).
|
||||
/// This means that the target independent code is not smart enough
|
||||
/// to get the mapping of \p MI and thus, the target has to provide the
|
||||
/// information for \p MI.
|
||||
///
|
||||
/// This implementation is able to get the mapping of:
|
||||
/// - Target specific instructions by looking at the encoding constraints.
|
||||
/// - Any instruction if all the register operands have already been assigned
|
||||
/// a register, a register class, or a register bank.
|
||||
/// - Copies and phis if at least one of the operands has been assigned a
|
||||
/// register, a register class, or a register bank.
|
||||
/// In other words, this method will likely fail to find a mapping for
|
||||
/// any generic opcode that has not been lowered by target specific code.
|
||||
const InstructionMapping &getInstrMappingImpl(const MachineInstr &MI) const;
|
||||
|
||||
/// Get the uniquely generated PartialMapping for the
|
||||
/// given arguments.
|
||||
const PartialMapping &getPartialMapping(unsigned StartIdx, unsigned Length,
|
||||
const RegisterBank &RegBank) const;
|
||||
|
||||
/// \name Methods to get a uniquely generated ValueMapping.
|
||||
/// @{
|
||||
|
||||
/// The most common ValueMapping consists of a single PartialMapping.
|
||||
/// Feature a method for that.
|
||||
const ValueMapping &getValueMapping(unsigned StartIdx, unsigned Length,
|
||||
const RegisterBank &RegBank) const;
|
||||
|
||||
/// Get the ValueMapping for the given arguments.
|
||||
const ValueMapping &getValueMapping(const PartialMapping *BreakDown,
|
||||
unsigned NumBreakDowns) const;
|
||||
/// @}
|
||||
|
||||
/// \name Methods to get a uniquely generated array of ValueMapping.
|
||||
/// @{
|
||||
|
||||
/// Get the uniquely generated array of ValueMapping for the
|
||||
/// elements of between \p Begin and \p End.
|
||||
///
|
||||
/// Elements that are nullptr will be replaced by
|
||||
/// invalid ValueMapping (ValueMapping::isValid == false).
|
||||
///
|
||||
/// \pre The pointers on ValueMapping between \p Begin and \p End
|
||||
/// must uniquely identify a ValueMapping. Otherwise, there is no
|
||||
/// guarantee that the return instance will be unique, i.e., another
|
||||
/// OperandsMapping could have the same content.
|
||||
template <typename Iterator>
|
||||
const ValueMapping *getOperandsMapping(Iterator Begin, Iterator End) const;
|
||||
|
||||
/// Get the uniquely generated array of ValueMapping for the
|
||||
/// elements of \p OpdsMapping.
|
||||
///
|
||||
/// Elements of \p OpdsMapping that are nullptr will be replaced by
|
||||
/// invalid ValueMapping (ValueMapping::isValid == false).
|
||||
const ValueMapping *getOperandsMapping(
|
||||
const SmallVectorImpl<const ValueMapping *> &OpdsMapping) const;
|
||||
|
||||
/// Get the uniquely generated array of ValueMapping for the
|
||||
/// given arguments.
|
||||
///
|
||||
/// Arguments that are nullptr will be replaced by invalid
|
||||
/// ValueMapping (ValueMapping::isValid == false).
|
||||
const ValueMapping *getOperandsMapping(
|
||||
std::initializer_list<const ValueMapping *> OpdsMapping) const;
|
||||
/// @}
|
||||
|
||||
/// \name Methods to get a uniquely generated InstructionMapping.
|
||||
/// @{
|
||||
|
||||
private:
|
||||
/// Method to get a uniquely generated InstructionMapping.
|
||||
const InstructionMapping &
|
||||
getInstructionMappingImpl(bool IsInvalid, unsigned ID = InvalidMappingID,
|
||||
unsigned Cost = 0,
|
||||
const ValueMapping *OperandsMapping = nullptr,
|
||||
unsigned NumOperands = 0) const;
|
||||
|
||||
public:
|
||||
/// Method to get a uniquely generated InstructionMapping.
|
||||
const InstructionMapping &
|
||||
getInstructionMapping(unsigned ID, unsigned Cost,
|
||||
const ValueMapping *OperandsMapping,
|
||||
unsigned NumOperands) const {
|
||||
return getInstructionMappingImpl(/*IsInvalid*/ false, ID, Cost,
|
||||
OperandsMapping, NumOperands);
|
||||
}
|
||||
|
||||
/// Method to get a uniquely generated invalid InstructionMapping.
|
||||
const InstructionMapping &getInvalidInstructionMapping() const {
|
||||
return getInstructionMappingImpl(/*IsInvalid*/ true);
|
||||
}
|
||||
/// @}
|
||||
|
||||
/// Get the register bank for the \p OpIdx-th operand of \p MI form
|
||||
/// the encoding constraints, if any.
|
||||
///
|
||||
/// \return A register bank that covers the register class of the
|
||||
/// related encoding constraints or nullptr if \p MI did not provide
|
||||
/// enough information to deduce it.
|
||||
const RegisterBank *
|
||||
getRegBankFromConstraints(const MachineInstr &MI, unsigned OpIdx,
|
||||
const TargetInstrInfo &TII,
|
||||
const MachineRegisterInfo &MRI) const;
|
||||
|
||||
/// Helper method to apply something that is like the default mapping.
|
||||
/// Basically, that means that \p OpdMapper.getMI() is left untouched
|
||||
/// aside from the reassignment of the register operand that have been
|
||||
/// remapped.
|
||||
///
|
||||
/// The type of all the new registers that have been created by the
|
||||
/// mapper are properly remapped to the type of the original registers
|
||||
/// they replace. In other words, the semantic of the instruction does
|
||||
/// not change, only the register banks.
|
||||
///
|
||||
/// If the mapping of one of the operand spans several registers, this
|
||||
/// method will abort as this is not like a default mapping anymore.
|
||||
///
|
||||
/// \pre For OpIdx in {0..\p OpdMapper.getMI().getNumOperands())
|
||||
/// the range OpdMapper.getVRegs(OpIdx) is empty or of size 1.
|
||||
static void applyDefaultMapping(const OperandsMapper &OpdMapper);
|
||||
|
||||
/// See ::applyMapping.
|
||||
virtual void applyMappingImpl(const OperandsMapper &OpdMapper) const {
|
||||
llvm_unreachable("The target has to implement that part");
|
||||
}
|
||||
|
||||
public:
|
||||
virtual ~RegisterBankInfo() = default;
|
||||
|
||||
/// Get the register bank identified by \p ID.
|
||||
const RegisterBank &getRegBank(unsigned ID) const {
|
||||
return const_cast<RegisterBankInfo *>(this)->getRegBank(ID);
|
||||
}
|
||||
|
||||
/// Get the register bank of \p Reg.
|
||||
/// If Reg has not been assigned a register, a register class,
|
||||
/// or a register bank, then this returns nullptr.
|
||||
///
|
||||
/// \pre Reg != 0 (NoRegister)
|
||||
const RegisterBank *getRegBank(Register Reg, const MachineRegisterInfo &MRI,
|
||||
const TargetRegisterInfo &TRI) const;
|
||||
|
||||
/// Get the total number of register banks.
|
||||
unsigned getNumRegBanks() const { return NumRegBanks; }
|
||||
|
||||
/// Get a register bank that covers \p RC.
|
||||
///
|
||||
/// \pre \p RC is a user-defined register class (as opposed as one
|
||||
/// generated by TableGen).
|
||||
///
|
||||
/// \note The mapping RC -> RegBank could be built while adding the
|
||||
/// coverage for the register banks. However, we do not do it, because,
|
||||
/// at least for now, we only need this information for register classes
|
||||
/// that are used in the description of instruction. In other words,
|
||||
/// there are just a handful of them and we do not want to waste space.
|
||||
///
|
||||
/// \todo This should be TableGen'ed.
|
||||
virtual const RegisterBank &
|
||||
getRegBankFromRegClass(const TargetRegisterClass &RC, LLT Ty) const {
|
||||
llvm_unreachable("The target must override this method");
|
||||
}
|
||||
|
||||
/// Get the cost of a copy from \p B to \p A, or put differently,
|
||||
/// get the cost of A = COPY B. Since register banks may cover
|
||||
/// different size, \p Size specifies what will be the size in bits
|
||||
/// that will be copied around.
|
||||
///
|
||||
/// \note Since this is a copy, both registers have the same size.
|
||||
virtual unsigned copyCost(const RegisterBank &A, const RegisterBank &B,
|
||||
unsigned Size) const {
|
||||
// Optimistically assume that copies are coalesced. I.e., when
|
||||
// they are on the same bank, they are free.
|
||||
// Otherwise assume a non-zero cost of 1. The targets are supposed
|
||||
// to override that properly anyway if they care.
|
||||
return &A != &B;
|
||||
}
|
||||
|
||||
/// \returns true if emitting a copy from \p Src to \p Dst is impossible.
|
||||
bool cannotCopy(const RegisterBank &Dst, const RegisterBank &Src,
|
||||
unsigned Size) const {
|
||||
return copyCost(Dst, Src, Size) == std::numeric_limits<unsigned>::max();
|
||||
}
|
||||
|
||||
/// Get the cost of using \p ValMapping to decompose a register. This is
|
||||
/// similar to ::copyCost, except for cases where multiple copy-like
|
||||
/// operations need to be inserted. If the register is used as a source
|
||||
/// operand and already has a bank assigned, \p CurBank is non-null.
|
||||
virtual unsigned getBreakDownCost(const ValueMapping &ValMapping,
|
||||
const RegisterBank *CurBank = nullptr) const {
|
||||
return std::numeric_limits<unsigned>::max();
|
||||
}
|
||||
|
||||
/// Constrain the (possibly generic) virtual register \p Reg to \p RC.
|
||||
///
|
||||
/// \pre \p Reg is a virtual register that either has a bank or a class.
|
||||
/// \returns The constrained register class, or nullptr if there is none.
|
||||
/// \note This is a generic variant of MachineRegisterInfo::constrainRegClass
|
||||
/// \note Use MachineRegisterInfo::constrainRegAttrs instead for any non-isel
|
||||
/// purpose, including non-select passes of GlobalISel
|
||||
static const TargetRegisterClass *
|
||||
constrainGenericRegister(Register Reg, const TargetRegisterClass &RC,
|
||||
MachineRegisterInfo &MRI);
|
||||
|
||||
/// Identifier used when the related instruction mapping instance
|
||||
/// is generated by target independent code.
|
||||
/// Make sure not to use that identifier to avoid possible collision.
|
||||
static const unsigned DefaultMappingID;
|
||||
|
||||
/// Identifier used when the related instruction mapping instance
|
||||
/// is generated by the default constructor.
|
||||
/// Make sure not to use that identifier.
|
||||
static const unsigned InvalidMappingID;
|
||||
|
||||
/// Get the mapping of the different operands of \p MI
|
||||
/// on the register bank.
|
||||
/// This mapping should be the direct translation of \p MI.
|
||||
/// In other words, when \p MI is mapped with the returned mapping,
|
||||
/// only the register banks of the operands of \p MI need to be updated.
|
||||
/// In particular, neither the opcode nor the type of \p MI needs to be
|
||||
/// updated for this direct mapping.
|
||||
///
|
||||
/// The target independent implementation gives a mapping based on
|
||||
/// the register classes for the target specific opcode.
|
||||
/// It uses the ID RegisterBankInfo::DefaultMappingID for that mapping.
|
||||
/// Make sure you do not use that ID for the alternative mapping
|
||||
/// for MI. See getInstrAlternativeMappings for the alternative
|
||||
/// mappings.
|
||||
///
|
||||
/// For instance, if \p MI is a vector add, the mapping should
|
||||
/// not be a scalarization of the add.
|
||||
///
|
||||
/// \post returnedVal.verify(MI).
|
||||
///
|
||||
/// \note If returnedVal does not verify MI, this would probably mean
|
||||
/// that the target does not support that instruction.
|
||||
virtual const InstructionMapping &
|
||||
getInstrMapping(const MachineInstr &MI) const;
|
||||
|
||||
/// Get the alternative mappings for \p MI.
|
||||
/// Alternative in the sense different from getInstrMapping.
|
||||
virtual InstructionMappings
|
||||
getInstrAlternativeMappings(const MachineInstr &MI) const;
|
||||
|
||||
/// Get the possible mapping for \p MI.
|
||||
/// A mapping defines where the different operands may live and at what cost.
|
||||
/// For instance, let us consider:
|
||||
/// v0(16) = G_ADD <2 x i8> v1, v2
|
||||
/// The possible mapping could be:
|
||||
///
|
||||
/// {/*ID*/VectorAdd, /*Cost*/1, /*v0*/{(0xFFFF, VPR)}, /*v1*/{(0xFFFF, VPR)},
|
||||
/// /*v2*/{(0xFFFF, VPR)}}
|
||||
/// {/*ID*/ScalarAddx2, /*Cost*/2, /*v0*/{(0x00FF, GPR),(0xFF00, GPR)},
|
||||
/// /*v1*/{(0x00FF, GPR),(0xFF00, GPR)},
|
||||
/// /*v2*/{(0x00FF, GPR),(0xFF00, GPR)}}
|
||||
///
|
||||
/// \note The first alternative of the returned mapping should be the
|
||||
/// direct translation of \p MI current form.
|
||||
///
|
||||
/// \post !returnedVal.empty().
|
||||
InstructionMappings getInstrPossibleMappings(const MachineInstr &MI) const;
|
||||
|
||||
/// Apply \p OpdMapper.getInstrMapping() to \p OpdMapper.getMI().
|
||||
/// After this call \p OpdMapper.getMI() may not be valid anymore.
|
||||
/// \p OpdMapper.getInstrMapping().getID() carries the information of
|
||||
/// what has been chosen to map \p OpdMapper.getMI(). This ID is set
|
||||
/// by the various getInstrXXXMapping method.
|
||||
///
|
||||
/// Therefore, getting the mapping and applying it should be kept in
|
||||
/// sync.
|
||||
void applyMapping(const OperandsMapper &OpdMapper) const {
|
||||
// The only mapping we know how to handle is the default mapping.
|
||||
if (OpdMapper.getInstrMapping().getID() == DefaultMappingID)
|
||||
return applyDefaultMapping(OpdMapper);
|
||||
// For other mapping, the target needs to do the right thing.
|
||||
// If that means calling applyDefaultMapping, fine, but this
|
||||
// must be explicitly stated.
|
||||
applyMappingImpl(OpdMapper);
|
||||
}
|
||||
|
||||
/// Get the size in bits of \p Reg.
|
||||
/// Utility method to get the size of any registers. Unlike
|
||||
/// MachineRegisterInfo::getSize, the register does not need to be a
|
||||
/// virtual register.
|
||||
///
|
||||
/// \pre \p Reg != 0 (NoRegister).
|
||||
unsigned getSizeInBits(Register Reg, const MachineRegisterInfo &MRI,
|
||||
const TargetRegisterInfo &TRI) const;
|
||||
|
||||
/// Check that information hold by this instance make sense for the
|
||||
/// given \p TRI.
|
||||
///
|
||||
/// \note This method does not check anything when assertions are disabled.
|
||||
///
|
||||
/// \return True is the check was successful.
|
||||
bool verify(const TargetRegisterInfo &TRI) const;
|
||||
};
|
||||
|
||||
inline raw_ostream &
|
||||
operator<<(raw_ostream &OS,
|
||||
const RegisterBankInfo::PartialMapping &PartMapping) {
|
||||
PartMapping.print(OS);
|
||||
return OS;
|
||||
}
|
||||
|
||||
inline raw_ostream &
|
||||
operator<<(raw_ostream &OS, const RegisterBankInfo::ValueMapping &ValMapping) {
|
||||
ValMapping.print(OS);
|
||||
return OS;
|
||||
}
|
||||
|
||||
inline raw_ostream &
|
||||
operator<<(raw_ostream &OS,
|
||||
const RegisterBankInfo::InstructionMapping &InstrMapping) {
|
||||
InstrMapping.print(OS);
|
||||
return OS;
|
||||
}
|
||||
|
||||
inline raw_ostream &
|
||||
operator<<(raw_ostream &OS, const RegisterBankInfo::OperandsMapper &OpdMapper) {
|
||||
OpdMapper.print(OS, /*ForDebug*/ false);
|
||||
return OS;
|
||||
}
|
||||
|
||||
/// Hashing function for PartialMapping.
|
||||
/// It is required for the hashing of ValueMapping.
|
||||
hash_code hash_value(const RegisterBankInfo::PartialMapping &PartMapping);
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_GLOBALISEL_REGISTERBANKINFO_H
|
||||
474
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/Utils.h
vendored
Normal file
474
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/GlobalISel/Utils.h
vendored
Normal file
@@ -0,0 +1,474 @@
|
||||
//==-- llvm/CodeGen/GlobalISel/Utils.h ---------------------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
/// \file This file declares the API of helper functions used throughout the
|
||||
/// GlobalISel pipeline.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_GLOBALISEL_UTILS_H
|
||||
#define LLVM_CODEGEN_GLOBALISEL_UTILS_H
|
||||
|
||||
#include "GISelWorkList.h"
|
||||
#include "LostDebugLocObserver.h"
|
||||
#include "llvm/ADT/APFloat.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/Register.h"
|
||||
#include "llvm/Support/Alignment.h"
|
||||
#include "llvm/Support/LowLevelTypeImpl.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class AnalysisUsage;
|
||||
class BlockFrequencyInfo;
|
||||
class GISelKnownBits;
|
||||
class MachineFunction;
|
||||
class MachineInstr;
|
||||
class MachineOperand;
|
||||
class MachineOptimizationRemarkEmitter;
|
||||
class MachineOptimizationRemarkMissed;
|
||||
struct MachinePointerInfo;
|
||||
class MachineRegisterInfo;
|
||||
class MCInstrDesc;
|
||||
class ProfileSummaryInfo;
|
||||
class RegisterBankInfo;
|
||||
class TargetInstrInfo;
|
||||
class TargetLowering;
|
||||
class TargetPassConfig;
|
||||
class TargetRegisterInfo;
|
||||
class TargetRegisterClass;
|
||||
class ConstantFP;
|
||||
class APFloat;
|
||||
class MachineIRBuilder;
|
||||
|
||||
// Convenience macros for dealing with vector reduction opcodes.
|
||||
#define GISEL_VECREDUCE_CASES_ALL \
|
||||
case TargetOpcode::G_VECREDUCE_SEQ_FADD: \
|
||||
case TargetOpcode::G_VECREDUCE_SEQ_FMUL: \
|
||||
case TargetOpcode::G_VECREDUCE_FADD: \
|
||||
case TargetOpcode::G_VECREDUCE_FMUL: \
|
||||
case TargetOpcode::G_VECREDUCE_FMAX: \
|
||||
case TargetOpcode::G_VECREDUCE_FMIN: \
|
||||
case TargetOpcode::G_VECREDUCE_ADD: \
|
||||
case TargetOpcode::G_VECREDUCE_MUL: \
|
||||
case TargetOpcode::G_VECREDUCE_AND: \
|
||||
case TargetOpcode::G_VECREDUCE_OR: \
|
||||
case TargetOpcode::G_VECREDUCE_XOR: \
|
||||
case TargetOpcode::G_VECREDUCE_SMAX: \
|
||||
case TargetOpcode::G_VECREDUCE_SMIN: \
|
||||
case TargetOpcode::G_VECREDUCE_UMAX: \
|
||||
case TargetOpcode::G_VECREDUCE_UMIN:
|
||||
|
||||
#define GISEL_VECREDUCE_CASES_NONSEQ \
|
||||
case TargetOpcode::G_VECREDUCE_FADD: \
|
||||
case TargetOpcode::G_VECREDUCE_FMUL: \
|
||||
case TargetOpcode::G_VECREDUCE_FMAX: \
|
||||
case TargetOpcode::G_VECREDUCE_FMIN: \
|
||||
case TargetOpcode::G_VECREDUCE_ADD: \
|
||||
case TargetOpcode::G_VECREDUCE_MUL: \
|
||||
case TargetOpcode::G_VECREDUCE_AND: \
|
||||
case TargetOpcode::G_VECREDUCE_OR: \
|
||||
case TargetOpcode::G_VECREDUCE_XOR: \
|
||||
case TargetOpcode::G_VECREDUCE_SMAX: \
|
||||
case TargetOpcode::G_VECREDUCE_SMIN: \
|
||||
case TargetOpcode::G_VECREDUCE_UMAX: \
|
||||
case TargetOpcode::G_VECREDUCE_UMIN:
|
||||
|
||||
/// Try to constrain Reg to the specified register class. If this fails,
|
||||
/// create a new virtual register in the correct class.
|
||||
///
|
||||
/// \return The virtual register constrained to the right register class.
|
||||
Register constrainRegToClass(MachineRegisterInfo &MRI,
|
||||
const TargetInstrInfo &TII,
|
||||
const RegisterBankInfo &RBI, Register Reg,
|
||||
const TargetRegisterClass &RegClass);
|
||||
|
||||
/// Constrain the Register operand OpIdx, so that it is now constrained to the
|
||||
/// TargetRegisterClass passed as an argument (RegClass).
|
||||
/// If this fails, create a new virtual register in the correct class and insert
|
||||
/// a COPY before \p InsertPt if it is a use or after if it is a definition.
|
||||
/// In both cases, the function also updates the register of RegMo. The debug
|
||||
/// location of \p InsertPt is used for the new copy.
|
||||
///
|
||||
/// \return The virtual register constrained to the right register class.
|
||||
Register constrainOperandRegClass(const MachineFunction &MF,
|
||||
const TargetRegisterInfo &TRI,
|
||||
MachineRegisterInfo &MRI,
|
||||
const TargetInstrInfo &TII,
|
||||
const RegisterBankInfo &RBI,
|
||||
MachineInstr &InsertPt,
|
||||
const TargetRegisterClass &RegClass,
|
||||
MachineOperand &RegMO);
|
||||
|
||||
/// Try to constrain Reg so that it is usable by argument OpIdx of the provided
|
||||
/// MCInstrDesc \p II. If this fails, create a new virtual register in the
|
||||
/// correct class and insert a COPY before \p InsertPt if it is a use or after
|
||||
/// if it is a definition. In both cases, the function also updates the register
|
||||
/// of RegMo.
|
||||
/// This is equivalent to constrainOperandRegClass(..., RegClass, ...)
|
||||
/// with RegClass obtained from the MCInstrDesc. The debug location of \p
|
||||
/// InsertPt is used for the new copy.
|
||||
///
|
||||
/// \return The virtual register constrained to the right register class.
|
||||
Register constrainOperandRegClass(const MachineFunction &MF,
|
||||
const TargetRegisterInfo &TRI,
|
||||
MachineRegisterInfo &MRI,
|
||||
const TargetInstrInfo &TII,
|
||||
const RegisterBankInfo &RBI,
|
||||
MachineInstr &InsertPt, const MCInstrDesc &II,
|
||||
MachineOperand &RegMO, unsigned OpIdx);
|
||||
|
||||
/// Mutate the newly-selected instruction \p I to constrain its (possibly
|
||||
/// generic) virtual register operands to the instruction's register class.
|
||||
/// This could involve inserting COPYs before (for uses) or after (for defs).
|
||||
/// This requires the number of operands to match the instruction description.
|
||||
/// \returns whether operand regclass constraining succeeded.
|
||||
///
|
||||
// FIXME: Not all instructions have the same number of operands. We should
|
||||
// probably expose a constrain helper per operand and let the target selector
|
||||
// constrain individual registers, like fast-isel.
|
||||
bool constrainSelectedInstRegOperands(MachineInstr &I,
|
||||
const TargetInstrInfo &TII,
|
||||
const TargetRegisterInfo &TRI,
|
||||
const RegisterBankInfo &RBI);
|
||||
|
||||
/// Check if DstReg can be replaced with SrcReg depending on the register
|
||||
/// constraints.
|
||||
bool canReplaceReg(Register DstReg, Register SrcReg, MachineRegisterInfo &MRI);
|
||||
|
||||
/// Check whether an instruction \p MI is dead: it only defines dead virtual
|
||||
/// registers, and doesn't have other side effects.
|
||||
bool isTriviallyDead(const MachineInstr &MI, const MachineRegisterInfo &MRI);
|
||||
|
||||
/// Report an ISel error as a missed optimization remark to the LLVMContext's
|
||||
/// diagnostic stream. Set the FailedISel MachineFunction property.
|
||||
void reportGISelFailure(MachineFunction &MF, const TargetPassConfig &TPC,
|
||||
MachineOptimizationRemarkEmitter &MORE,
|
||||
MachineOptimizationRemarkMissed &R);
|
||||
|
||||
void reportGISelFailure(MachineFunction &MF, const TargetPassConfig &TPC,
|
||||
MachineOptimizationRemarkEmitter &MORE,
|
||||
const char *PassName, StringRef Msg,
|
||||
const MachineInstr &MI);
|
||||
|
||||
/// Report an ISel warning as a missed optimization remark to the LLVMContext's
|
||||
/// diagnostic stream.
|
||||
void reportGISelWarning(MachineFunction &MF, const TargetPassConfig &TPC,
|
||||
MachineOptimizationRemarkEmitter &MORE,
|
||||
MachineOptimizationRemarkMissed &R);
|
||||
|
||||
/// If \p VReg is defined by a G_CONSTANT, return the corresponding value.
|
||||
Optional<APInt> getIConstantVRegVal(Register VReg,
|
||||
const MachineRegisterInfo &MRI);
|
||||
|
||||
/// If \p VReg is defined by a G_CONSTANT fits in int64_t returns it.
|
||||
Optional<int64_t> getIConstantVRegSExtVal(Register VReg,
|
||||
const MachineRegisterInfo &MRI);
|
||||
|
||||
/// Simple struct used to hold a constant integer value and a virtual
|
||||
/// register.
|
||||
struct ValueAndVReg {
|
||||
APInt Value;
|
||||
Register VReg;
|
||||
};
|
||||
|
||||
/// If \p VReg is defined by a statically evaluable chain of instructions rooted
|
||||
/// on a G_CONSTANT returns its APInt value and def register.
|
||||
Optional<ValueAndVReg>
|
||||
getIConstantVRegValWithLookThrough(Register VReg,
|
||||
const MachineRegisterInfo &MRI,
|
||||
bool LookThroughInstrs = true);
|
||||
|
||||
/// If \p VReg is defined by a statically evaluable chain of instructions rooted
|
||||
/// on a G_CONSTANT or G_FCONSTANT returns its value as APInt and def register.
|
||||
Optional<ValueAndVReg> getAnyConstantVRegValWithLookThrough(
|
||||
Register VReg, const MachineRegisterInfo &MRI,
|
||||
bool LookThroughInstrs = true, bool LookThroughAnyExt = false);
|
||||
|
||||
struct FPValueAndVReg {
|
||||
APFloat Value;
|
||||
Register VReg;
|
||||
};
|
||||
|
||||
/// If \p VReg is defined by a statically evaluable chain of instructions rooted
|
||||
/// on a G_FCONSTANT returns its APFloat value and def register.
|
||||
Optional<FPValueAndVReg>
|
||||
getFConstantVRegValWithLookThrough(Register VReg,
|
||||
const MachineRegisterInfo &MRI,
|
||||
bool LookThroughInstrs = true);
|
||||
|
||||
const ConstantFP* getConstantFPVRegVal(Register VReg,
|
||||
const MachineRegisterInfo &MRI);
|
||||
|
||||
/// See if Reg is defined by an single def instruction that is
|
||||
/// Opcode. Also try to do trivial folding if it's a COPY with
|
||||
/// same types. Returns null otherwise.
|
||||
MachineInstr *getOpcodeDef(unsigned Opcode, Register Reg,
|
||||
const MachineRegisterInfo &MRI);
|
||||
|
||||
/// Simple struct used to hold a Register value and the instruction which
|
||||
/// defines it.
|
||||
struct DefinitionAndSourceRegister {
|
||||
MachineInstr *MI;
|
||||
Register Reg;
|
||||
};
|
||||
|
||||
/// Find the def instruction for \p Reg, and underlying value Register folding
|
||||
/// away any copies.
|
||||
///
|
||||
/// Also walks through hints such as G_ASSERT_ZEXT.
|
||||
Optional<DefinitionAndSourceRegister>
|
||||
getDefSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI);
|
||||
|
||||
/// Find the def instruction for \p Reg, folding away any trivial copies. May
|
||||
/// return nullptr if \p Reg is not a generic virtual register.
|
||||
///
|
||||
/// Also walks through hints such as G_ASSERT_ZEXT.
|
||||
MachineInstr *getDefIgnoringCopies(Register Reg,
|
||||
const MachineRegisterInfo &MRI);
|
||||
|
||||
/// Find the source register for \p Reg, folding away any trivial copies. It
|
||||
/// will be an output register of the instruction that getDefIgnoringCopies
|
||||
/// returns. May return an invalid register if \p Reg is not a generic virtual
|
||||
/// register.
|
||||
///
|
||||
/// Also walks through hints such as G_ASSERT_ZEXT.
|
||||
Register getSrcRegIgnoringCopies(Register Reg, const MachineRegisterInfo &MRI);
|
||||
|
||||
// Templated variant of getOpcodeDef returning a MachineInstr derived T.
|
||||
/// See if Reg is defined by an single def instruction of type T
|
||||
/// Also try to do trivial folding if it's a COPY with
|
||||
/// same types. Returns null otherwise.
|
||||
template <class T>
|
||||
T *getOpcodeDef(Register Reg, const MachineRegisterInfo &MRI) {
|
||||
MachineInstr *DefMI = getDefIgnoringCopies(Reg, MRI);
|
||||
return dyn_cast_or_null<T>(DefMI);
|
||||
}
|
||||
|
||||
/// Returns an APFloat from Val converted to the appropriate size.
|
||||
APFloat getAPFloatFromSize(double Val, unsigned Size);
|
||||
|
||||
/// Modify analysis usage so it preserves passes required for the SelectionDAG
|
||||
/// fallback.
|
||||
void getSelectionDAGFallbackAnalysisUsage(AnalysisUsage &AU);
|
||||
|
||||
Optional<APInt> ConstantFoldBinOp(unsigned Opcode, const Register Op1,
|
||||
const Register Op2,
|
||||
const MachineRegisterInfo &MRI);
|
||||
Optional<APFloat> ConstantFoldFPBinOp(unsigned Opcode, const Register Op1,
|
||||
const Register Op2,
|
||||
const MachineRegisterInfo &MRI);
|
||||
|
||||
/// Tries to constant fold a vector binop with sources \p Op1 and \p Op2.
|
||||
/// If successful, returns the G_BUILD_VECTOR representing the folded vector
|
||||
/// constant. \p MIB should have an insertion point already set to create new
|
||||
/// G_CONSTANT instructions as needed.
|
||||
Register ConstantFoldVectorBinop(unsigned Opcode, const Register Op1,
|
||||
const Register Op2,
|
||||
const MachineRegisterInfo &MRI,
|
||||
MachineIRBuilder &MIB);
|
||||
|
||||
Optional<APInt> ConstantFoldExtOp(unsigned Opcode, const Register Op1,
|
||||
uint64_t Imm, const MachineRegisterInfo &MRI);
|
||||
|
||||
Optional<APFloat> ConstantFoldIntToFloat(unsigned Opcode, LLT DstTy,
|
||||
Register Src,
|
||||
const MachineRegisterInfo &MRI);
|
||||
|
||||
/// Tries to constant fold a G_CTLZ operation on \p Src. If \p Src is a vector
|
||||
/// then it tries to do an element-wise constant fold.
|
||||
Optional<SmallVector<unsigned>>
|
||||
ConstantFoldCTLZ(Register Src, const MachineRegisterInfo &MRI);
|
||||
|
||||
/// Test if the given value is known to have exactly one bit set. This differs
|
||||
/// from computeKnownBits in that it doesn't necessarily determine which bit is
|
||||
/// set.
|
||||
bool isKnownToBeAPowerOfTwo(Register Val, const MachineRegisterInfo &MRI,
|
||||
GISelKnownBits *KnownBits = nullptr);
|
||||
|
||||
/// Returns true if \p Val can be assumed to never be a NaN. If \p SNaN is true,
|
||||
/// this returns if \p Val can be assumed to never be a signaling NaN.
|
||||
bool isKnownNeverNaN(Register Val, const MachineRegisterInfo &MRI,
|
||||
bool SNaN = false);
|
||||
|
||||
/// Returns true if \p Val can be assumed to never be a signaling NaN.
|
||||
inline bool isKnownNeverSNaN(Register Val, const MachineRegisterInfo &MRI) {
|
||||
return isKnownNeverNaN(Val, MRI, true);
|
||||
}
|
||||
|
||||
Align inferAlignFromPtrInfo(MachineFunction &MF, const MachinePointerInfo &MPO);
|
||||
|
||||
/// Return a virtual register corresponding to the incoming argument register \p
|
||||
/// PhysReg. This register is expected to have class \p RC, and optional type \p
|
||||
/// RegTy. This assumes all references to the register will use the same type.
|
||||
///
|
||||
/// If there is an existing live-in argument register, it will be returned.
|
||||
/// This will also ensure there is a valid copy
|
||||
Register getFunctionLiveInPhysReg(MachineFunction &MF,
|
||||
const TargetInstrInfo &TII,
|
||||
MCRegister PhysReg,
|
||||
const TargetRegisterClass &RC,
|
||||
const DebugLoc &DL, LLT RegTy = LLT());
|
||||
|
||||
/// Return the least common multiple type of \p OrigTy and \p TargetTy, by changing the
|
||||
/// number of vector elements or scalar bitwidth. The intent is a
|
||||
/// G_MERGE_VALUES, G_BUILD_VECTOR, or G_CONCAT_VECTORS can be constructed from
|
||||
/// \p OrigTy elements, and unmerged into \p TargetTy
|
||||
LLVM_READNONE
|
||||
LLT getLCMType(LLT OrigTy, LLT TargetTy);
|
||||
|
||||
LLVM_READNONE
|
||||
/// Return smallest type that covers both \p OrigTy and \p TargetTy and is
|
||||
/// multiple of TargetTy.
|
||||
LLT getCoverTy(LLT OrigTy, LLT TargetTy);
|
||||
|
||||
/// Return a type where the total size is the greatest common divisor of \p
|
||||
/// OrigTy and \p TargetTy. This will try to either change the number of vector
|
||||
/// elements, or bitwidth of scalars. The intent is the result type can be used
|
||||
/// as the result of a G_UNMERGE_VALUES from \p OrigTy, and then some
|
||||
/// combination of G_MERGE_VALUES, G_BUILD_VECTOR and G_CONCAT_VECTORS (possibly
|
||||
/// with intermediate casts) can re-form \p TargetTy.
|
||||
///
|
||||
/// If these are vectors with different element types, this will try to produce
|
||||
/// a vector with a compatible total size, but the element type of \p OrigTy. If
|
||||
/// this can't be satisfied, this will produce a scalar smaller than the
|
||||
/// original vector elements.
|
||||
///
|
||||
/// In the worst case, this returns LLT::scalar(1)
|
||||
LLVM_READNONE
|
||||
LLT getGCDType(LLT OrigTy, LLT TargetTy);
|
||||
|
||||
/// Represents a value which can be a Register or a constant.
|
||||
///
|
||||
/// This is useful in situations where an instruction may have an interesting
|
||||
/// register operand or interesting constant operand. For a concrete example,
|
||||
/// \see getVectorSplat.
|
||||
class RegOrConstant {
|
||||
int64_t Cst;
|
||||
Register Reg;
|
||||
bool IsReg;
|
||||
|
||||
public:
|
||||
explicit RegOrConstant(Register Reg) : Reg(Reg), IsReg(true) {}
|
||||
explicit RegOrConstant(int64_t Cst) : Cst(Cst), IsReg(false) {}
|
||||
bool isReg() const { return IsReg; }
|
||||
bool isCst() const { return !IsReg; }
|
||||
Register getReg() const {
|
||||
assert(isReg() && "Expected a register!");
|
||||
return Reg;
|
||||
}
|
||||
int64_t getCst() const {
|
||||
assert(isCst() && "Expected a constant!");
|
||||
return Cst;
|
||||
}
|
||||
};
|
||||
|
||||
/// \returns The splat index of a G_SHUFFLE_VECTOR \p MI when \p MI is a splat.
|
||||
/// If \p MI is not a splat, returns None.
|
||||
Optional<int> getSplatIndex(MachineInstr &MI);
|
||||
|
||||
/// Returns a scalar constant of a G_BUILD_VECTOR splat if it exists.
|
||||
Optional<int64_t> getBuildVectorConstantSplat(const MachineInstr &MI,
|
||||
const MachineRegisterInfo &MRI);
|
||||
|
||||
/// Returns a floating point scalar constant of a build vector splat if it
|
||||
/// exists. When \p AllowUndef == true some elements can be undef but not all.
|
||||
Optional<FPValueAndVReg> getFConstantSplat(Register VReg,
|
||||
const MachineRegisterInfo &MRI,
|
||||
bool AllowUndef = true);
|
||||
|
||||
/// Return true if the specified register is defined by G_BUILD_VECTOR or
|
||||
/// G_BUILD_VECTOR_TRUNC where all of the elements are \p SplatValue or undef.
|
||||
bool isBuildVectorConstantSplat(const Register Reg,
|
||||
const MachineRegisterInfo &MRI,
|
||||
int64_t SplatValue, bool AllowUndef);
|
||||
|
||||
/// Return true if the specified instruction is a G_BUILD_VECTOR or
|
||||
/// G_BUILD_VECTOR_TRUNC where all of the elements are \p SplatValue or undef.
|
||||
bool isBuildVectorConstantSplat(const MachineInstr &MI,
|
||||
const MachineRegisterInfo &MRI,
|
||||
int64_t SplatValue, bool AllowUndef);
|
||||
|
||||
/// Return true if the specified instruction is a G_BUILD_VECTOR or
|
||||
/// G_BUILD_VECTOR_TRUNC where all of the elements are 0 or undef.
|
||||
bool isBuildVectorAllZeros(const MachineInstr &MI,
|
||||
const MachineRegisterInfo &MRI,
|
||||
bool AllowUndef = false);
|
||||
|
||||
/// Return true if the specified instruction is a G_BUILD_VECTOR or
|
||||
/// G_BUILD_VECTOR_TRUNC where all of the elements are ~0 or undef.
|
||||
bool isBuildVectorAllOnes(const MachineInstr &MI,
|
||||
const MachineRegisterInfo &MRI,
|
||||
bool AllowUndef = false);
|
||||
|
||||
/// \returns a value when \p MI is a vector splat. The splat can be either a
|
||||
/// Register or a constant.
|
||||
///
|
||||
/// Examples:
|
||||
///
|
||||
/// \code
|
||||
/// %reg = COPY $physreg
|
||||
/// %reg_splat = G_BUILD_VECTOR %reg, %reg, ..., %reg
|
||||
/// \endcode
|
||||
///
|
||||
/// If called on the G_BUILD_VECTOR above, this will return a RegOrConstant
|
||||
/// containing %reg.
|
||||
///
|
||||
/// \code
|
||||
/// %cst = G_CONSTANT iN 4
|
||||
/// %constant_splat = G_BUILD_VECTOR %cst, %cst, ..., %cst
|
||||
/// \endcode
|
||||
///
|
||||
/// In the above case, this will return a RegOrConstant containing 4.
|
||||
Optional<RegOrConstant> getVectorSplat(const MachineInstr &MI,
|
||||
const MachineRegisterInfo &MRI);
|
||||
|
||||
/// Determines if \p MI defines a constant integer or a build vector of
|
||||
/// constant integers. Treats undef values as constants.
|
||||
bool isConstantOrConstantVector(MachineInstr &MI,
|
||||
const MachineRegisterInfo &MRI);
|
||||
|
||||
/// Determines if \p MI defines a constant integer or a splat vector of
|
||||
/// constant integers.
|
||||
/// \returns the scalar constant or None.
|
||||
Optional<APInt> isConstantOrConstantSplatVector(MachineInstr &MI,
|
||||
const MachineRegisterInfo &MRI);
|
||||
|
||||
/// Attempt to match a unary predicate against a scalar/splat constant or every
|
||||
/// element of a constant G_BUILD_VECTOR. If \p ConstVal is null, the source
|
||||
/// value was undef.
|
||||
bool matchUnaryPredicate(const MachineRegisterInfo &MRI, Register Reg,
|
||||
std::function<bool(const Constant *ConstVal)> Match,
|
||||
bool AllowUndefs = false);
|
||||
|
||||
/// Returns true if given the TargetLowering's boolean contents information,
|
||||
/// the value \p Val contains a true value.
|
||||
bool isConstTrueVal(const TargetLowering &TLI, int64_t Val, bool IsVector,
|
||||
bool IsFP);
|
||||
|
||||
/// Returns an integer representing true, as defined by the
|
||||
/// TargetBooleanContents.
|
||||
int64_t getICmpTrueVal(const TargetLowering &TLI, bool IsVector, bool IsFP);
|
||||
|
||||
/// Returns true if the given block should be optimized for size.
|
||||
bool shouldOptForSize(const MachineBasicBlock &MBB, ProfileSummaryInfo *PSI,
|
||||
BlockFrequencyInfo *BFI);
|
||||
|
||||
using SmallInstListTy = GISelWorkList<4>;
|
||||
void saveUsesAndErase(MachineInstr &MI, MachineRegisterInfo &MRI,
|
||||
LostDebugLocObserver *LocObserver,
|
||||
SmallInstListTy &DeadInstChain);
|
||||
void eraseInstrs(ArrayRef<MachineInstr *> DeadInstrs, MachineRegisterInfo &MRI,
|
||||
LostDebugLocObserver *LocObserver = nullptr);
|
||||
void eraseInstr(MachineInstr &MI, MachineRegisterInfo &MRI,
|
||||
LostDebugLocObserver *LocObserver = nullptr);
|
||||
|
||||
} // End namespace llvm.
|
||||
#endif
|
||||
1463
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/ISDOpcodes.h
vendored
Normal file
1463
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/ISDOpcodes.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
115
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/IndirectThunks.h
vendored
Normal file
115
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/IndirectThunks.h
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
//===---- IndirectThunks.h - Indirect Thunk Base Class ----------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// Contains a base class for Passes that inject an MI thunk.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_INDIRECTTHUNKS_H
|
||||
#define LLVM_CODEGEN_INDIRECTTHUNKS_H
|
||||
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineModuleInfo.h"
|
||||
#include "llvm/IR/IRBuilder.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
template <typename Derived> class ThunkInserter {
|
||||
Derived &getDerived() { return *static_cast<Derived *>(this); }
|
||||
|
||||
protected:
|
||||
bool InsertedThunks;
|
||||
void doInitialization(Module &M) {}
|
||||
void createThunkFunction(MachineModuleInfo &MMI, StringRef Name,
|
||||
bool Comdat = true);
|
||||
|
||||
public:
|
||||
void init(Module &M) {
|
||||
InsertedThunks = false;
|
||||
getDerived().doInitialization(M);
|
||||
}
|
||||
// return `true` if `MMI` or `MF` was modified
|
||||
bool run(MachineModuleInfo &MMI, MachineFunction &MF);
|
||||
};
|
||||
|
||||
template <typename Derived>
|
||||
void ThunkInserter<Derived>::createThunkFunction(MachineModuleInfo &MMI,
|
||||
StringRef Name, bool Comdat) {
|
||||
assert(Name.startswith(getDerived().getThunkPrefix()) &&
|
||||
"Created a thunk with an unexpected prefix!");
|
||||
|
||||
Module &M = const_cast<Module &>(*MMI.getModule());
|
||||
LLVMContext &Ctx = M.getContext();
|
||||
auto Type = FunctionType::get(Type::getVoidTy(Ctx), false);
|
||||
Function *F = Function::Create(Type,
|
||||
Comdat ? GlobalValue::LinkOnceODRLinkage
|
||||
: GlobalValue::InternalLinkage,
|
||||
Name, &M);
|
||||
if (Comdat) {
|
||||
F->setVisibility(GlobalValue::HiddenVisibility);
|
||||
F->setComdat(M.getOrInsertComdat(Name));
|
||||
}
|
||||
|
||||
// Add Attributes so that we don't create a frame, unwind information, or
|
||||
// inline.
|
||||
AttrBuilder B(Ctx);
|
||||
B.addAttribute(llvm::Attribute::NoUnwind);
|
||||
B.addAttribute(llvm::Attribute::Naked);
|
||||
F->addFnAttrs(B);
|
||||
|
||||
// Populate our function a bit so that we can verify.
|
||||
BasicBlock *Entry = BasicBlock::Create(Ctx, "entry", F);
|
||||
IRBuilder<> Builder(Entry);
|
||||
|
||||
Builder.CreateRetVoid();
|
||||
|
||||
// MachineFunctions aren't created automatically for the IR-level constructs
|
||||
// we already made. Create them and insert them into the module.
|
||||
MachineFunction &MF = MMI.getOrCreateMachineFunction(*F);
|
||||
// A MachineBasicBlock must not be created for the Entry block; code
|
||||
// generation from an empty naked function in C source code also does not
|
||||
// generate one. At least GlobalISel asserts if this invariant isn't
|
||||
// respected.
|
||||
|
||||
// Set MF properties. We never use vregs...
|
||||
MF.getProperties().set(MachineFunctionProperties::Property::NoVRegs);
|
||||
}
|
||||
|
||||
template <typename Derived>
|
||||
bool ThunkInserter<Derived>::run(MachineModuleInfo &MMI, MachineFunction &MF) {
|
||||
// If MF is not a thunk, check to see if we need to insert a thunk.
|
||||
if (!MF.getName().startswith(getDerived().getThunkPrefix())) {
|
||||
// If we've already inserted a thunk, nothing else to do.
|
||||
if (InsertedThunks)
|
||||
return false;
|
||||
|
||||
// Only add a thunk if one of the functions has the corresponding feature
|
||||
// enabled in its subtarget, and doesn't enable external thunks.
|
||||
// FIXME: Conditionalize on indirect calls so we don't emit a thunk when
|
||||
// nothing will end up calling it.
|
||||
// FIXME: It's a little silly to look at every function just to enumerate
|
||||
// the subtargets, but eventually we'll want to look at them for indirect
|
||||
// calls, so maybe this is OK.
|
||||
if (!getDerived().mayUseThunk(MF))
|
||||
return false;
|
||||
|
||||
getDerived().insertThunks(MMI);
|
||||
InsertedThunks = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
// If this *is* a thunk function, we need to populate it with the correct MI.
|
||||
getDerived().populateThunk(MF);
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif
|
||||
48
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/IntrinsicLowering.h
vendored
Normal file
48
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/IntrinsicLowering.h
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
//===-- IntrinsicLowering.h - Intrinsic Function Lowering -------*- 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 file defines the IntrinsicLowering interface. This interface allows
|
||||
// addition of domain-specific or front-end specific intrinsics to LLVM without
|
||||
// having to modify all of the C backend or interpreter.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_INTRINSICLOWERING_H
|
||||
#define LLVM_CODEGEN_INTRINSICLOWERING_H
|
||||
|
||||
#include "llvm/IR/Intrinsics.h"
|
||||
|
||||
namespace llvm {
|
||||
class CallInst;
|
||||
class DataLayout;
|
||||
|
||||
class IntrinsicLowering {
|
||||
const DataLayout &DL;
|
||||
|
||||
bool Warned = false;
|
||||
|
||||
public:
|
||||
explicit IntrinsicLowering(const DataLayout &DL) : DL(DL) {}
|
||||
|
||||
/// Replace a call to the specified intrinsic function.
|
||||
/// If an intrinsic function must be implemented by the code generator
|
||||
/// (such as va_start), this function should print a message and abort.
|
||||
///
|
||||
/// Otherwise, if an intrinsic function call can be lowered, the code to
|
||||
/// implement it (often a call to a non-intrinsic function) is inserted
|
||||
/// _after_ the call instruction and the call is deleted. The caller must
|
||||
/// be capable of handling this kind of change.
|
||||
void LowerIntrinsicCall(CallInst *CI);
|
||||
|
||||
/// Try to replace a call instruction with a call to a bswap intrinsic. Return
|
||||
/// false if the call is not a simple integer bswap.
|
||||
static bool LowerToByteSwap(CallInst *CI);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
102
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LatencyPriorityQueue.h
vendored
Normal file
102
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LatencyPriorityQueue.h
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
//===---- LatencyPriorityQueue.h - A latency-oriented priority queue ------===//
|
||||
//
|
||||
// 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 file declares the LatencyPriorityQueue class, which is a
|
||||
// SchedulingPriorityQueue that schedules using latency information to
|
||||
// reduce the length of the critical path through the basic block.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_LATENCYPRIORITYQUEUE_H
|
||||
#define LLVM_CODEGEN_LATENCYPRIORITYQUEUE_H
|
||||
|
||||
#include "llvm/CodeGen/ScheduleDAG.h"
|
||||
#include "llvm/Config/llvm-config.h"
|
||||
|
||||
namespace llvm {
|
||||
class LatencyPriorityQueue;
|
||||
|
||||
/// Sorting functions for the Available queue.
|
||||
struct latency_sort {
|
||||
LatencyPriorityQueue *PQ;
|
||||
explicit latency_sort(LatencyPriorityQueue *pq) : PQ(pq) {}
|
||||
|
||||
bool operator()(const SUnit* LHS, const SUnit* RHS) const;
|
||||
};
|
||||
|
||||
class LatencyPriorityQueue : public SchedulingPriorityQueue {
|
||||
// SUnits - The SUnits for the current graph.
|
||||
std::vector<SUnit> *SUnits;
|
||||
|
||||
/// NumNodesSolelyBlocking - This vector contains, for every node in the
|
||||
/// Queue, the number of nodes that the node is the sole unscheduled
|
||||
/// predecessor for. This is used as a tie-breaker heuristic for better
|
||||
/// mobility.
|
||||
std::vector<unsigned> NumNodesSolelyBlocking;
|
||||
|
||||
/// Queue - The queue.
|
||||
std::vector<SUnit*> Queue;
|
||||
latency_sort Picker;
|
||||
|
||||
public:
|
||||
LatencyPriorityQueue() : Picker(this) {
|
||||
}
|
||||
|
||||
bool isBottomUp() const override { return false; }
|
||||
|
||||
void initNodes(std::vector<SUnit> &sunits) override {
|
||||
SUnits = &sunits;
|
||||
NumNodesSolelyBlocking.resize(SUnits->size(), 0);
|
||||
}
|
||||
|
||||
void addNode(const SUnit *SU) override {
|
||||
NumNodesSolelyBlocking.resize(SUnits->size(), 0);
|
||||
}
|
||||
|
||||
void updateNode(const SUnit *SU) override {
|
||||
}
|
||||
|
||||
void releaseState() override {
|
||||
SUnits = nullptr;
|
||||
}
|
||||
|
||||
unsigned getLatency(unsigned NodeNum) const {
|
||||
assert(NodeNum < (*SUnits).size());
|
||||
return (*SUnits)[NodeNum].getHeight();
|
||||
}
|
||||
|
||||
unsigned getNumSolelyBlockNodes(unsigned NodeNum) const {
|
||||
assert(NodeNum < NumNodesSolelyBlocking.size());
|
||||
return NumNodesSolelyBlocking[NodeNum];
|
||||
}
|
||||
|
||||
bool empty() const override { return Queue.empty(); }
|
||||
|
||||
void push(SUnit *U) override;
|
||||
|
||||
SUnit *pop() override;
|
||||
|
||||
void remove(SUnit *SU) override;
|
||||
|
||||
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
||||
LLVM_DUMP_METHOD void dump(ScheduleDAG *DAG) const override;
|
||||
#endif
|
||||
|
||||
// scheduledNode - As nodes are scheduled, we look to see if there are any
|
||||
// successor nodes that have a single unscheduled predecessor. If so, that
|
||||
// single predecessor has a higher priority, since scheduling it will make
|
||||
// the node available.
|
||||
void scheduledNode(SUnit *SU) override;
|
||||
|
||||
private:
|
||||
void AdjustPriorityOfUnscheduledPreds(SUnit *SU);
|
||||
SUnit *getSingleUnscheduledPred(SUnit *SU);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,75 @@
|
||||
///===- LazyMachineBlockFrequencyInfo.h - Lazy Block Frequency -*- 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
|
||||
///
|
||||
///===---------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// This is an alternative analysis pass to MachineBlockFrequencyInfo. The
|
||||
/// difference is that with this pass the block frequencies are not computed
|
||||
/// when the analysis pass is executed but rather when the BFI result is
|
||||
/// explicitly requested by the analysis client.
|
||||
///
|
||||
///===---------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_LAZYMACHINEBLOCKFREQUENCYINFO_H
|
||||
#define LLVM_CODEGEN_LAZYMACHINEBLOCKFREQUENCYINFO_H
|
||||
|
||||
#include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
|
||||
#include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
|
||||
#include "llvm/CodeGen/MachineDominators.h"
|
||||
#include "llvm/CodeGen/MachineLoopInfo.h"
|
||||
|
||||
namespace llvm {
|
||||
/// This is an alternative analysis pass to MachineBlockFrequencyInfo.
|
||||
/// The difference is that with this pass, the block frequencies are not
|
||||
/// computed when the analysis pass is executed but rather when the BFI result
|
||||
/// is explicitly requested by the analysis client.
|
||||
///
|
||||
/// This works by checking querying if MBFI is available and otherwise
|
||||
/// generating MBFI on the fly. In this case the passes required for (LI, DT)
|
||||
/// are also queried before being computed on the fly.
|
||||
///
|
||||
/// Note that it is expected that we wouldn't need this functionality for the
|
||||
/// new PM since with the new PM, analyses are executed on demand.
|
||||
|
||||
class LazyMachineBlockFrequencyInfoPass : public MachineFunctionPass {
|
||||
private:
|
||||
/// If generated on the fly this own the instance.
|
||||
mutable std::unique_ptr<MachineBlockFrequencyInfo> OwnedMBFI;
|
||||
|
||||
/// If generated on the fly this own the instance.
|
||||
mutable std::unique_ptr<MachineLoopInfo> OwnedMLI;
|
||||
|
||||
/// If generated on the fly this own the instance.
|
||||
mutable std::unique_ptr<MachineDominatorTree> OwnedMDT;
|
||||
|
||||
/// The function.
|
||||
MachineFunction *MF = nullptr;
|
||||
|
||||
/// Calculate MBFI and all other analyses that's not available and
|
||||
/// required by BFI.
|
||||
MachineBlockFrequencyInfo &calculateIfNotAvailable() const;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
LazyMachineBlockFrequencyInfoPass();
|
||||
|
||||
/// Compute and return the block frequencies.
|
||||
MachineBlockFrequencyInfo &getBFI() { return calculateIfNotAvailable(); }
|
||||
|
||||
/// Compute and return the block frequencies.
|
||||
const MachineBlockFrequencyInfo &getBFI() const {
|
||||
return calculateIfNotAvailable();
|
||||
}
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
bool runOnMachineFunction(MachineFunction &F) override;
|
||||
void releaseMemory() override;
|
||||
void print(raw_ostream &OS, const Module *M) const override;
|
||||
};
|
||||
}
|
||||
#endif
|
||||
259
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LexicalScopes.h
vendored
Normal file
259
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LexicalScopes.h
vendored
Normal file
@@ -0,0 +1,259 @@
|
||||
//===- LexicalScopes.cpp - Collecting lexical scope info --------*- 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 file implements LexicalScopes analysis.
|
||||
//
|
||||
// This pass collects lexical scope information and maps machine instructions
|
||||
// to respective lexical scopes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_LEXICALSCOPES_H
|
||||
#define LLVM_CODEGEN_LEXICALSCOPES_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/IR/DebugInfoMetadata.h"
|
||||
#include <cassert>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MachineBasicBlock;
|
||||
class MachineFunction;
|
||||
class MachineInstr;
|
||||
class MDNode;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// InsnRange - This is used to track range of instructions with identical
|
||||
/// lexical scope.
|
||||
///
|
||||
using InsnRange = std::pair<const MachineInstr *, const MachineInstr *>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// LexicalScope - This class is used to track scope information.
|
||||
///
|
||||
class LexicalScope {
|
||||
public:
|
||||
LexicalScope(LexicalScope *P, const DILocalScope *D, const DILocation *I,
|
||||
bool A)
|
||||
: Parent(P), Desc(D), InlinedAtLocation(I), AbstractScope(A) {
|
||||
assert(D);
|
||||
assert(D->getSubprogram()->getUnit()->getEmissionKind() !=
|
||||
DICompileUnit::NoDebug &&
|
||||
"Don't build lexical scopes for non-debug locations");
|
||||
assert(D->isResolved() && "Expected resolved node");
|
||||
assert((!I || I->isResolved()) && "Expected resolved node");
|
||||
if (Parent)
|
||||
Parent->addChild(this);
|
||||
}
|
||||
|
||||
// Accessors.
|
||||
LexicalScope *getParent() const { return Parent; }
|
||||
const MDNode *getDesc() const { return Desc; }
|
||||
const DILocation *getInlinedAt() const { return InlinedAtLocation; }
|
||||
const DILocalScope *getScopeNode() const { return Desc; }
|
||||
bool isAbstractScope() const { return AbstractScope; }
|
||||
SmallVectorImpl<LexicalScope *> &getChildren() { return Children; }
|
||||
SmallVectorImpl<InsnRange> &getRanges() { return Ranges; }
|
||||
|
||||
/// addChild - Add a child scope.
|
||||
void addChild(LexicalScope *S) { Children.push_back(S); }
|
||||
|
||||
/// openInsnRange - This scope covers instruction range starting from MI.
|
||||
void openInsnRange(const MachineInstr *MI) {
|
||||
if (!FirstInsn)
|
||||
FirstInsn = MI;
|
||||
|
||||
if (Parent)
|
||||
Parent->openInsnRange(MI);
|
||||
}
|
||||
|
||||
/// extendInsnRange - Extend the current instruction range covered by
|
||||
/// this scope.
|
||||
void extendInsnRange(const MachineInstr *MI) {
|
||||
assert(FirstInsn && "MI Range is not open!");
|
||||
LastInsn = MI;
|
||||
if (Parent)
|
||||
Parent->extendInsnRange(MI);
|
||||
}
|
||||
|
||||
/// closeInsnRange - Create a range based on FirstInsn and LastInsn collected
|
||||
/// until now. This is used when a new scope is encountered while walking
|
||||
/// machine instructions.
|
||||
void closeInsnRange(LexicalScope *NewScope = nullptr) {
|
||||
assert(LastInsn && "Last insn missing!");
|
||||
Ranges.push_back(InsnRange(FirstInsn, LastInsn));
|
||||
FirstInsn = nullptr;
|
||||
LastInsn = nullptr;
|
||||
// If Parent dominates NewScope then do not close Parent's instruction
|
||||
// range.
|
||||
if (Parent && (!NewScope || !Parent->dominates(NewScope)))
|
||||
Parent->closeInsnRange(NewScope);
|
||||
}
|
||||
|
||||
/// dominates - Return true if current scope dominates given lexical scope.
|
||||
bool dominates(const LexicalScope *S) const {
|
||||
if (S == this)
|
||||
return true;
|
||||
if (DFSIn < S->getDFSIn() && DFSOut > S->getDFSOut())
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Depth First Search support to walk and manipulate LexicalScope hierarchy.
|
||||
unsigned getDFSOut() const { return DFSOut; }
|
||||
void setDFSOut(unsigned O) { DFSOut = O; }
|
||||
unsigned getDFSIn() const { return DFSIn; }
|
||||
void setDFSIn(unsigned I) { DFSIn = I; }
|
||||
|
||||
/// dump - print lexical scope.
|
||||
void dump(unsigned Indent = 0) const;
|
||||
|
||||
private:
|
||||
LexicalScope *Parent; // Parent to this scope.
|
||||
const DILocalScope *Desc; // Debug info descriptor.
|
||||
const DILocation *InlinedAtLocation; // Location at which this
|
||||
// scope is inlined.
|
||||
bool AbstractScope; // Abstract Scope
|
||||
SmallVector<LexicalScope *, 4> Children; // Scopes defined in scope.
|
||||
// Contents not owned.
|
||||
SmallVector<InsnRange, 4> Ranges;
|
||||
|
||||
const MachineInstr *LastInsn = nullptr; // Last instruction of this scope.
|
||||
const MachineInstr *FirstInsn = nullptr; // First instruction of this scope.
|
||||
unsigned DFSIn = 0; // In & Out Depth use to determine scope nesting.
|
||||
unsigned DFSOut = 0;
|
||||
};
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// LexicalScopes - This class provides interface to collect and use lexical
|
||||
/// scoping information from machine instruction.
|
||||
///
|
||||
class LexicalScopes {
|
||||
public:
|
||||
LexicalScopes() = default;
|
||||
|
||||
/// initialize - Scan machine function and construct lexical scope nest, resets
|
||||
/// the instance if necessary.
|
||||
void initialize(const MachineFunction &);
|
||||
|
||||
/// releaseMemory - release memory.
|
||||
void reset();
|
||||
|
||||
/// empty - Return true if there is any lexical scope information available.
|
||||
bool empty() { return CurrentFnLexicalScope == nullptr; }
|
||||
|
||||
/// getCurrentFunctionScope - Return lexical scope for the current function.
|
||||
LexicalScope *getCurrentFunctionScope() const {
|
||||
return CurrentFnLexicalScope;
|
||||
}
|
||||
|
||||
/// getMachineBasicBlocks - Populate given set using machine basic blocks
|
||||
/// which have machine instructions that belong to lexical scope identified by
|
||||
/// DebugLoc.
|
||||
void getMachineBasicBlocks(const DILocation *DL,
|
||||
SmallPtrSetImpl<const MachineBasicBlock *> &MBBs);
|
||||
|
||||
/// Return true if DebugLoc's lexical scope dominates at least one machine
|
||||
/// instruction's lexical scope in a given machine basic block.
|
||||
bool dominates(const DILocation *DL, MachineBasicBlock *MBB);
|
||||
|
||||
/// findLexicalScope - Find lexical scope, either regular or inlined, for the
|
||||
/// given DebugLoc. Return NULL if not found.
|
||||
LexicalScope *findLexicalScope(const DILocation *DL);
|
||||
|
||||
/// getAbstractScopesList - Return a reference to list of abstract scopes.
|
||||
ArrayRef<LexicalScope *> getAbstractScopesList() const {
|
||||
return AbstractScopesList;
|
||||
}
|
||||
|
||||
/// findAbstractScope - Find an abstract scope or return null.
|
||||
LexicalScope *findAbstractScope(const DILocalScope *N) {
|
||||
auto I = AbstractScopeMap.find(N);
|
||||
return I != AbstractScopeMap.end() ? &I->second : nullptr;
|
||||
}
|
||||
|
||||
/// findInlinedScope - Find an inlined scope for the given scope/inlined-at.
|
||||
LexicalScope *findInlinedScope(const DILocalScope *N, const DILocation *IA) {
|
||||
auto I = InlinedLexicalScopeMap.find(std::make_pair(N, IA));
|
||||
return I != InlinedLexicalScopeMap.end() ? &I->second : nullptr;
|
||||
}
|
||||
|
||||
/// findLexicalScope - Find regular lexical scope or return null.
|
||||
LexicalScope *findLexicalScope(const DILocalScope *N) {
|
||||
auto I = LexicalScopeMap.find(N);
|
||||
return I != LexicalScopeMap.end() ? &I->second : nullptr;
|
||||
}
|
||||
|
||||
/// getOrCreateAbstractScope - Find or create an abstract lexical scope.
|
||||
LexicalScope *getOrCreateAbstractScope(const DILocalScope *Scope);
|
||||
|
||||
private:
|
||||
/// getOrCreateLexicalScope - Find lexical scope for the given Scope/IA. If
|
||||
/// not available then create new lexical scope.
|
||||
LexicalScope *getOrCreateLexicalScope(const DILocalScope *Scope,
|
||||
const DILocation *IA = nullptr);
|
||||
LexicalScope *getOrCreateLexicalScope(const DILocation *DL) {
|
||||
return DL ? getOrCreateLexicalScope(DL->getScope(), DL->getInlinedAt())
|
||||
: nullptr;
|
||||
}
|
||||
|
||||
/// getOrCreateRegularScope - Find or create a regular lexical scope.
|
||||
LexicalScope *getOrCreateRegularScope(const DILocalScope *Scope);
|
||||
|
||||
/// getOrCreateInlinedScope - Find or create an inlined lexical scope.
|
||||
LexicalScope *getOrCreateInlinedScope(const DILocalScope *Scope,
|
||||
const DILocation *InlinedAt);
|
||||
|
||||
/// extractLexicalScopes - Extract instruction ranges for each lexical scopes
|
||||
/// for the given machine function.
|
||||
void extractLexicalScopes(SmallVectorImpl<InsnRange> &MIRanges,
|
||||
DenseMap<const MachineInstr *, LexicalScope *> &M);
|
||||
void constructScopeNest(LexicalScope *Scope);
|
||||
void
|
||||
assignInstructionRanges(SmallVectorImpl<InsnRange> &MIRanges,
|
||||
DenseMap<const MachineInstr *, LexicalScope *> &M);
|
||||
|
||||
const MachineFunction *MF = nullptr;
|
||||
|
||||
/// LexicalScopeMap - Tracks the scopes in the current function.
|
||||
// Use an unordered_map to ensure value pointer validity over insertion.
|
||||
std::unordered_map<const DILocalScope *, LexicalScope> LexicalScopeMap;
|
||||
|
||||
/// InlinedLexicalScopeMap - Tracks inlined function scopes in current
|
||||
/// function.
|
||||
std::unordered_map<std::pair<const DILocalScope *, const DILocation *>,
|
||||
LexicalScope,
|
||||
pair_hash<const DILocalScope *, const DILocation *>>
|
||||
InlinedLexicalScopeMap;
|
||||
|
||||
/// AbstractScopeMap - These scopes are not included LexicalScopeMap.
|
||||
// Use an unordered_map to ensure value pointer validity over insertion.
|
||||
std::unordered_map<const DILocalScope *, LexicalScope> AbstractScopeMap;
|
||||
|
||||
/// AbstractScopesList - Tracks abstract scopes constructed while processing
|
||||
/// a function.
|
||||
SmallVector<LexicalScope *, 4> AbstractScopesList;
|
||||
|
||||
/// CurrentFnLexicalScope - Top level scope for the current function.
|
||||
///
|
||||
LexicalScope *CurrentFnLexicalScope = nullptr;
|
||||
|
||||
/// Map a location to the set of basic blocks it dominates. This is a cache
|
||||
/// for \ref LexicalScopes::getMachineBasicBlocks results.
|
||||
using BlockSetT = SmallPtrSet<const MachineBasicBlock *, 4>;
|
||||
DenseMap<const DILocation *, std::unique_ptr<BlockSetT>> DominatedBlocks;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_LEXICALSCOPES_H
|
||||
40
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LinkAllAsmWriterComponents.h
vendored
Normal file
40
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LinkAllAsmWriterComponents.h
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
//===- llvm/Codegen/LinkAllAsmWriterComponents.h ----------------*- 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 header file pulls in all assembler writer related passes for tools like
|
||||
// llc that need this functionality.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_LINKALLASMWRITERCOMPONENTS_H
|
||||
#define LLVM_CODEGEN_LINKALLASMWRITERCOMPONENTS_H
|
||||
|
||||
#include "llvm/IR/BuiltinGCs.h"
|
||||
#include <cstdlib>
|
||||
|
||||
namespace {
|
||||
struct ForceAsmWriterLinking {
|
||||
ForceAsmWriterLinking() {
|
||||
// We must reference the plug-ins in such a way that compilers will not
|
||||
// delete it all as dead code, even with whole program optimization,
|
||||
// yet is effectively a NO-OP. As the compiler isn't smart enough
|
||||
// to know that getenv() never returns -1, this will do the job.
|
||||
// This is so that globals in the translation units where these functions
|
||||
// are defined are forced to be initialized, populating various
|
||||
// registries.
|
||||
if (std::getenv("bar") != (char*) -1)
|
||||
return;
|
||||
|
||||
llvm::linkOcamlGCPrinter();
|
||||
llvm::linkErlangGCPrinter();
|
||||
|
||||
}
|
||||
} ForceAsmWriterLinking; // Force link by creating a global definition.
|
||||
}
|
||||
|
||||
#endif // LLVM_CODEGEN_LINKALLASMWRITERCOMPONENTS_H
|
||||
57
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LinkAllCodegenComponents.h
vendored
Normal file
57
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LinkAllCodegenComponents.h
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
//===- llvm/Codegen/LinkAllCodegenComponents.h ------------------*- 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 header file pulls in all codegen related passes for tools like lli and
|
||||
// llc that need this functionality.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_LINKALLCODEGENCOMPONENTS_H
|
||||
#define LLVM_CODEGEN_LINKALLCODEGENCOMPONENTS_H
|
||||
|
||||
#include "llvm/IR/BuiltinGCs.h"
|
||||
#include "llvm/CodeGen/Passes.h"
|
||||
#include "llvm/CodeGen/SchedulerRegistry.h"
|
||||
#include "llvm/Target/TargetMachine.h"
|
||||
#include <cstdlib>
|
||||
|
||||
namespace {
|
||||
struct ForceCodegenLinking {
|
||||
ForceCodegenLinking() {
|
||||
// We must reference the passes in such a way that compilers will not
|
||||
// delete it all as dead code, even with whole program optimization,
|
||||
// yet is effectively a NO-OP. As the compiler isn't smart enough
|
||||
// to know that getenv() never returns -1, this will do the job.
|
||||
// This is so that globals in the translation units where these functions
|
||||
// are defined are forced to be initialized, populating various
|
||||
// registries.
|
||||
if (std::getenv("bar") != (char*) -1)
|
||||
return;
|
||||
|
||||
(void) llvm::createFastRegisterAllocator();
|
||||
(void) llvm::createBasicRegisterAllocator();
|
||||
(void) llvm::createGreedyRegisterAllocator();
|
||||
(void) llvm::createDefaultPBQPRegisterAllocator();
|
||||
|
||||
llvm::linkAllBuiltinGCs();
|
||||
|
||||
(void) llvm::createBURRListDAGScheduler(nullptr,
|
||||
llvm::CodeGenOpt::Default);
|
||||
(void) llvm::createSourceListDAGScheduler(nullptr,
|
||||
llvm::CodeGenOpt::Default);
|
||||
(void) llvm::createHybridListDAGScheduler(nullptr,
|
||||
llvm::CodeGenOpt::Default);
|
||||
(void) llvm::createFastDAGScheduler(nullptr, llvm::CodeGenOpt::Default);
|
||||
(void) llvm::createDefaultScheduler(nullptr, llvm::CodeGenOpt::Default);
|
||||
(void) llvm::createVLIWDAGScheduler(nullptr, llvm::CodeGenOpt::Default);
|
||||
|
||||
}
|
||||
} ForceCodegenLinking; // Force link by creating a global definition.
|
||||
}
|
||||
|
||||
#endif
|
||||
1017
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LiveInterval.h
vendored
Normal file
1017
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LiveInterval.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
71
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LiveIntervalCalc.h
vendored
Normal file
71
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LiveIntervalCalc.h
vendored
Normal file
@@ -0,0 +1,71 @@
|
||||
//===- LiveIntervalCalc.h - Calculate live intervals -----------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LiveIntervalCalc class is an extension of LiveRangeCalc targeted to the
|
||||
// computation and modification of the LiveInterval variants of LiveRanges.
|
||||
// LiveIntervals are meant to track liveness of registers and stack slots and
|
||||
// LiveIntervalCalc adds to LiveRangeCalc all the machinery required to
|
||||
// construct the liveness of virtual registers tracked by a LiveInterval.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_LIVEINTERVALCALC_H
|
||||
#define LLVM_CODEGEN_LIVEINTERVALCALC_H
|
||||
|
||||
#include "llvm/CodeGen/LiveRangeCalc.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
template <class NodeT> class DomTreeNodeBase;
|
||||
|
||||
using MachineDomTreeNode = DomTreeNodeBase<MachineBasicBlock>;
|
||||
|
||||
class LiveIntervalCalc : public LiveRangeCalc {
|
||||
/// Extend the live range of @p LR to reach all uses of Reg.
|
||||
///
|
||||
/// If @p LR is a main range, or if @p LI is null, then all uses must be
|
||||
/// jointly dominated by the definitions from @p LR. If @p LR is a subrange
|
||||
/// of the live interval @p LI, corresponding to lane mask @p LaneMask,
|
||||
/// all uses must be jointly dominated by the definitions from @p LR
|
||||
/// together with definitions of other lanes where @p LR becomes undefined
|
||||
/// (via <def,read-undef> operands).
|
||||
/// If @p LR is a main range, the @p LaneMask should be set to ~0, i.e.
|
||||
/// LaneBitmask::getAll().
|
||||
void extendToUses(LiveRange &LR, Register Reg, LaneBitmask LaneMask,
|
||||
LiveInterval *LI = nullptr);
|
||||
|
||||
public:
|
||||
LiveIntervalCalc() = default;
|
||||
|
||||
/// createDeadDefs - Create a dead def in LI for every def operand of Reg.
|
||||
/// Each instruction defining Reg gets a new VNInfo with a corresponding
|
||||
/// minimal live range.
|
||||
void createDeadDefs(LiveRange &LR, Register Reg);
|
||||
|
||||
/// Extend the live range of @p LR to reach all uses of Reg.
|
||||
///
|
||||
/// All uses must be jointly dominated by existing liveness. PHI-defs are
|
||||
/// inserted as needed to preserve SSA form.
|
||||
void extendToUses(LiveRange &LR, MCRegister PhysReg) {
|
||||
extendToUses(LR, PhysReg, LaneBitmask::getAll());
|
||||
}
|
||||
|
||||
/// Calculates liveness for the register specified in live interval @p LI.
|
||||
/// Creates subregister live ranges as needed if subreg liveness tracking is
|
||||
/// enabled.
|
||||
void calculate(LiveInterval &LI, bool TrackSubRegs);
|
||||
|
||||
/// For live interval \p LI with correct SubRanges construct matching
|
||||
/// information for the main live range. Expects the main live range to not
|
||||
/// have any segments or value numbers.
|
||||
void constructMainRangeFromSubranges(LiveInterval &LI);
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_LIVEINTERVALCALC_H
|
||||
201
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LiveIntervalUnion.h
vendored
Normal file
201
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LiveIntervalUnion.h
vendored
Normal file
@@ -0,0 +1,201 @@
|
||||
//===- LiveIntervalUnion.h - Live interval union data struct ---*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// LiveIntervalUnion is a union of live segments across multiple live virtual
|
||||
// registers. This may be used during coalescing to represent a congruence
|
||||
// class, or during register allocation to model liveness of a physical
|
||||
// register.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_LIVEINTERVALUNION_H
|
||||
#define LLVM_CODEGEN_LIVEINTERVALUNION_H
|
||||
|
||||
#include "llvm/ADT/IntervalMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/CodeGen/LiveInterval.h"
|
||||
#include "llvm/CodeGen/SlotIndexes.h"
|
||||
#include <cassert>
|
||||
#include <limits>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class raw_ostream;
|
||||
class TargetRegisterInfo;
|
||||
|
||||
#ifndef NDEBUG
|
||||
// forward declaration
|
||||
template <unsigned Element> class SparseBitVector;
|
||||
|
||||
using LiveVirtRegBitSet = SparseBitVector<128>;
|
||||
#endif
|
||||
|
||||
/// Union of live intervals that are strong candidates for coalescing into a
|
||||
/// single register (either physical or virtual depending on the context). We
|
||||
/// expect the constituent live intervals to be disjoint, although we may
|
||||
/// eventually make exceptions to handle value-based interference.
|
||||
class LiveIntervalUnion {
|
||||
// A set of live virtual register segments that supports fast insertion,
|
||||
// intersection, and removal.
|
||||
// Mapping SlotIndex intervals to virtual register numbers.
|
||||
using LiveSegments = IntervalMap<SlotIndex, LiveInterval*>;
|
||||
|
||||
public:
|
||||
// SegmentIter can advance to the next segment ordered by starting position
|
||||
// which may belong to a different live virtual register. We also must be able
|
||||
// to reach the current segment's containing virtual register.
|
||||
using SegmentIter = LiveSegments::iterator;
|
||||
|
||||
/// Const version of SegmentIter.
|
||||
using ConstSegmentIter = LiveSegments::const_iterator;
|
||||
|
||||
// LiveIntervalUnions share an external allocator.
|
||||
using Allocator = LiveSegments::Allocator;
|
||||
|
||||
private:
|
||||
unsigned Tag = 0; // unique tag for current contents.
|
||||
LiveSegments Segments; // union of virtual reg segments
|
||||
|
||||
public:
|
||||
explicit LiveIntervalUnion(Allocator &a) : Segments(a) {}
|
||||
|
||||
// Iterate over all segments in the union of live virtual registers ordered
|
||||
// by their starting position.
|
||||
SegmentIter begin() { return Segments.begin(); }
|
||||
SegmentIter end() { return Segments.end(); }
|
||||
SegmentIter find(SlotIndex x) { return Segments.find(x); }
|
||||
ConstSegmentIter begin() const { return Segments.begin(); }
|
||||
ConstSegmentIter end() const { return Segments.end(); }
|
||||
ConstSegmentIter find(SlotIndex x) const { return Segments.find(x); }
|
||||
|
||||
bool empty() const { return Segments.empty(); }
|
||||
SlotIndex startIndex() const { return Segments.start(); }
|
||||
SlotIndex endIndex() const { return Segments.stop(); }
|
||||
|
||||
// Provide public access to the underlying map to allow overlap iteration.
|
||||
using Map = LiveSegments;
|
||||
const Map &getMap() const { return Segments; }
|
||||
|
||||
/// getTag - Return an opaque tag representing the current state of the union.
|
||||
unsigned getTag() const { return Tag; }
|
||||
|
||||
/// changedSince - Return true if the union change since getTag returned tag.
|
||||
bool changedSince(unsigned tag) const { return tag != Tag; }
|
||||
|
||||
// Add a live virtual register to this union and merge its segments.
|
||||
void unify(LiveInterval &VirtReg, const LiveRange &Range);
|
||||
|
||||
// Remove a live virtual register's segments from this union.
|
||||
void extract(LiveInterval &VirtReg, const LiveRange &Range);
|
||||
|
||||
// Remove all inserted virtual registers.
|
||||
void clear() { Segments.clear(); ++Tag; }
|
||||
|
||||
// Print union, using TRI to translate register names
|
||||
void print(raw_ostream &OS, const TargetRegisterInfo *TRI) const;
|
||||
|
||||
#ifndef NDEBUG
|
||||
// Verify the live intervals in this union and add them to the visited set.
|
||||
void verify(LiveVirtRegBitSet& VisitedVRegs);
|
||||
#endif
|
||||
|
||||
// Get any virtual register that is assign to this physical unit
|
||||
LiveInterval *getOneVReg() const;
|
||||
|
||||
/// Query interferences between a single live virtual register and a live
|
||||
/// interval union.
|
||||
class Query {
|
||||
const LiveIntervalUnion *LiveUnion = nullptr;
|
||||
const LiveRange *LR = nullptr;
|
||||
LiveRange::const_iterator LRI; ///< current position in LR
|
||||
ConstSegmentIter LiveUnionI; ///< current position in LiveUnion
|
||||
SmallVector<LiveInterval *, 4> InterferingVRegs;
|
||||
bool CheckedFirstInterference = false;
|
||||
bool SeenAllInterferences = false;
|
||||
unsigned Tag = 0;
|
||||
unsigned UserTag = 0;
|
||||
|
||||
// Count the virtual registers in this union that interfere with this
|
||||
// query's live virtual register, up to maxInterferingRegs.
|
||||
unsigned collectInterferingVRegs(unsigned MaxInterferingRegs);
|
||||
|
||||
// Was this virtual register visited during collectInterferingVRegs?
|
||||
bool isSeenInterference(LiveInterval *VirtReg) const;
|
||||
|
||||
public:
|
||||
Query() = default;
|
||||
Query(const LiveRange &LR, const LiveIntervalUnion &LIU)
|
||||
: LiveUnion(&LIU), LR(&LR) {}
|
||||
Query(const Query &) = delete;
|
||||
Query &operator=(const Query &) = delete;
|
||||
|
||||
void reset(unsigned NewUserTag, const LiveRange &NewLR,
|
||||
const LiveIntervalUnion &NewLiveUnion) {
|
||||
LiveUnion = &NewLiveUnion;
|
||||
LR = &NewLR;
|
||||
InterferingVRegs.clear();
|
||||
CheckedFirstInterference = false;
|
||||
SeenAllInterferences = false;
|
||||
Tag = NewLiveUnion.getTag();
|
||||
UserTag = NewUserTag;
|
||||
}
|
||||
|
||||
void init(unsigned NewUserTag, const LiveRange &NewLR,
|
||||
const LiveIntervalUnion &NewLiveUnion) {
|
||||
if (UserTag == NewUserTag && LR == &NewLR && LiveUnion == &NewLiveUnion &&
|
||||
!NewLiveUnion.changedSince(Tag)) {
|
||||
// Retain cached results, e.g. firstInterference.
|
||||
return;
|
||||
}
|
||||
reset(NewUserTag, NewLR, NewLiveUnion);
|
||||
}
|
||||
|
||||
// Does this live virtual register interfere with the union?
|
||||
bool checkInterference() { return collectInterferingVRegs(1); }
|
||||
|
||||
// Vector generated by collectInterferingVRegs.
|
||||
const SmallVectorImpl<LiveInterval *> &interferingVRegs(
|
||||
unsigned MaxInterferingRegs = std::numeric_limits<unsigned>::max()) {
|
||||
if (!SeenAllInterferences || MaxInterferingRegs < InterferingVRegs.size())
|
||||
collectInterferingVRegs(MaxInterferingRegs);
|
||||
return InterferingVRegs;
|
||||
}
|
||||
};
|
||||
|
||||
// Array of LiveIntervalUnions.
|
||||
class Array {
|
||||
unsigned Size = 0;
|
||||
LiveIntervalUnion *LIUs = nullptr;
|
||||
|
||||
public:
|
||||
Array() = default;
|
||||
~Array() { clear(); }
|
||||
|
||||
// Initialize the array to have Size entries.
|
||||
// Reuse an existing allocation if the size matches.
|
||||
void init(LiveIntervalUnion::Allocator&, unsigned Size);
|
||||
|
||||
unsigned size() const { return Size; }
|
||||
|
||||
void clear();
|
||||
|
||||
LiveIntervalUnion& operator[](unsigned idx) {
|
||||
assert(idx < Size && "idx out of bounds");
|
||||
return LIUs[idx];
|
||||
}
|
||||
|
||||
const LiveIntervalUnion& operator[](unsigned Idx) const {
|
||||
assert(Idx < Size && "Idx out of bounds");
|
||||
return LIUs[Idx];
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_LIVEINTERVALUNION_H
|
||||
494
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LiveIntervals.h
vendored
Normal file
494
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LiveIntervals.h
vendored
Normal file
@@ -0,0 +1,494 @@
|
||||
//===- LiveIntervals.h - Live Interval Analysis -----------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
/// \file This file implements the LiveInterval analysis pass. Given some
|
||||
/// numbering of each the machine instructions (in this implementation depth-first
|
||||
/// order) an interval [i, j) is said to be a live interval for register v if
|
||||
/// there is no instruction with number j' > j such that v is live at j' and
|
||||
/// there is no instruction with number i' < i such that v is live at i'. In
|
||||
/// this implementation intervals can have holes, i.e. an interval might look
|
||||
/// like [1,20), [50,65), [1000,1001).
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_LIVEINTERVALS_H
|
||||
#define LLVM_CODEGEN_LIVEINTERVALS_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/IndexedMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/CodeGen/LiveInterval.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/SlotIndexes.h"
|
||||
#include "llvm/CodeGen/TargetRegisterInfo.h"
|
||||
#include "llvm/MC/LaneBitmask.h"
|
||||
#include "llvm/Support/CommandLine.h"
|
||||
#include "llvm/Support/Compiler.h"
|
||||
#include "llvm/Support/ErrorHandling.h"
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
extern cl::opt<bool> UseSegmentSetForPhysRegs;
|
||||
|
||||
class AAResults;
|
||||
class BitVector;
|
||||
class LiveIntervalCalc;
|
||||
class MachineBlockFrequencyInfo;
|
||||
class MachineDominatorTree;
|
||||
class MachineFunction;
|
||||
class MachineInstr;
|
||||
class MachineRegisterInfo;
|
||||
class raw_ostream;
|
||||
class TargetInstrInfo;
|
||||
class VirtRegMap;
|
||||
|
||||
class LiveIntervals : public MachineFunctionPass {
|
||||
MachineFunction* MF;
|
||||
MachineRegisterInfo* MRI;
|
||||
const TargetRegisterInfo* TRI;
|
||||
const TargetInstrInfo* TII;
|
||||
AAResults *AA;
|
||||
SlotIndexes* Indexes;
|
||||
MachineDominatorTree *DomTree = nullptr;
|
||||
LiveIntervalCalc *LICalc = nullptr;
|
||||
|
||||
/// Special pool allocator for VNInfo's (LiveInterval val#).
|
||||
VNInfo::Allocator VNInfoAllocator;
|
||||
|
||||
/// Live interval pointers for all the virtual registers.
|
||||
IndexedMap<LiveInterval*, VirtReg2IndexFunctor> VirtRegIntervals;
|
||||
|
||||
/// Sorted list of instructions with register mask operands. Always use the
|
||||
/// 'r' slot, RegMasks are normal clobbers, not early clobbers.
|
||||
SmallVector<SlotIndex, 8> RegMaskSlots;
|
||||
|
||||
/// This vector is parallel to RegMaskSlots, it holds a pointer to the
|
||||
/// corresponding register mask. This pointer can be recomputed as:
|
||||
///
|
||||
/// MI = Indexes->getInstructionFromIndex(RegMaskSlot[N]);
|
||||
/// unsigned OpNum = findRegMaskOperand(MI);
|
||||
/// RegMaskBits[N] = MI->getOperand(OpNum).getRegMask();
|
||||
///
|
||||
/// This is kept in a separate vector partly because some standard
|
||||
/// libraries don't support lower_bound() with mixed objects, partly to
|
||||
/// improve locality when searching in RegMaskSlots.
|
||||
/// Also see the comment in LiveInterval::find().
|
||||
SmallVector<const uint32_t*, 8> RegMaskBits;
|
||||
|
||||
/// For each basic block number, keep (begin, size) pairs indexing into the
|
||||
/// RegMaskSlots and RegMaskBits arrays.
|
||||
/// Note that basic block numbers may not be layout contiguous, that's why
|
||||
/// we can't just keep track of the first register mask in each basic
|
||||
/// block.
|
||||
SmallVector<std::pair<unsigned, unsigned>, 8> RegMaskBlocks;
|
||||
|
||||
/// Keeps a live range set for each register unit to track fixed physreg
|
||||
/// interference.
|
||||
SmallVector<LiveRange*, 0> RegUnitRanges;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
LiveIntervals();
|
||||
~LiveIntervals() override;
|
||||
|
||||
/// Calculate the spill weight to assign to a single instruction.
|
||||
static float getSpillWeight(bool isDef, bool isUse,
|
||||
const MachineBlockFrequencyInfo *MBFI,
|
||||
const MachineInstr &MI);
|
||||
|
||||
/// Calculate the spill weight to assign to a single instruction.
|
||||
static float getSpillWeight(bool isDef, bool isUse,
|
||||
const MachineBlockFrequencyInfo *MBFI,
|
||||
const MachineBasicBlock *MBB);
|
||||
|
||||
LiveInterval &getInterval(Register Reg) {
|
||||
if (hasInterval(Reg))
|
||||
return *VirtRegIntervals[Reg.id()];
|
||||
|
||||
return createAndComputeVirtRegInterval(Reg);
|
||||
}
|
||||
|
||||
const LiveInterval &getInterval(Register Reg) const {
|
||||
return const_cast<LiveIntervals*>(this)->getInterval(Reg);
|
||||
}
|
||||
|
||||
bool hasInterval(Register Reg) const {
|
||||
return VirtRegIntervals.inBounds(Reg.id()) &&
|
||||
VirtRegIntervals[Reg.id()];
|
||||
}
|
||||
|
||||
/// Interval creation.
|
||||
LiveInterval &createEmptyInterval(Register Reg) {
|
||||
assert(!hasInterval(Reg) && "Interval already exists!");
|
||||
VirtRegIntervals.grow(Reg.id());
|
||||
VirtRegIntervals[Reg.id()] = createInterval(Reg);
|
||||
return *VirtRegIntervals[Reg.id()];
|
||||
}
|
||||
|
||||
LiveInterval &createAndComputeVirtRegInterval(Register Reg) {
|
||||
LiveInterval &LI = createEmptyInterval(Reg);
|
||||
computeVirtRegInterval(LI);
|
||||
return LI;
|
||||
}
|
||||
|
||||
/// Interval removal.
|
||||
void removeInterval(Register Reg) {
|
||||
delete VirtRegIntervals[Reg];
|
||||
VirtRegIntervals[Reg] = nullptr;
|
||||
}
|
||||
|
||||
/// Given a register and an instruction, adds a live segment from that
|
||||
/// instruction to the end of its MBB.
|
||||
LiveInterval::Segment addSegmentToEndOfBlock(Register Reg,
|
||||
MachineInstr &startInst);
|
||||
|
||||
/// After removing some uses of a register, shrink its live range to just
|
||||
/// the remaining uses. This method does not compute reaching defs for new
|
||||
/// uses, and it doesn't remove dead defs.
|
||||
/// Dead PHIDef values are marked as unused. New dead machine instructions
|
||||
/// are added to the dead vector. Returns true if the interval may have been
|
||||
/// separated into multiple connected components.
|
||||
bool shrinkToUses(LiveInterval *li,
|
||||
SmallVectorImpl<MachineInstr*> *dead = nullptr);
|
||||
|
||||
/// Specialized version of
|
||||
/// shrinkToUses(LiveInterval *li, SmallVectorImpl<MachineInstr*> *dead)
|
||||
/// that works on a subregister live range and only looks at uses matching
|
||||
/// the lane mask of the subregister range.
|
||||
/// This may leave the subrange empty which needs to be cleaned up with
|
||||
/// LiveInterval::removeEmptySubranges() afterwards.
|
||||
void shrinkToUses(LiveInterval::SubRange &SR, Register Reg);
|
||||
|
||||
/// Extend the live range \p LR to reach all points in \p Indices. The
|
||||
/// points in the \p Indices array must be jointly dominated by the union
|
||||
/// of the existing defs in \p LR and points in \p Undefs.
|
||||
///
|
||||
/// PHI-defs are added as needed to maintain SSA form.
|
||||
///
|
||||
/// If a SlotIndex in \p Indices is the end index of a basic block, \p LR
|
||||
/// will be extended to be live out of the basic block.
|
||||
/// If a SlotIndex in \p Indices is jointy dominated only by points in
|
||||
/// \p Undefs, the live range will not be extended to that point.
|
||||
///
|
||||
/// See also LiveRangeCalc::extend().
|
||||
void extendToIndices(LiveRange &LR, ArrayRef<SlotIndex> Indices,
|
||||
ArrayRef<SlotIndex> Undefs);
|
||||
|
||||
void extendToIndices(LiveRange &LR, ArrayRef<SlotIndex> Indices) {
|
||||
extendToIndices(LR, Indices, /*Undefs=*/{});
|
||||
}
|
||||
|
||||
/// If \p LR has a live value at \p Kill, prune its live range by removing
|
||||
/// any liveness reachable from Kill. Add live range end points to
|
||||
/// EndPoints such that extendToIndices(LI, EndPoints) will reconstruct the
|
||||
/// value's live range.
|
||||
///
|
||||
/// Calling pruneValue() and extendToIndices() can be used to reconstruct
|
||||
/// SSA form after adding defs to a virtual register.
|
||||
void pruneValue(LiveRange &LR, SlotIndex Kill,
|
||||
SmallVectorImpl<SlotIndex> *EndPoints);
|
||||
|
||||
/// This function should not be used. Its intent is to tell you that you are
|
||||
/// doing something wrong if you call pruneValue directly on a
|
||||
/// LiveInterval. Indeed, you are supposed to call pruneValue on the main
|
||||
/// LiveRange and all the LiveRanges of the subranges if any.
|
||||
LLVM_ATTRIBUTE_UNUSED void pruneValue(LiveInterval &, SlotIndex,
|
||||
SmallVectorImpl<SlotIndex> *) {
|
||||
llvm_unreachable(
|
||||
"Use pruneValue on the main LiveRange and on each subrange");
|
||||
}
|
||||
|
||||
SlotIndexes *getSlotIndexes() const {
|
||||
return Indexes;
|
||||
}
|
||||
|
||||
AAResults *getAliasAnalysis() const {
|
||||
return AA;
|
||||
}
|
||||
|
||||
/// Returns true if the specified machine instr has been removed or was
|
||||
/// never entered in the map.
|
||||
bool isNotInMIMap(const MachineInstr &Instr) const {
|
||||
return !Indexes->hasIndex(Instr);
|
||||
}
|
||||
|
||||
/// Returns the base index of the given instruction.
|
||||
SlotIndex getInstructionIndex(const MachineInstr &Instr) const {
|
||||
return Indexes->getInstructionIndex(Instr);
|
||||
}
|
||||
|
||||
/// Returns the instruction associated with the given index.
|
||||
MachineInstr* getInstructionFromIndex(SlotIndex index) const {
|
||||
return Indexes->getInstructionFromIndex(index);
|
||||
}
|
||||
|
||||
/// Return the first index in the given basic block.
|
||||
SlotIndex getMBBStartIdx(const MachineBasicBlock *mbb) const {
|
||||
return Indexes->getMBBStartIdx(mbb);
|
||||
}
|
||||
|
||||
/// Return the last index in the given basic block.
|
||||
SlotIndex getMBBEndIdx(const MachineBasicBlock *mbb) const {
|
||||
return Indexes->getMBBEndIdx(mbb);
|
||||
}
|
||||
|
||||
bool isLiveInToMBB(const LiveRange &LR,
|
||||
const MachineBasicBlock *mbb) const {
|
||||
return LR.liveAt(getMBBStartIdx(mbb));
|
||||
}
|
||||
|
||||
bool isLiveOutOfMBB(const LiveRange &LR,
|
||||
const MachineBasicBlock *mbb) const {
|
||||
return LR.liveAt(getMBBEndIdx(mbb).getPrevSlot());
|
||||
}
|
||||
|
||||
MachineBasicBlock* getMBBFromIndex(SlotIndex index) const {
|
||||
return Indexes->getMBBFromIndex(index);
|
||||
}
|
||||
|
||||
void insertMBBInMaps(MachineBasicBlock *MBB) {
|
||||
Indexes->insertMBBInMaps(MBB);
|
||||
assert(unsigned(MBB->getNumber()) == RegMaskBlocks.size() &&
|
||||
"Blocks must be added in order.");
|
||||
RegMaskBlocks.push_back(std::make_pair(RegMaskSlots.size(), 0));
|
||||
}
|
||||
|
||||
SlotIndex InsertMachineInstrInMaps(MachineInstr &MI) {
|
||||
return Indexes->insertMachineInstrInMaps(MI);
|
||||
}
|
||||
|
||||
void InsertMachineInstrRangeInMaps(MachineBasicBlock::iterator B,
|
||||
MachineBasicBlock::iterator E) {
|
||||
for (MachineBasicBlock::iterator I = B; I != E; ++I)
|
||||
Indexes->insertMachineInstrInMaps(*I);
|
||||
}
|
||||
|
||||
void RemoveMachineInstrFromMaps(MachineInstr &MI) {
|
||||
Indexes->removeMachineInstrFromMaps(MI);
|
||||
}
|
||||
|
||||
SlotIndex ReplaceMachineInstrInMaps(MachineInstr &MI, MachineInstr &NewMI) {
|
||||
return Indexes->replaceMachineInstrInMaps(MI, NewMI);
|
||||
}
|
||||
|
||||
VNInfo::Allocator& getVNInfoAllocator() { return VNInfoAllocator; }
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
void releaseMemory() override;
|
||||
|
||||
/// Pass entry point; Calculates LiveIntervals.
|
||||
bool runOnMachineFunction(MachineFunction&) override;
|
||||
|
||||
/// Implement the dump method.
|
||||
void print(raw_ostream &O, const Module* = nullptr) const override;
|
||||
|
||||
/// If LI is confined to a single basic block, return a pointer to that
|
||||
/// block. If LI is live in to or out of any block, return NULL.
|
||||
MachineBasicBlock *intervalIsInOneMBB(const LiveInterval &LI) const;
|
||||
|
||||
/// Returns true if VNI is killed by any PHI-def values in LI.
|
||||
/// This may conservatively return true to avoid expensive computations.
|
||||
bool hasPHIKill(const LiveInterval &LI, const VNInfo *VNI) const;
|
||||
|
||||
/// Add kill flags to any instruction that kills a virtual register.
|
||||
void addKillFlags(const VirtRegMap*);
|
||||
|
||||
/// Call this method to notify LiveIntervals that instruction \p MI has been
|
||||
/// moved within a basic block. This will update the live intervals for all
|
||||
/// operands of \p MI. Moves between basic blocks are not supported.
|
||||
///
|
||||
/// \param UpdateFlags Update live intervals for nonallocatable physregs.
|
||||
void handleMove(MachineInstr &MI, bool UpdateFlags = false);
|
||||
|
||||
/// Update intervals of operands of all instructions in the newly
|
||||
/// created bundle specified by \p BundleStart.
|
||||
///
|
||||
/// \param UpdateFlags Update live intervals for nonallocatable physregs.
|
||||
///
|
||||
/// Assumes existing liveness is accurate.
|
||||
/// \pre BundleStart should be the first instruction in the Bundle.
|
||||
/// \pre BundleStart should not have a have SlotIndex as one will be assigned.
|
||||
void handleMoveIntoNewBundle(MachineInstr &BundleStart,
|
||||
bool UpdateFlags = false);
|
||||
|
||||
/// Update live intervals for instructions in a range of iterators. It is
|
||||
/// intended for use after target hooks that may insert or remove
|
||||
/// instructions, and is only efficient for a small number of instructions.
|
||||
///
|
||||
/// OrigRegs is a vector of registers that were originally used by the
|
||||
/// instructions in the range between the two iterators.
|
||||
///
|
||||
/// Currently, the only only changes that are supported are simple removal
|
||||
/// and addition of uses.
|
||||
void repairIntervalsInRange(MachineBasicBlock *MBB,
|
||||
MachineBasicBlock::iterator Begin,
|
||||
MachineBasicBlock::iterator End,
|
||||
ArrayRef<Register> OrigRegs);
|
||||
|
||||
// Register mask functions.
|
||||
//
|
||||
// Machine instructions may use a register mask operand to indicate that a
|
||||
// large number of registers are clobbered by the instruction. This is
|
||||
// typically used for calls.
|
||||
//
|
||||
// For compile time performance reasons, these clobbers are not recorded in
|
||||
// the live intervals for individual physical registers. Instead,
|
||||
// LiveIntervalAnalysis maintains a sorted list of instructions with
|
||||
// register mask operands.
|
||||
|
||||
/// Returns a sorted array of slot indices of all instructions with
|
||||
/// register mask operands.
|
||||
ArrayRef<SlotIndex> getRegMaskSlots() const { return RegMaskSlots; }
|
||||
|
||||
/// Returns a sorted array of slot indices of all instructions with register
|
||||
/// mask operands in the basic block numbered \p MBBNum.
|
||||
ArrayRef<SlotIndex> getRegMaskSlotsInBlock(unsigned MBBNum) const {
|
||||
std::pair<unsigned, unsigned> P = RegMaskBlocks[MBBNum];
|
||||
return getRegMaskSlots().slice(P.first, P.second);
|
||||
}
|
||||
|
||||
/// Returns an array of register mask pointers corresponding to
|
||||
/// getRegMaskSlots().
|
||||
ArrayRef<const uint32_t*> getRegMaskBits() const { return RegMaskBits; }
|
||||
|
||||
/// Returns an array of mask pointers corresponding to
|
||||
/// getRegMaskSlotsInBlock(MBBNum).
|
||||
ArrayRef<const uint32_t*> getRegMaskBitsInBlock(unsigned MBBNum) const {
|
||||
std::pair<unsigned, unsigned> P = RegMaskBlocks[MBBNum];
|
||||
return getRegMaskBits().slice(P.first, P.second);
|
||||
}
|
||||
|
||||
/// Test if \p LI is live across any register mask instructions, and
|
||||
/// compute a bit mask of physical registers that are not clobbered by any
|
||||
/// of them.
|
||||
///
|
||||
/// Returns false if \p LI doesn't cross any register mask instructions. In
|
||||
/// that case, the bit vector is not filled in.
|
||||
bool checkRegMaskInterference(LiveInterval &LI,
|
||||
BitVector &UsableRegs);
|
||||
|
||||
// Register unit functions.
|
||||
//
|
||||
// Fixed interference occurs when MachineInstrs use physregs directly
|
||||
// instead of virtual registers. This typically happens when passing
|
||||
// arguments to a function call, or when instructions require operands in
|
||||
// fixed registers.
|
||||
//
|
||||
// Each physreg has one or more register units, see MCRegisterInfo. We
|
||||
// track liveness per register unit to handle aliasing registers more
|
||||
// efficiently.
|
||||
|
||||
/// Return the live range for register unit \p Unit. It will be computed if
|
||||
/// it doesn't exist.
|
||||
LiveRange &getRegUnit(unsigned Unit) {
|
||||
LiveRange *LR = RegUnitRanges[Unit];
|
||||
if (!LR) {
|
||||
// Compute missing ranges on demand.
|
||||
// Use segment set to speed-up initial computation of the live range.
|
||||
RegUnitRanges[Unit] = LR = new LiveRange(UseSegmentSetForPhysRegs);
|
||||
computeRegUnitRange(*LR, Unit);
|
||||
}
|
||||
return *LR;
|
||||
}
|
||||
|
||||
/// Return the live range for register unit \p Unit if it has already been
|
||||
/// computed, or nullptr if it hasn't been computed yet.
|
||||
LiveRange *getCachedRegUnit(unsigned Unit) {
|
||||
return RegUnitRanges[Unit];
|
||||
}
|
||||
|
||||
const LiveRange *getCachedRegUnit(unsigned Unit) const {
|
||||
return RegUnitRanges[Unit];
|
||||
}
|
||||
|
||||
/// Remove computed live range for register unit \p Unit. Subsequent uses
|
||||
/// should rely on on-demand recomputation.
|
||||
void removeRegUnit(unsigned Unit) {
|
||||
delete RegUnitRanges[Unit];
|
||||
RegUnitRanges[Unit] = nullptr;
|
||||
}
|
||||
|
||||
/// Remove associated live ranges for the register units associated with \p
|
||||
/// Reg. Subsequent uses should rely on on-demand recomputation. \note This
|
||||
/// method can result in inconsistent liveness tracking if multiple phyical
|
||||
/// registers share a regunit, and should be used cautiously.
|
||||
void removeAllRegUnitsForPhysReg(MCRegister Reg) {
|
||||
for (MCRegUnitIterator Units(Reg, TRI); Units.isValid(); ++Units)
|
||||
removeRegUnit(*Units);
|
||||
}
|
||||
|
||||
/// Remove value numbers and related live segments starting at position
|
||||
/// \p Pos that are part of any liverange of physical register \p Reg or one
|
||||
/// of its subregisters.
|
||||
void removePhysRegDefAt(MCRegister Reg, SlotIndex Pos);
|
||||
|
||||
/// Remove value number and related live segments of \p LI and its subranges
|
||||
/// that start at position \p Pos.
|
||||
void removeVRegDefAt(LiveInterval &LI, SlotIndex Pos);
|
||||
|
||||
/// Split separate components in LiveInterval \p LI into separate intervals.
|
||||
void splitSeparateComponents(LiveInterval &LI,
|
||||
SmallVectorImpl<LiveInterval*> &SplitLIs);
|
||||
|
||||
/// For live interval \p LI with correct SubRanges construct matching
|
||||
/// information for the main live range. Expects the main live range to not
|
||||
/// have any segments or value numbers.
|
||||
void constructMainRangeFromSubranges(LiveInterval &LI);
|
||||
|
||||
private:
|
||||
/// Compute live intervals for all virtual registers.
|
||||
void computeVirtRegs();
|
||||
|
||||
/// Compute RegMaskSlots and RegMaskBits.
|
||||
void computeRegMasks();
|
||||
|
||||
/// Walk the values in \p LI and check for dead values:
|
||||
/// - Dead PHIDef values are marked as unused.
|
||||
/// - Dead operands are marked as such.
|
||||
/// - Completely dead machine instructions are added to the \p dead vector
|
||||
/// if it is not nullptr.
|
||||
/// Returns true if any PHI value numbers have been removed which may
|
||||
/// have separated the interval into multiple connected components.
|
||||
bool computeDeadValues(LiveInterval &LI,
|
||||
SmallVectorImpl<MachineInstr*> *dead);
|
||||
|
||||
static LiveInterval *createInterval(Register Reg);
|
||||
|
||||
void printInstrs(raw_ostream &O) const;
|
||||
void dumpInstrs() const;
|
||||
|
||||
void computeLiveInRegUnits();
|
||||
void computeRegUnitRange(LiveRange&, unsigned Unit);
|
||||
bool computeVirtRegInterval(LiveInterval&);
|
||||
|
||||
using ShrinkToUsesWorkList = SmallVector<std::pair<SlotIndex, VNInfo*>, 16>;
|
||||
void extendSegmentsToUses(LiveRange &Segments,
|
||||
ShrinkToUsesWorkList &WorkList, Register Reg,
|
||||
LaneBitmask LaneMask);
|
||||
|
||||
/// Helper function for repairIntervalsInRange(), walks backwards and
|
||||
/// creates/modifies live segments in \p LR to match the operands found.
|
||||
/// Only full operands or operands with subregisters matching \p LaneMask
|
||||
/// are considered.
|
||||
void repairOldRegInRange(MachineBasicBlock::iterator Begin,
|
||||
MachineBasicBlock::iterator End,
|
||||
const SlotIndex endIdx, LiveRange &LR,
|
||||
Register Reg,
|
||||
LaneBitmask LaneMask = LaneBitmask::getAll());
|
||||
|
||||
class HMEditor;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
204
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LivePhysRegs.h
vendored
Normal file
204
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LivePhysRegs.h
vendored
Normal file
@@ -0,0 +1,204 @@
|
||||
//===- llvm/CodeGen/LivePhysRegs.h - Live Physical Register Set -*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
/// \file
|
||||
/// This file implements the LivePhysRegs utility for tracking liveness of
|
||||
/// physical registers. This can be used for ad-hoc liveness tracking after
|
||||
/// register allocation. You can start with the live-ins/live-outs at the
|
||||
/// beginning/end of a block and update the information while walking the
|
||||
/// instructions inside the block. This implementation tracks the liveness on a
|
||||
/// sub-register granularity.
|
||||
///
|
||||
/// We assume that the high bits of a physical super-register are not preserved
|
||||
/// unless the instruction has an implicit-use operand reading the super-
|
||||
/// register.
|
||||
///
|
||||
/// X86 Example:
|
||||
/// %ymm0 = ...
|
||||
/// %xmm0 = ... (Kills %xmm0, all %xmm0s sub-registers, and %ymm0)
|
||||
///
|
||||
/// %ymm0 = ...
|
||||
/// %xmm0 = ..., implicit %ymm0 (%ymm0 and all its sub-registers are alive)
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_LIVEPHYSREGS_H
|
||||
#define LLVM_CODEGEN_LIVEPHYSREGS_H
|
||||
|
||||
#include "llvm/ADT/SparseSet.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/TargetRegisterInfo.h"
|
||||
#include "llvm/MC/MCRegisterInfo.h"
|
||||
#include <cassert>
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MachineInstr;
|
||||
class MachineOperand;
|
||||
class MachineRegisterInfo;
|
||||
class raw_ostream;
|
||||
|
||||
/// A set of physical registers with utility functions to track liveness
|
||||
/// when walking backward/forward through a basic block.
|
||||
class LivePhysRegs {
|
||||
const TargetRegisterInfo *TRI = nullptr;
|
||||
using RegisterSet = SparseSet<MCPhysReg, identity<MCPhysReg>>;
|
||||
RegisterSet LiveRegs;
|
||||
|
||||
public:
|
||||
/// Constructs an uninitialized set. init() needs to be called to initialize it.
|
||||
LivePhysRegs() = default;
|
||||
|
||||
/// Constructs and initializes an empty set.
|
||||
LivePhysRegs(const TargetRegisterInfo &TRI) : TRI(&TRI) {
|
||||
LiveRegs.setUniverse(TRI.getNumRegs());
|
||||
}
|
||||
|
||||
LivePhysRegs(const LivePhysRegs&) = delete;
|
||||
LivePhysRegs &operator=(const LivePhysRegs&) = delete;
|
||||
|
||||
/// (re-)initializes and clears the set.
|
||||
void init(const TargetRegisterInfo &TRI) {
|
||||
this->TRI = &TRI;
|
||||
LiveRegs.clear();
|
||||
LiveRegs.setUniverse(TRI.getNumRegs());
|
||||
}
|
||||
|
||||
/// Clears the set.
|
||||
void clear() { LiveRegs.clear(); }
|
||||
|
||||
/// Returns true if the set is empty.
|
||||
bool empty() const { return LiveRegs.empty(); }
|
||||
|
||||
/// Adds a physical register and all its sub-registers to the set.
|
||||
void addReg(MCPhysReg Reg) {
|
||||
assert(TRI && "LivePhysRegs is not initialized.");
|
||||
assert(Reg <= TRI->getNumRegs() && "Expected a physical register.");
|
||||
for (MCSubRegIterator SubRegs(Reg, TRI, /*IncludeSelf=*/true);
|
||||
SubRegs.isValid(); ++SubRegs)
|
||||
LiveRegs.insert(*SubRegs);
|
||||
}
|
||||
|
||||
/// Removes a physical register, all its sub-registers, and all its
|
||||
/// super-registers from the set.
|
||||
void removeReg(MCPhysReg Reg) {
|
||||
assert(TRI && "LivePhysRegs is not initialized.");
|
||||
assert(Reg <= TRI->getNumRegs() && "Expected a physical register.");
|
||||
for (MCRegAliasIterator R(Reg, TRI, true); R.isValid(); ++R)
|
||||
LiveRegs.erase(*R);
|
||||
}
|
||||
|
||||
/// Removes physical registers clobbered by the regmask operand \p MO.
|
||||
void removeRegsInMask(const MachineOperand &MO,
|
||||
SmallVectorImpl<std::pair<MCPhysReg, const MachineOperand*>> *Clobbers =
|
||||
nullptr);
|
||||
|
||||
/// Returns true if register \p Reg is contained in the set. This also
|
||||
/// works if only the super register of \p Reg has been defined, because
|
||||
/// addReg() always adds all sub-registers to the set as well.
|
||||
/// Note: Returns false if just some sub registers are live, use available()
|
||||
/// when searching a free register.
|
||||
bool contains(MCPhysReg Reg) const { return LiveRegs.count(Reg); }
|
||||
|
||||
/// Returns true if register \p Reg and no aliasing register is in the set.
|
||||
bool available(const MachineRegisterInfo &MRI, MCPhysReg Reg) const;
|
||||
|
||||
/// Remove defined registers and regmask kills from the set.
|
||||
void removeDefs(const MachineInstr &MI);
|
||||
|
||||
/// Add uses to the set.
|
||||
void addUses(const MachineInstr &MI);
|
||||
|
||||
/// Simulates liveness when stepping backwards over an instruction(bundle).
|
||||
/// Remove Defs, add uses. This is the recommended way of calculating
|
||||
/// liveness.
|
||||
void stepBackward(const MachineInstr &MI);
|
||||
|
||||
/// Simulates liveness when stepping forward over an instruction(bundle).
|
||||
/// Remove killed-uses, add defs. This is the not recommended way, because it
|
||||
/// depends on accurate kill flags. If possible use stepBackward() instead of
|
||||
/// this function. The clobbers set will be the list of registers either
|
||||
/// defined or clobbered by a regmask. The operand will identify whether this
|
||||
/// is a regmask or register operand.
|
||||
void stepForward(const MachineInstr &MI,
|
||||
SmallVectorImpl<std::pair<MCPhysReg, const MachineOperand*>> &Clobbers);
|
||||
|
||||
/// Adds all live-in registers of basic block \p MBB.
|
||||
/// Live in registers are the registers in the blocks live-in list and the
|
||||
/// pristine registers.
|
||||
void addLiveIns(const MachineBasicBlock &MBB);
|
||||
|
||||
/// Adds all live-in registers of basic block \p MBB but skips pristine
|
||||
/// registers.
|
||||
void addLiveInsNoPristines(const MachineBasicBlock &MBB);
|
||||
|
||||
/// Adds all live-out registers of basic block \p MBB.
|
||||
/// Live out registers are the union of the live-in registers of the successor
|
||||
/// blocks and pristine registers. Live out registers of the end block are the
|
||||
/// callee saved registers.
|
||||
/// If a register is not added by this method, it is guaranteed to not be
|
||||
/// live out from MBB, although a sub-register may be. This is true
|
||||
/// both before and after regalloc.
|
||||
void addLiveOuts(const MachineBasicBlock &MBB);
|
||||
|
||||
/// Adds all live-out registers of basic block \p MBB but skips pristine
|
||||
/// registers.
|
||||
void addLiveOutsNoPristines(const MachineBasicBlock &MBB);
|
||||
|
||||
using const_iterator = RegisterSet::const_iterator;
|
||||
|
||||
const_iterator begin() const { return LiveRegs.begin(); }
|
||||
const_iterator end() const { return LiveRegs.end(); }
|
||||
|
||||
/// Prints the currently live registers to \p OS.
|
||||
void print(raw_ostream &OS) const;
|
||||
|
||||
/// Dumps the currently live registers to the debug output.
|
||||
void dump() const;
|
||||
|
||||
private:
|
||||
/// Adds live-in registers from basic block \p MBB, taking associated
|
||||
/// lane masks into consideration.
|
||||
void addBlockLiveIns(const MachineBasicBlock &MBB);
|
||||
|
||||
/// Adds pristine registers. Pristine registers are callee saved registers
|
||||
/// that are unused in the function.
|
||||
void addPristines(const MachineFunction &MF);
|
||||
};
|
||||
|
||||
inline raw_ostream &operator<<(raw_ostream &OS, const LivePhysRegs& LR) {
|
||||
LR.print(OS);
|
||||
return OS;
|
||||
}
|
||||
|
||||
/// Computes registers live-in to \p MBB assuming all of its successors
|
||||
/// live-in lists are up-to-date. Puts the result into the given LivePhysReg
|
||||
/// instance \p LiveRegs.
|
||||
void computeLiveIns(LivePhysRegs &LiveRegs, const MachineBasicBlock &MBB);
|
||||
|
||||
/// Recomputes dead and kill flags in \p MBB.
|
||||
void recomputeLivenessFlags(MachineBasicBlock &MBB);
|
||||
|
||||
/// Adds registers contained in \p LiveRegs to the block live-in list of \p MBB.
|
||||
/// Does not add reserved registers.
|
||||
void addLiveIns(MachineBasicBlock &MBB, const LivePhysRegs &LiveRegs);
|
||||
|
||||
/// Convenience function combining computeLiveIns() and addLiveIns().
|
||||
void computeAndAddLiveIns(LivePhysRegs &LiveRegs,
|
||||
MachineBasicBlock &MBB);
|
||||
|
||||
/// Convenience function for recomputing live-in's for \p MBB.
|
||||
static inline void recomputeLiveIns(MachineBasicBlock &MBB) {
|
||||
LivePhysRegs LPR;
|
||||
MBB.clearLiveIns();
|
||||
computeAndAddLiveIns(LPR, MBB);
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_LIVEPHYSREGS_H
|
||||
270
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LiveRangeCalc.h
vendored
Normal file
270
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LiveRangeCalc.h
vendored
Normal file
@@ -0,0 +1,270 @@
|
||||
//===- LiveRangeCalc.h - Calculate live ranges -----------------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LiveRangeCalc class can be used to implement the computation of
|
||||
// live ranges from scratch.
|
||||
// It caches information about values in the CFG to speed up repeated
|
||||
// operations on the same live range. The cache can be shared by
|
||||
// non-overlapping live ranges. SplitKit uses that when computing the live
|
||||
// range of split products.
|
||||
//
|
||||
// A low-level interface is available to clients that know where a variable is
|
||||
// live, but don't know which value it has as every point. LiveRangeCalc will
|
||||
// propagate values down the dominator tree, and even insert PHI-defs where
|
||||
// needed. SplitKit uses this faster interface when possible.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_LIVERANGECALC_H
|
||||
#define LLVM_CODEGEN_LIVERANGECALC_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/IndexedMap.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/CodeGen/LiveInterval.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/SlotIndexes.h"
|
||||
#include "llvm/MC/LaneBitmask.h"
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
template <class NodeT> class DomTreeNodeBase;
|
||||
class MachineDominatorTree;
|
||||
class MachineFunction;
|
||||
class MachineRegisterInfo;
|
||||
|
||||
using MachineDomTreeNode = DomTreeNodeBase<MachineBasicBlock>;
|
||||
|
||||
class LiveRangeCalc {
|
||||
const MachineFunction *MF = nullptr;
|
||||
const MachineRegisterInfo *MRI = nullptr;
|
||||
SlotIndexes *Indexes = nullptr;
|
||||
MachineDominatorTree *DomTree = nullptr;
|
||||
VNInfo::Allocator *Alloc = nullptr;
|
||||
|
||||
/// LiveOutPair - A value and the block that defined it. The domtree node is
|
||||
/// redundant, it can be computed as: MDT[Indexes.getMBBFromIndex(VNI->def)].
|
||||
using LiveOutPair = std::pair<VNInfo *, MachineDomTreeNode *>;
|
||||
|
||||
/// LiveOutMap - Map basic blocks to the value leaving the block.
|
||||
using LiveOutMap = IndexedMap<LiveOutPair, MBB2NumberFunctor>;
|
||||
|
||||
/// Bit vector of active entries in LiveOut, also used as a visited set by
|
||||
/// findReachingDefs. One entry per basic block, indexed by block number.
|
||||
/// This is kept as a separate bit vector because it can be cleared quickly
|
||||
/// when switching live ranges.
|
||||
BitVector Seen;
|
||||
|
||||
/// Map LiveRange to sets of blocks (represented by bit vectors) that
|
||||
/// in the live range are defined on entry and undefined on entry.
|
||||
/// A block is defined on entry if there is a path from at least one of
|
||||
/// the defs in the live range to the entry of the block, and conversely,
|
||||
/// a block is undefined on entry, if there is no such path (i.e. no
|
||||
/// definition reaches the entry of the block). A single LiveRangeCalc
|
||||
/// object is used to track live-out information for multiple registers
|
||||
/// in live range splitting (which is ok, since the live ranges of these
|
||||
/// registers do not overlap), but the defined/undefined information must
|
||||
/// be kept separate for each individual range.
|
||||
/// By convention, EntryInfoMap[&LR] = { Defined, Undefined }.
|
||||
using EntryInfoMap = DenseMap<LiveRange *, std::pair<BitVector, BitVector>>;
|
||||
EntryInfoMap EntryInfos;
|
||||
|
||||
/// Map each basic block where a live range is live out to the live-out value
|
||||
/// and its defining block.
|
||||
///
|
||||
/// For every basic block, MBB, one of these conditions shall be true:
|
||||
///
|
||||
/// 1. !Seen.count(MBB->getNumber())
|
||||
/// Blocks without a Seen bit are ignored.
|
||||
/// 2. LiveOut[MBB].second.getNode() == MBB
|
||||
/// The live-out value is defined in MBB.
|
||||
/// 3. forall P in preds(MBB): LiveOut[P] == LiveOut[MBB]
|
||||
/// The live-out value passses through MBB. All predecessors must carry
|
||||
/// the same value.
|
||||
///
|
||||
/// The domtree node may be null, it can be computed.
|
||||
///
|
||||
/// The map can be shared by multiple live ranges as long as no two are
|
||||
/// live-out of the same block.
|
||||
LiveOutMap Map;
|
||||
|
||||
/// LiveInBlock - Information about a basic block where a live range is known
|
||||
/// to be live-in, but the value has not yet been determined.
|
||||
struct LiveInBlock {
|
||||
// The live range set that is live-in to this block. The algorithms can
|
||||
// handle multiple non-overlapping live ranges simultaneously.
|
||||
LiveRange &LR;
|
||||
|
||||
// DomNode - Dominator tree node for the block.
|
||||
// Cleared when the final value has been determined and LI has been updated.
|
||||
MachineDomTreeNode *DomNode;
|
||||
|
||||
// Position in block where the live-in range ends, or SlotIndex() if the
|
||||
// range passes through the block. When the final value has been
|
||||
// determined, the range from the block start to Kill will be added to LI.
|
||||
SlotIndex Kill;
|
||||
|
||||
// Live-in value filled in by updateSSA once it is known.
|
||||
VNInfo *Value = nullptr;
|
||||
|
||||
LiveInBlock(LiveRange &LR, MachineDomTreeNode *node, SlotIndex kill)
|
||||
: LR(LR), DomNode(node), Kill(kill) {}
|
||||
};
|
||||
|
||||
/// LiveIn - Work list of blocks where the live-in value has yet to be
|
||||
/// determined. This list is typically computed by findReachingDefs() and
|
||||
/// used as a work list by updateSSA(). The low-level interface may also be
|
||||
/// used to add entries directly.
|
||||
SmallVector<LiveInBlock, 16> LiveIn;
|
||||
|
||||
/// Check if the entry to block @p MBB can be reached by any of the defs
|
||||
/// in @p LR. Return true if none of the defs reach the entry to @p MBB.
|
||||
bool isDefOnEntry(LiveRange &LR, ArrayRef<SlotIndex> Undefs,
|
||||
MachineBasicBlock &MBB, BitVector &DefOnEntry,
|
||||
BitVector &UndefOnEntry);
|
||||
|
||||
/// Find the set of defs that can reach @p Kill. @p Kill must belong to
|
||||
/// @p UseMBB.
|
||||
///
|
||||
/// If exactly one def can reach @p UseMBB, and the def dominates @p Kill,
|
||||
/// all paths from the def to @p UseMBB are added to @p LR, and the function
|
||||
/// returns true.
|
||||
///
|
||||
/// If multiple values can reach @p UseMBB, the blocks that need @p LR to be
|
||||
/// live in are added to the LiveIn array, and the function returns false.
|
||||
///
|
||||
/// The array @p Undef provides the locations where the range @p LR becomes
|
||||
/// undefined by <def,read-undef> operands on other subranges. If @p Undef
|
||||
/// is non-empty and @p Kill is jointly dominated only by the entries of
|
||||
/// @p Undef, the function returns false.
|
||||
///
|
||||
/// PhysReg, when set, is used to verify live-in lists on basic blocks.
|
||||
bool findReachingDefs(LiveRange &LR, MachineBasicBlock &UseMBB, SlotIndex Use,
|
||||
unsigned PhysReg, ArrayRef<SlotIndex> Undefs);
|
||||
|
||||
/// updateSSA - Compute the values that will be live in to all requested
|
||||
/// blocks in LiveIn. Create PHI-def values as required to preserve SSA form.
|
||||
///
|
||||
/// Every live-in block must be jointly dominated by the added live-out
|
||||
/// blocks. No values are read from the live ranges.
|
||||
void updateSSA();
|
||||
|
||||
/// Transfer information from the LiveIn vector to the live ranges and update
|
||||
/// the given @p LiveOuts.
|
||||
void updateFromLiveIns();
|
||||
|
||||
protected:
|
||||
/// Some getters to expose in a read-only way some private fields to
|
||||
/// subclasses.
|
||||
const MachineFunction *getMachineFunction() { return MF; }
|
||||
const MachineRegisterInfo *getRegInfo() const { return MRI; }
|
||||
SlotIndexes *getIndexes() { return Indexes; }
|
||||
MachineDominatorTree *getDomTree() { return DomTree; }
|
||||
VNInfo::Allocator *getVNAlloc() { return Alloc; }
|
||||
|
||||
/// Reset Map and Seen fields.
|
||||
void resetLiveOutMap();
|
||||
|
||||
public:
|
||||
LiveRangeCalc() = default;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// High-level interface.
|
||||
//===--------------------------------------------------------------------===//
|
||||
//
|
||||
// Calculate live ranges from scratch.
|
||||
//
|
||||
|
||||
/// reset - Prepare caches for a new set of non-overlapping live ranges. The
|
||||
/// caches must be reset before attempting calculations with a live range
|
||||
/// that may overlap a previously computed live range, and before the first
|
||||
/// live range in a function. If live ranges are not known to be
|
||||
/// non-overlapping, call reset before each.
|
||||
void reset(const MachineFunction *mf, SlotIndexes *SI,
|
||||
MachineDominatorTree *MDT, VNInfo::Allocator *VNIA);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Mid-level interface.
|
||||
//===--------------------------------------------------------------------===//
|
||||
//
|
||||
// Modify existing live ranges.
|
||||
//
|
||||
|
||||
/// Extend the live range of @p LR to reach @p Use.
|
||||
///
|
||||
/// The existing values in @p LR must be live so they jointly dominate @p Use.
|
||||
/// If @p Use is not dominated by a single existing value, PHI-defs are
|
||||
/// inserted as required to preserve SSA form.
|
||||
///
|
||||
/// PhysReg, when set, is used to verify live-in lists on basic blocks.
|
||||
void extend(LiveRange &LR, SlotIndex Use, unsigned PhysReg,
|
||||
ArrayRef<SlotIndex> Undefs);
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Low-level interface.
|
||||
//===--------------------------------------------------------------------===//
|
||||
//
|
||||
// These functions can be used to compute live ranges where the live-in and
|
||||
// live-out blocks are already known, but the SSA value in each block is
|
||||
// unknown.
|
||||
//
|
||||
// After calling reset(), add known live-out values and known live-in blocks.
|
||||
// Then call calculateValues() to compute the actual value that is
|
||||
// live-in to each block, and add liveness to the live ranges.
|
||||
//
|
||||
|
||||
/// setLiveOutValue - Indicate that VNI is live out from MBB. The
|
||||
/// calculateValues() function will not add liveness for MBB, the caller
|
||||
/// should take care of that.
|
||||
///
|
||||
/// VNI may be null only if MBB is a live-through block also passed to
|
||||
/// addLiveInBlock().
|
||||
void setLiveOutValue(MachineBasicBlock *MBB, VNInfo *VNI) {
|
||||
Seen.set(MBB->getNumber());
|
||||
Map[MBB] = LiveOutPair(VNI, nullptr);
|
||||
}
|
||||
|
||||
/// addLiveInBlock - Add a block with an unknown live-in value. This
|
||||
/// function can only be called once per basic block. Once the live-in value
|
||||
/// has been determined, calculateValues() will add liveness to LI.
|
||||
///
|
||||
/// @param LR The live range that is live-in to the block.
|
||||
/// @param DomNode The domtree node for the block.
|
||||
/// @param Kill Index in block where LI is killed. If the value is
|
||||
/// live-through, set Kill = SLotIndex() and also call
|
||||
/// setLiveOutValue(MBB, 0).
|
||||
void addLiveInBlock(LiveRange &LR, MachineDomTreeNode *DomNode,
|
||||
SlotIndex Kill = SlotIndex()) {
|
||||
LiveIn.push_back(LiveInBlock(LR, DomNode, Kill));
|
||||
}
|
||||
|
||||
/// calculateValues - Calculate the value that will be live-in to each block
|
||||
/// added with addLiveInBlock. Add PHI-def values as needed to preserve SSA
|
||||
/// form. Add liveness to all live-in blocks up to the Kill point, or the
|
||||
/// whole block for live-through blocks.
|
||||
///
|
||||
/// Every predecessor of a live-in block must have been given a value with
|
||||
/// setLiveOutValue, the value may be null for live-trough blocks.
|
||||
void calculateValues();
|
||||
|
||||
/// A diagnostic function to check if the end of the block @p MBB is
|
||||
/// jointly dominated by the blocks corresponding to the slot indices
|
||||
/// in @p Defs. This function is mainly for use in self-verification
|
||||
/// checks.
|
||||
LLVM_ATTRIBUTE_UNUSED
|
||||
static bool isJointlyDominated(const MachineBasicBlock *MBB,
|
||||
ArrayRef<SlotIndex> Defs,
|
||||
const SlotIndexes &Indexes);
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_LIVERANGECALC_H
|
||||
255
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LiveRangeEdit.h
vendored
Normal file
255
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LiveRangeEdit.h
vendored
Normal file
@@ -0,0 +1,255 @@
|
||||
//===- LiveRangeEdit.h - Basic tools for split and spill --------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LiveRangeEdit class represents changes done to a virtual register when it
|
||||
// is spilled or split.
|
||||
//
|
||||
// The parent register is never changed. Instead, a number of new virtual
|
||||
// registers are created and added to the newRegs vector.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_LIVERANGEEDIT_H
|
||||
#define LLVM_CODEGEN_LIVERANGEEDIT_H
|
||||
|
||||
#include "llvm/ADT/ArrayRef.h"
|
||||
#include "llvm/ADT/None.h"
|
||||
#include "llvm/ADT/SetVector.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/CodeGen/LiveInterval.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
||||
#include "llvm/CodeGen/SlotIndexes.h"
|
||||
#include "llvm/CodeGen/TargetSubtargetInfo.h"
|
||||
#include <cassert>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class AAResults;
|
||||
class LiveIntervals;
|
||||
class MachineInstr;
|
||||
class MachineOperand;
|
||||
class TargetInstrInfo;
|
||||
class TargetRegisterInfo;
|
||||
class VirtRegMap;
|
||||
class VirtRegAuxInfo;
|
||||
|
||||
class LiveRangeEdit : private MachineRegisterInfo::Delegate {
|
||||
public:
|
||||
/// Callback methods for LiveRangeEdit owners.
|
||||
class Delegate {
|
||||
virtual void anchor();
|
||||
|
||||
public:
|
||||
virtual ~Delegate() = default;
|
||||
|
||||
/// Called immediately before erasing a dead machine instruction.
|
||||
virtual void LRE_WillEraseInstruction(MachineInstr *MI) {}
|
||||
|
||||
/// Called when a virtual register is no longer used. Return false to defer
|
||||
/// its deletion from LiveIntervals.
|
||||
virtual bool LRE_CanEraseVirtReg(Register) { return true; }
|
||||
|
||||
/// Called before shrinking the live range of a virtual register.
|
||||
virtual void LRE_WillShrinkVirtReg(Register) {}
|
||||
|
||||
/// Called after cloning a virtual register.
|
||||
/// This is used for new registers representing connected components of Old.
|
||||
virtual void LRE_DidCloneVirtReg(Register New, Register Old) {}
|
||||
};
|
||||
|
||||
private:
|
||||
LiveInterval *Parent;
|
||||
SmallVectorImpl<Register> &NewRegs;
|
||||
MachineRegisterInfo &MRI;
|
||||
LiveIntervals &LIS;
|
||||
VirtRegMap *VRM;
|
||||
const TargetInstrInfo &TII;
|
||||
Delegate *const TheDelegate;
|
||||
|
||||
/// FirstNew - Index of the first register added to NewRegs.
|
||||
const unsigned FirstNew;
|
||||
|
||||
/// ScannedRemattable - true when remattable values have been identified.
|
||||
bool ScannedRemattable = false;
|
||||
|
||||
/// DeadRemats - The saved instructions which have already been dead after
|
||||
/// rematerialization but not deleted yet -- to be done in postOptimization.
|
||||
SmallPtrSet<MachineInstr *, 32> *DeadRemats;
|
||||
|
||||
/// Remattable - Values defined by remattable instructions as identified by
|
||||
/// tii.isTriviallyReMaterializable().
|
||||
SmallPtrSet<const VNInfo *, 4> Remattable;
|
||||
|
||||
/// Rematted - Values that were actually rematted, and so need to have their
|
||||
/// live range trimmed or entirely removed.
|
||||
SmallPtrSet<const VNInfo *, 4> Rematted;
|
||||
|
||||
/// scanRemattable - Identify the Parent values that may rematerialize.
|
||||
void scanRemattable(AAResults *aa);
|
||||
|
||||
/// foldAsLoad - If LI has a single use and a single def that can be folded as
|
||||
/// a load, eliminate the register by folding the def into the use.
|
||||
bool foldAsLoad(LiveInterval *LI, SmallVectorImpl<MachineInstr *> &Dead);
|
||||
|
||||
using ToShrinkSet = SetVector<LiveInterval *, SmallVector<LiveInterval *, 8>,
|
||||
SmallPtrSet<LiveInterval *, 8>>;
|
||||
|
||||
/// Helper for eliminateDeadDefs.
|
||||
void eliminateDeadDef(MachineInstr *MI, ToShrinkSet &ToShrink,
|
||||
AAResults *AA);
|
||||
|
||||
/// MachineRegisterInfo callback to notify when new virtual
|
||||
/// registers are created.
|
||||
void MRI_NoteNewVirtualRegister(Register VReg) override;
|
||||
|
||||
/// Check if MachineOperand \p MO is a last use/kill either in the
|
||||
/// main live range of \p LI or in one of the matching subregister ranges.
|
||||
bool useIsKill(const LiveInterval &LI, const MachineOperand &MO) const;
|
||||
|
||||
/// Create a new empty interval based on OldReg.
|
||||
LiveInterval &createEmptyIntervalFrom(Register OldReg, bool createSubRanges);
|
||||
|
||||
public:
|
||||
/// Create a LiveRangeEdit for breaking down parent into smaller pieces.
|
||||
/// @param parent The register being spilled or split.
|
||||
/// @param newRegs List to receive any new registers created. This needn't be
|
||||
/// empty initially, any existing registers are ignored.
|
||||
/// @param MF The MachineFunction the live range edit is taking place in.
|
||||
/// @param lis The collection of all live intervals in this function.
|
||||
/// @param vrm Map of virtual registers to physical registers for this
|
||||
/// function. If NULL, no virtual register map updates will
|
||||
/// be done. This could be the case if called before Regalloc.
|
||||
/// @param deadRemats The collection of all the instructions defining an
|
||||
/// original reg and are dead after remat.
|
||||
LiveRangeEdit(LiveInterval *parent, SmallVectorImpl<Register> &newRegs,
|
||||
MachineFunction &MF, LiveIntervals &lis, VirtRegMap *vrm,
|
||||
Delegate *delegate = nullptr,
|
||||
SmallPtrSet<MachineInstr *, 32> *deadRemats = nullptr)
|
||||
: Parent(parent), NewRegs(newRegs), MRI(MF.getRegInfo()), LIS(lis),
|
||||
VRM(vrm), TII(*MF.getSubtarget().getInstrInfo()), TheDelegate(delegate),
|
||||
FirstNew(newRegs.size()), DeadRemats(deadRemats) {
|
||||
MRI.setDelegate(this);
|
||||
}
|
||||
|
||||
~LiveRangeEdit() override { MRI.resetDelegate(this); }
|
||||
|
||||
LiveInterval &getParent() const {
|
||||
assert(Parent && "No parent LiveInterval");
|
||||
return *Parent;
|
||||
}
|
||||
|
||||
Register getReg() const { return getParent().reg(); }
|
||||
|
||||
/// Iterator for accessing the new registers added by this edit.
|
||||
using iterator = SmallVectorImpl<Register>::const_iterator;
|
||||
iterator begin() const { return NewRegs.begin() + FirstNew; }
|
||||
iterator end() const { return NewRegs.end(); }
|
||||
unsigned size() const { return NewRegs.size() - FirstNew; }
|
||||
bool empty() const { return size() == 0; }
|
||||
Register get(unsigned idx) const { return NewRegs[idx + FirstNew]; }
|
||||
|
||||
/// pop_back - It allows LiveRangeEdit users to drop new registers.
|
||||
/// The context is when an original def instruction of a register is
|
||||
/// dead after rematerialization, we still want to keep it for following
|
||||
/// rematerializations. We save the def instruction in DeadRemats,
|
||||
/// and replace the original dst register with a new dummy register so
|
||||
/// the live range of original dst register can be shrunk normally.
|
||||
/// We don't want to allocate phys register for the dummy register, so
|
||||
/// we want to drop it from the NewRegs set.
|
||||
void pop_back() { NewRegs.pop_back(); }
|
||||
|
||||
ArrayRef<Register> regs() const {
|
||||
return makeArrayRef(NewRegs).slice(FirstNew);
|
||||
}
|
||||
|
||||
/// createFrom - Create a new virtual register based on OldReg.
|
||||
Register createFrom(Register OldReg);
|
||||
|
||||
/// create - Create a new register with the same class and original slot as
|
||||
/// parent.
|
||||
LiveInterval &createEmptyInterval() {
|
||||
return createEmptyIntervalFrom(getReg(), true);
|
||||
}
|
||||
|
||||
Register create() { return createFrom(getReg()); }
|
||||
|
||||
/// anyRematerializable - Return true if any parent values may be
|
||||
/// rematerializable.
|
||||
/// This function must be called before any rematerialization is attempted.
|
||||
bool anyRematerializable(AAResults *);
|
||||
|
||||
/// checkRematerializable - Manually add VNI to the list of rematerializable
|
||||
/// values if DefMI may be rematerializable.
|
||||
bool checkRematerializable(VNInfo *VNI, const MachineInstr *DefMI,
|
||||
AAResults *);
|
||||
|
||||
/// Remat - Information needed to rematerialize at a specific location.
|
||||
struct Remat {
|
||||
VNInfo *ParentVNI; // parent_'s value at the remat location.
|
||||
MachineInstr *OrigMI = nullptr; // Instruction defining OrigVNI. It contains
|
||||
// the real expr for remat.
|
||||
|
||||
explicit Remat(VNInfo *ParentVNI) : ParentVNI(ParentVNI) {}
|
||||
};
|
||||
|
||||
/// allUsesAvailableAt - Return true if all registers used by OrigMI at
|
||||
/// OrigIdx are also available with the same value at UseIdx.
|
||||
bool allUsesAvailableAt(const MachineInstr *OrigMI, SlotIndex OrigIdx,
|
||||
SlotIndex UseIdx) const;
|
||||
|
||||
/// canRematerializeAt - Determine if ParentVNI can be rematerialized at
|
||||
/// UseIdx. It is assumed that parent_.getVNINfoAt(UseIdx) == ParentVNI.
|
||||
/// When cheapAsAMove is set, only cheap remats are allowed.
|
||||
bool canRematerializeAt(Remat &RM, VNInfo *OrigVNI, SlotIndex UseIdx,
|
||||
bool cheapAsAMove);
|
||||
|
||||
/// rematerializeAt - Rematerialize RM.ParentVNI into DestReg by inserting an
|
||||
/// instruction into MBB before MI. The new instruction is mapped, but
|
||||
/// liveness is not updated.
|
||||
/// Return the SlotIndex of the new instruction.
|
||||
SlotIndex rematerializeAt(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator MI, unsigned DestReg,
|
||||
const Remat &RM, const TargetRegisterInfo &,
|
||||
bool Late = false);
|
||||
|
||||
/// markRematerialized - explicitly mark a value as rematerialized after doing
|
||||
/// it manually.
|
||||
void markRematerialized(const VNInfo *ParentVNI) {
|
||||
Rematted.insert(ParentVNI);
|
||||
}
|
||||
|
||||
/// didRematerialize - Return true if ParentVNI was rematerialized anywhere.
|
||||
bool didRematerialize(const VNInfo *ParentVNI) const {
|
||||
return Rematted.count(ParentVNI);
|
||||
}
|
||||
|
||||
/// eraseVirtReg - Notify the delegate that Reg is no longer in use, and try
|
||||
/// to erase it from LIS.
|
||||
void eraseVirtReg(Register Reg);
|
||||
|
||||
/// eliminateDeadDefs - Try to delete machine instructions that are now dead
|
||||
/// (allDefsAreDead returns true). This may cause live intervals to be trimmed
|
||||
/// and further dead efs to be eliminated.
|
||||
/// RegsBeingSpilled lists registers currently being spilled by the register
|
||||
/// allocator. These registers should not be split into new intervals
|
||||
/// as currently those new intervals are not guaranteed to spill.
|
||||
void eliminateDeadDefs(SmallVectorImpl<MachineInstr *> &Dead,
|
||||
ArrayRef<Register> RegsBeingSpilled = None,
|
||||
AAResults *AA = nullptr);
|
||||
|
||||
/// calculateRegClassAndHint - Recompute register class and hint for each new
|
||||
/// register.
|
||||
void calculateRegClassAndHint(MachineFunction &, VirtRegAuxInfo &);
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_LIVERANGEEDIT_H
|
||||
162
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LiveRegMatrix.h
vendored
Normal file
162
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LiveRegMatrix.h
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
//===- LiveRegMatrix.h - Track register interference ----------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LiveRegMatrix analysis pass keeps track of virtual register interference
|
||||
// along two dimensions: Slot indexes and register units. The matrix is used by
|
||||
// register allocators to ensure that no interfering virtual registers get
|
||||
// assigned to overlapping physical registers.
|
||||
//
|
||||
// Register units are defined in MCRegisterInfo.h, they represent the smallest
|
||||
// unit of interference when dealing with overlapping physical registers. The
|
||||
// LiveRegMatrix is represented as a LiveIntervalUnion per register unit. When
|
||||
// a virtual register is assigned to a physical register, the live range for
|
||||
// the virtual register is inserted into the LiveIntervalUnion for each regunit
|
||||
// in the physreg.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_LIVEREGMATRIX_H
|
||||
#define LLVM_CODEGEN_LIVEREGMATRIX_H
|
||||
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/CodeGen/LiveIntervalUnion.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include <memory>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class AnalysisUsage;
|
||||
class LiveInterval;
|
||||
class LiveIntervals;
|
||||
class MachineFunction;
|
||||
class TargetRegisterInfo;
|
||||
class VirtRegMap;
|
||||
|
||||
class LiveRegMatrix : public MachineFunctionPass {
|
||||
const TargetRegisterInfo *TRI;
|
||||
LiveIntervals *LIS;
|
||||
VirtRegMap *VRM;
|
||||
|
||||
// UserTag changes whenever virtual registers have been modified.
|
||||
unsigned UserTag = 0;
|
||||
|
||||
// The matrix is represented as a LiveIntervalUnion per register unit.
|
||||
LiveIntervalUnion::Allocator LIUAlloc;
|
||||
LiveIntervalUnion::Array Matrix;
|
||||
|
||||
// Cached queries per register unit.
|
||||
std::unique_ptr<LiveIntervalUnion::Query[]> Queries;
|
||||
|
||||
// Cached register mask interference info.
|
||||
unsigned RegMaskTag = 0;
|
||||
unsigned RegMaskVirtReg = 0;
|
||||
BitVector RegMaskUsable;
|
||||
|
||||
// MachineFunctionPass boilerplate.
|
||||
void getAnalysisUsage(AnalysisUsage &) const override;
|
||||
bool runOnMachineFunction(MachineFunction &) override;
|
||||
void releaseMemory() override;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
LiveRegMatrix();
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// High-level interface.
|
||||
//===--------------------------------------------------------------------===//
|
||||
//
|
||||
// Check for interference before assigning virtual registers to physical
|
||||
// registers.
|
||||
//
|
||||
|
||||
/// Invalidate cached interference queries after modifying virtual register
|
||||
/// live ranges. Interference checks may return stale information unless
|
||||
/// caches are invalidated.
|
||||
void invalidateVirtRegs() { ++UserTag; }
|
||||
|
||||
enum InterferenceKind {
|
||||
/// No interference, go ahead and assign.
|
||||
IK_Free = 0,
|
||||
|
||||
/// Virtual register interference. There are interfering virtual registers
|
||||
/// assigned to PhysReg or its aliases. This interference could be resolved
|
||||
/// by unassigning those other virtual registers.
|
||||
IK_VirtReg,
|
||||
|
||||
/// Register unit interference. A fixed live range is in the way, typically
|
||||
/// argument registers for a call. This can't be resolved by unassigning
|
||||
/// other virtual registers.
|
||||
IK_RegUnit,
|
||||
|
||||
/// RegMask interference. The live range is crossing an instruction with a
|
||||
/// regmask operand that doesn't preserve PhysReg. This typically means
|
||||
/// VirtReg is live across a call, and PhysReg isn't call-preserved.
|
||||
IK_RegMask
|
||||
};
|
||||
|
||||
/// Check for interference before assigning VirtReg to PhysReg.
|
||||
/// If this function returns IK_Free, it is legal to assign(VirtReg, PhysReg).
|
||||
/// When there is more than one kind of interference, the InterferenceKind
|
||||
/// with the highest enum value is returned.
|
||||
InterferenceKind checkInterference(LiveInterval &VirtReg, MCRegister PhysReg);
|
||||
|
||||
/// Check for interference in the segment [Start, End) that may prevent
|
||||
/// assignment to PhysReg. If this function returns true, there is
|
||||
/// interference in the segment [Start, End) of some other interval already
|
||||
/// assigned to PhysReg. If this function returns false, PhysReg is free at
|
||||
/// the segment [Start, End).
|
||||
bool checkInterference(SlotIndex Start, SlotIndex End, MCRegister PhysReg);
|
||||
|
||||
/// Assign VirtReg to PhysReg.
|
||||
/// This will mark VirtReg's live range as occupied in the LiveRegMatrix and
|
||||
/// update VirtRegMap. The live range is expected to be available in PhysReg.
|
||||
void assign(LiveInterval &VirtReg, MCRegister PhysReg);
|
||||
|
||||
/// Unassign VirtReg from its PhysReg.
|
||||
/// Assuming that VirtReg was previously assigned to a PhysReg, this undoes
|
||||
/// the assignment and updates VirtRegMap accordingly.
|
||||
void unassign(LiveInterval &VirtReg);
|
||||
|
||||
/// Returns true if the given \p PhysReg has any live intervals assigned.
|
||||
bool isPhysRegUsed(MCRegister PhysReg) const;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// Low-level interface.
|
||||
//===--------------------------------------------------------------------===//
|
||||
//
|
||||
// Provide access to the underlying LiveIntervalUnions.
|
||||
//
|
||||
|
||||
/// Check for regmask interference only.
|
||||
/// Return true if VirtReg crosses a regmask operand that clobbers PhysReg.
|
||||
/// If PhysReg is null, check if VirtReg crosses any regmask operands.
|
||||
bool checkRegMaskInterference(LiveInterval &VirtReg,
|
||||
MCRegister PhysReg = MCRegister::NoRegister);
|
||||
|
||||
/// Check for regunit interference only.
|
||||
/// Return true if VirtReg overlaps a fixed assignment of one of PhysRegs's
|
||||
/// register units.
|
||||
bool checkRegUnitInterference(LiveInterval &VirtReg, MCRegister PhysReg);
|
||||
|
||||
/// Query a line of the assigned virtual register matrix directly.
|
||||
/// Use MCRegUnitIterator to enumerate all regunits in the desired PhysReg.
|
||||
/// This returns a reference to an internal Query data structure that is only
|
||||
/// valid until the next query() call.
|
||||
LiveIntervalUnion::Query &query(const LiveRange &LR, MCRegister RegUnit);
|
||||
|
||||
/// Directly access the live interval unions per regunit.
|
||||
/// This returns an array indexed by the regunit number.
|
||||
LiveIntervalUnion *getLiveUnions() { return &Matrix[0]; }
|
||||
|
||||
Register getOneVReg(unsigned PhysReg) const;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_LIVEREGMATRIX_H
|
||||
177
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LiveRegUnits.h
vendored
Normal file
177
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LiveRegUnits.h
vendored
Normal file
@@ -0,0 +1,177 @@
|
||||
//===- llvm/CodeGen/LiveRegUnits.h - Register Unit Set ----------*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
/// \file
|
||||
/// A set of register units. It is intended for register liveness tracking.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_LIVEREGUNITS_H
|
||||
#define LLVM_CODEGEN_LIVEREGUNITS_H
|
||||
|
||||
#include "llvm/ADT/BitVector.h"
|
||||
#include "llvm/CodeGen/MachineInstrBundle.h"
|
||||
#include "llvm/CodeGen/TargetRegisterInfo.h"
|
||||
#include "llvm/MC/LaneBitmask.h"
|
||||
#include "llvm/MC/MCRegisterInfo.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MachineInstr;
|
||||
class MachineBasicBlock;
|
||||
|
||||
/// A set of register units used to track register liveness.
|
||||
class LiveRegUnits {
|
||||
const TargetRegisterInfo *TRI = nullptr;
|
||||
BitVector Units;
|
||||
|
||||
public:
|
||||
/// Constructs a new empty LiveRegUnits set.
|
||||
LiveRegUnits() = default;
|
||||
|
||||
/// Constructs and initialize an empty LiveRegUnits set.
|
||||
LiveRegUnits(const TargetRegisterInfo &TRI) {
|
||||
init(TRI);
|
||||
}
|
||||
|
||||
/// For a machine instruction \p MI, adds all register units used in
|
||||
/// \p UsedRegUnits and defined or clobbered in \p ModifiedRegUnits. This is
|
||||
/// useful when walking over a range of instructions to track registers
|
||||
/// used or defined separately.
|
||||
static void accumulateUsedDefed(const MachineInstr &MI,
|
||||
LiveRegUnits &ModifiedRegUnits,
|
||||
LiveRegUnits &UsedRegUnits,
|
||||
const TargetRegisterInfo *TRI) {
|
||||
for (ConstMIBundleOperands O(MI); O.isValid(); ++O) {
|
||||
if (O->isRegMask())
|
||||
ModifiedRegUnits.addRegsInMask(O->getRegMask());
|
||||
if (!O->isReg())
|
||||
continue;
|
||||
Register Reg = O->getReg();
|
||||
if (!Reg.isPhysical())
|
||||
continue;
|
||||
if (O->isDef()) {
|
||||
// Some architectures (e.g. AArch64 XZR/WZR) have registers that are
|
||||
// constant and may be used as destinations to indicate the generated
|
||||
// value is discarded. No need to track such case as a def.
|
||||
if (!TRI->isConstantPhysReg(Reg))
|
||||
ModifiedRegUnits.addReg(Reg);
|
||||
} else {
|
||||
assert(O->isUse() && "Reg operand not a def and not a use");
|
||||
UsedRegUnits.addReg(Reg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Initialize and clear the set.
|
||||
void init(const TargetRegisterInfo &TRI) {
|
||||
this->TRI = &TRI;
|
||||
Units.reset();
|
||||
Units.resize(TRI.getNumRegUnits());
|
||||
}
|
||||
|
||||
/// Clears the set.
|
||||
void clear() { Units.reset(); }
|
||||
|
||||
/// Returns true if the set is empty.
|
||||
bool empty() const { return Units.none(); }
|
||||
|
||||
/// Adds register units covered by physical register \p Reg.
|
||||
void addReg(MCPhysReg Reg) {
|
||||
for (MCRegUnitIterator Unit(Reg, TRI); Unit.isValid(); ++Unit)
|
||||
Units.set(*Unit);
|
||||
}
|
||||
|
||||
/// Adds register units covered by physical register \p Reg that are
|
||||
/// part of the lanemask \p Mask.
|
||||
void addRegMasked(MCPhysReg Reg, LaneBitmask Mask) {
|
||||
for (MCRegUnitMaskIterator Unit(Reg, TRI); Unit.isValid(); ++Unit) {
|
||||
LaneBitmask UnitMask = (*Unit).second;
|
||||
if (UnitMask.none() || (UnitMask & Mask).any())
|
||||
Units.set((*Unit).first);
|
||||
}
|
||||
}
|
||||
|
||||
/// Removes all register units covered by physical register \p Reg.
|
||||
void removeReg(MCPhysReg Reg) {
|
||||
for (MCRegUnitIterator Unit(Reg, TRI); Unit.isValid(); ++Unit)
|
||||
Units.reset(*Unit);
|
||||
}
|
||||
|
||||
/// Removes register units not preserved by the regmask \p RegMask.
|
||||
/// The regmask has the same format as the one in the RegMask machine operand.
|
||||
void removeRegsNotPreserved(const uint32_t *RegMask);
|
||||
|
||||
/// Adds register units not preserved by the regmask \p RegMask.
|
||||
/// The regmask has the same format as the one in the RegMask machine operand.
|
||||
void addRegsInMask(const uint32_t *RegMask);
|
||||
|
||||
/// Returns true if no part of physical register \p Reg is live.
|
||||
bool available(MCPhysReg Reg) const {
|
||||
for (MCRegUnitIterator Unit(Reg, TRI); Unit.isValid(); ++Unit) {
|
||||
if (Units.test(*Unit))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Updates liveness when stepping backwards over the instruction \p MI.
|
||||
/// This removes all register units defined or clobbered in \p MI and then
|
||||
/// adds the units used (as in use operands) in \p MI.
|
||||
void stepBackward(const MachineInstr &MI);
|
||||
|
||||
/// Adds all register units used, defined or clobbered in \p MI.
|
||||
/// This is useful when walking over a range of instruction to find registers
|
||||
/// unused over the whole range.
|
||||
void accumulate(const MachineInstr &MI);
|
||||
|
||||
/// Adds registers living out of block \p MBB.
|
||||
/// Live out registers are the union of the live-in registers of the successor
|
||||
/// blocks and pristine registers. Live out registers of the end block are the
|
||||
/// callee saved registers.
|
||||
void addLiveOuts(const MachineBasicBlock &MBB);
|
||||
|
||||
/// Adds registers living into block \p MBB.
|
||||
void addLiveIns(const MachineBasicBlock &MBB);
|
||||
|
||||
/// Adds all register units marked in the bitvector \p RegUnits.
|
||||
void addUnits(const BitVector &RegUnits) {
|
||||
Units |= RegUnits;
|
||||
}
|
||||
/// Removes all register units marked in the bitvector \p RegUnits.
|
||||
void removeUnits(const BitVector &RegUnits) {
|
||||
Units.reset(RegUnits);
|
||||
}
|
||||
/// Return the internal bitvector representation of the set.
|
||||
const BitVector &getBitVector() const {
|
||||
return Units;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Adds pristine registers. Pristine registers are callee saved registers
|
||||
/// that are unused in the function.
|
||||
void addPristines(const MachineFunction &MF);
|
||||
};
|
||||
|
||||
/// Returns an iterator range over all physical register and mask operands for
|
||||
/// \p MI and bundled instructions. This also skips any debug operands.
|
||||
inline iterator_range<filter_iterator<
|
||||
ConstMIBundleOperands, std::function<bool(const MachineOperand &)>>>
|
||||
phys_regs_and_masks(const MachineInstr &MI) {
|
||||
std::function<bool(const MachineOperand &)> Pred =
|
||||
[](const MachineOperand &MOP) {
|
||||
return MOP.isRegMask() || (MOP.isReg() && !MOP.isDebug() &&
|
||||
Register::isPhysicalRegister(MOP.getReg()));
|
||||
};
|
||||
return make_filter_range(const_mi_bundle_ops(MI), Pred);
|
||||
}
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_LIVEREGUNITS_H
|
||||
103
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LiveStacks.h
vendored
Normal file
103
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LiveStacks.h
vendored
Normal file
@@ -0,0 +1,103 @@
|
||||
//===- LiveStacks.h - Live Stack Slot Analysis ------------------*- 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 file implements the live stack slot analysis pass. It is analogous to
|
||||
// live interval analysis except it's analyzing liveness of stack slots rather
|
||||
// than registers.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_LIVESTACKS_H
|
||||
#define LLVM_CODEGEN_LIVESTACKS_H
|
||||
|
||||
#include "llvm/CodeGen/LiveInterval.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/InitializePasses.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include <cassert>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class TargetRegisterClass;
|
||||
class TargetRegisterInfo;
|
||||
|
||||
class LiveStacks : public MachineFunctionPass {
|
||||
const TargetRegisterInfo *TRI;
|
||||
|
||||
/// Special pool allocator for VNInfo's (LiveInterval val#).
|
||||
///
|
||||
VNInfo::Allocator VNInfoAllocator;
|
||||
|
||||
/// S2IMap - Stack slot indices to live interval mapping.
|
||||
using SS2IntervalMap = std::unordered_map<int, LiveInterval>;
|
||||
SS2IntervalMap S2IMap;
|
||||
|
||||
/// S2RCMap - Stack slot indices to register class mapping.
|
||||
std::map<int, const TargetRegisterClass *> S2RCMap;
|
||||
|
||||
public:
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
|
||||
LiveStacks() : MachineFunctionPass(ID) {
|
||||
initializeLiveStacksPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
using iterator = SS2IntervalMap::iterator;
|
||||
using const_iterator = SS2IntervalMap::const_iterator;
|
||||
|
||||
const_iterator begin() const { return S2IMap.begin(); }
|
||||
const_iterator end() const { return S2IMap.end(); }
|
||||
iterator begin() { return S2IMap.begin(); }
|
||||
iterator end() { return S2IMap.end(); }
|
||||
|
||||
unsigned getNumIntervals() const { return (unsigned)S2IMap.size(); }
|
||||
|
||||
LiveInterval &getOrCreateInterval(int Slot, const TargetRegisterClass *RC);
|
||||
|
||||
LiveInterval &getInterval(int Slot) {
|
||||
assert(Slot >= 0 && "Spill slot indice must be >= 0");
|
||||
SS2IntervalMap::iterator I = S2IMap.find(Slot);
|
||||
assert(I != S2IMap.end() && "Interval does not exist for stack slot");
|
||||
return I->second;
|
||||
}
|
||||
|
||||
const LiveInterval &getInterval(int Slot) const {
|
||||
assert(Slot >= 0 && "Spill slot indice must be >= 0");
|
||||
SS2IntervalMap::const_iterator I = S2IMap.find(Slot);
|
||||
assert(I != S2IMap.end() && "Interval does not exist for stack slot");
|
||||
return I->second;
|
||||
}
|
||||
|
||||
bool hasInterval(int Slot) const { return S2IMap.count(Slot); }
|
||||
|
||||
const TargetRegisterClass *getIntervalRegClass(int Slot) const {
|
||||
assert(Slot >= 0 && "Spill slot indice must be >= 0");
|
||||
std::map<int, const TargetRegisterClass *>::const_iterator I =
|
||||
S2RCMap.find(Slot);
|
||||
assert(I != S2RCMap.end() &&
|
||||
"Register class info does not exist for stack slot");
|
||||
return I->second;
|
||||
}
|
||||
|
||||
VNInfo::Allocator &getVNInfoAllocator() { return VNInfoAllocator; }
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
void releaseMemory() override;
|
||||
|
||||
/// runOnMachineFunction - pass entry point
|
||||
bool runOnMachineFunction(MachineFunction &) override;
|
||||
|
||||
/// print - Implement the dump method.
|
||||
void print(raw_ostream &O, const Module * = nullptr) const override;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
320
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LiveVariables.h
vendored
Normal file
320
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LiveVariables.h
vendored
Normal file
@@ -0,0 +1,320 @@
|
||||
//===-- llvm/CodeGen/LiveVariables.h - Live Variable Analysis ---*- 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 file implements the LiveVariables analysis pass. For each machine
|
||||
// instruction in the function, this pass calculates the set of registers that
|
||||
// are immediately dead after the instruction (i.e., the instruction calculates
|
||||
// the value, but it is never used) and the set of registers that are used by
|
||||
// the instruction, but are never used after the instruction (i.e., they are
|
||||
// killed).
|
||||
//
|
||||
// This class computes live variables using a sparse implementation based on
|
||||
// the machine code SSA form. This class computes live variable information for
|
||||
// each virtual and _register allocatable_ physical register in a function. It
|
||||
// uses the dominance properties of SSA form to efficiently compute live
|
||||
// variables for virtual registers, and assumes that physical registers are only
|
||||
// live within a single basic block (allowing it to do a single local analysis
|
||||
// to resolve physical register lifetimes in each basic block). If a physical
|
||||
// register is not register allocatable, it is not tracked. This is useful for
|
||||
// things like the stack pointer and condition codes.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_LIVEVARIABLES_H
|
||||
#define LLVM_CODEGEN_LIVEVARIABLES_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/IndexedMap.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/SparseBitVector.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
#include "llvm/CodeGen/TargetRegisterInfo.h"
|
||||
#include "llvm/InitializePasses.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MachineBasicBlock;
|
||||
class MachineRegisterInfo;
|
||||
|
||||
class LiveVariables : public MachineFunctionPass {
|
||||
public:
|
||||
static char ID; // Pass identification, replacement for typeid
|
||||
LiveVariables() : MachineFunctionPass(ID) {
|
||||
initializeLiveVariablesPass(*PassRegistry::getPassRegistry());
|
||||
}
|
||||
|
||||
/// VarInfo - This represents the regions where a virtual register is live in
|
||||
/// the program. We represent this with three different pieces of
|
||||
/// information: the set of blocks in which the instruction is live
|
||||
/// throughout, the set of blocks in which the instruction is actually used,
|
||||
/// and the set of non-phi instructions that are the last users of the value.
|
||||
///
|
||||
/// In the common case where a value is defined and killed in the same block,
|
||||
/// There is one killing instruction, and AliveBlocks is empty.
|
||||
///
|
||||
/// Otherwise, the value is live out of the block. If the value is live
|
||||
/// throughout any blocks, these blocks are listed in AliveBlocks. Blocks
|
||||
/// where the liveness range ends are not included in AliveBlocks, instead
|
||||
/// being captured by the Kills set. In these blocks, the value is live into
|
||||
/// the block (unless the value is defined and killed in the same block) and
|
||||
/// lives until the specified instruction. Note that there cannot ever be a
|
||||
/// value whose Kills set contains two instructions from the same basic block.
|
||||
///
|
||||
/// PHI nodes complicate things a bit. If a PHI node is the last user of a
|
||||
/// value in one of its predecessor blocks, it is not listed in the kills set,
|
||||
/// but does include the predecessor block in the AliveBlocks set (unless that
|
||||
/// block also defines the value). This leads to the (perfectly sensical)
|
||||
/// situation where a value is defined in a block, and the last use is a phi
|
||||
/// node in the successor. In this case, AliveBlocks is empty (the value is
|
||||
/// not live across any blocks) and Kills is empty (phi nodes are not
|
||||
/// included). This is sensical because the value must be live to the end of
|
||||
/// the block, but is not live in any successor blocks.
|
||||
struct VarInfo {
|
||||
/// AliveBlocks - Set of blocks in which this value is alive completely
|
||||
/// through. This is a bit set which uses the basic block number as an
|
||||
/// index.
|
||||
///
|
||||
SparseBitVector<> AliveBlocks;
|
||||
|
||||
/// Kills - List of MachineInstruction's which are the last use of this
|
||||
/// virtual register (kill it) in their basic block.
|
||||
///
|
||||
std::vector<MachineInstr*> Kills;
|
||||
|
||||
/// removeKill - Delete a kill corresponding to the specified
|
||||
/// machine instruction. Returns true if there was a kill
|
||||
/// corresponding to this instruction, false otherwise.
|
||||
bool removeKill(MachineInstr &MI) {
|
||||
std::vector<MachineInstr *>::iterator I = find(Kills, &MI);
|
||||
if (I == Kills.end())
|
||||
return false;
|
||||
Kills.erase(I);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// findKill - Find a kill instruction in MBB. Return NULL if none is found.
|
||||
MachineInstr *findKill(const MachineBasicBlock *MBB) const;
|
||||
|
||||
/// isLiveIn - Is Reg live in to MBB? This means that Reg is live through
|
||||
/// MBB, or it is killed in MBB. If Reg is only used by PHI instructions in
|
||||
/// MBB, it is not considered live in.
|
||||
bool isLiveIn(const MachineBasicBlock &MBB, Register Reg,
|
||||
MachineRegisterInfo &MRI);
|
||||
|
||||
void dump() const;
|
||||
};
|
||||
|
||||
private:
|
||||
/// VirtRegInfo - This list is a mapping from virtual register number to
|
||||
/// variable information.
|
||||
///
|
||||
IndexedMap<VarInfo, VirtReg2IndexFunctor> VirtRegInfo;
|
||||
|
||||
/// PHIJoins - list of virtual registers that are PHI joins. These registers
|
||||
/// may have multiple definitions, and they require special handling when
|
||||
/// building live intervals.
|
||||
SparseBitVector<> PHIJoins;
|
||||
|
||||
private: // Intermediate data structures
|
||||
MachineFunction *MF;
|
||||
|
||||
MachineRegisterInfo* MRI;
|
||||
|
||||
const TargetRegisterInfo *TRI;
|
||||
|
||||
// PhysRegInfo - Keep track of which instruction was the last def of a
|
||||
// physical register. This is a purely local property, because all physical
|
||||
// register references are presumed dead across basic blocks.
|
||||
std::vector<MachineInstr *> PhysRegDef;
|
||||
|
||||
// PhysRegInfo - Keep track of which instruction was the last use of a
|
||||
// physical register. This is a purely local property, because all physical
|
||||
// register references are presumed dead across basic blocks.
|
||||
std::vector<MachineInstr *> PhysRegUse;
|
||||
|
||||
std::vector<SmallVector<unsigned, 4>> PHIVarInfo;
|
||||
|
||||
// DistanceMap - Keep track the distance of a MI from the start of the
|
||||
// current basic block.
|
||||
DenseMap<MachineInstr*, unsigned> DistanceMap;
|
||||
|
||||
/// HandlePhysRegKill - Add kills of Reg and its sub-registers to the
|
||||
/// uses. Pay special attention to the sub-register uses which may come below
|
||||
/// the last use of the whole register.
|
||||
bool HandlePhysRegKill(Register Reg, MachineInstr *MI);
|
||||
|
||||
/// HandleRegMask - Call HandlePhysRegKill for all registers clobbered by Mask.
|
||||
void HandleRegMask(const MachineOperand&);
|
||||
|
||||
void HandlePhysRegUse(Register Reg, MachineInstr &MI);
|
||||
void HandlePhysRegDef(Register Reg, MachineInstr *MI,
|
||||
SmallVectorImpl<unsigned> &Defs);
|
||||
void UpdatePhysRegDefs(MachineInstr &MI, SmallVectorImpl<unsigned> &Defs);
|
||||
|
||||
/// FindLastRefOrPartRef - Return the last reference or partial reference of
|
||||
/// the specified register.
|
||||
MachineInstr *FindLastRefOrPartRef(Register Reg);
|
||||
|
||||
/// FindLastPartialDef - Return the last partial def of the specified
|
||||
/// register. Also returns the sub-registers that're defined by the
|
||||
/// instruction.
|
||||
MachineInstr *FindLastPartialDef(Register Reg,
|
||||
SmallSet<unsigned, 4> &PartDefRegs);
|
||||
|
||||
/// analyzePHINodes - Gather information about the PHI nodes in here. In
|
||||
/// particular, we want to map the variable information of a virtual
|
||||
/// register which is used in a PHI node. We map that to the BB the vreg
|
||||
/// is coming from.
|
||||
void analyzePHINodes(const MachineFunction& Fn);
|
||||
|
||||
void runOnInstr(MachineInstr &MI, SmallVectorImpl<unsigned> &Defs);
|
||||
|
||||
void runOnBlock(MachineBasicBlock *MBB, unsigned NumRegs);
|
||||
public:
|
||||
|
||||
bool runOnMachineFunction(MachineFunction &MF) override;
|
||||
|
||||
/// RegisterDefIsDead - Return true if the specified instruction defines the
|
||||
/// specified register, but that definition is dead.
|
||||
bool RegisterDefIsDead(MachineInstr &MI, Register Reg) const;
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
// API to update live variable information
|
||||
|
||||
/// Recompute liveness from scratch for a virtual register \p Reg that is
|
||||
/// known to have a single def that dominates all uses. This can be useful
|
||||
/// after removing some uses of \p Reg. It is not necessary for the whole
|
||||
/// machine function to be in SSA form.
|
||||
void recomputeForSingleDefVirtReg(Register Reg);
|
||||
|
||||
/// replaceKillInstruction - Update register kill info by replacing a kill
|
||||
/// instruction with a new one.
|
||||
void replaceKillInstruction(Register Reg, MachineInstr &OldMI,
|
||||
MachineInstr &NewMI);
|
||||
|
||||
/// addVirtualRegisterKilled - Add information about the fact that the
|
||||
/// specified register is killed after being used by the specified
|
||||
/// instruction. If AddIfNotFound is true, add a implicit operand if it's
|
||||
/// not found.
|
||||
void addVirtualRegisterKilled(Register IncomingReg, MachineInstr &MI,
|
||||
bool AddIfNotFound = false) {
|
||||
if (MI.addRegisterKilled(IncomingReg, TRI, AddIfNotFound))
|
||||
getVarInfo(IncomingReg).Kills.push_back(&MI);
|
||||
}
|
||||
|
||||
/// removeVirtualRegisterKilled - Remove the specified kill of the virtual
|
||||
/// register from the live variable information. Returns true if the
|
||||
/// variable was marked as killed by the specified instruction,
|
||||
/// false otherwise.
|
||||
bool removeVirtualRegisterKilled(Register Reg, MachineInstr &MI) {
|
||||
if (!getVarInfo(Reg).removeKill(MI))
|
||||
return false;
|
||||
|
||||
bool Removed = false;
|
||||
for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) {
|
||||
MachineOperand &MO = MI.getOperand(i);
|
||||
if (MO.isReg() && MO.isKill() && MO.getReg() == Reg) {
|
||||
MO.setIsKill(false);
|
||||
Removed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
assert(Removed && "Register is not used by this instruction!");
|
||||
(void)Removed;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// removeVirtualRegistersKilled - Remove all killed info for the specified
|
||||
/// instruction.
|
||||
void removeVirtualRegistersKilled(MachineInstr &MI);
|
||||
|
||||
/// addVirtualRegisterDead - Add information about the fact that the specified
|
||||
/// register is dead after being used by the specified instruction. If
|
||||
/// AddIfNotFound is true, add a implicit operand if it's not found.
|
||||
void addVirtualRegisterDead(Register IncomingReg, MachineInstr &MI,
|
||||
bool AddIfNotFound = false) {
|
||||
if (MI.addRegisterDead(IncomingReg, TRI, AddIfNotFound))
|
||||
getVarInfo(IncomingReg).Kills.push_back(&MI);
|
||||
}
|
||||
|
||||
/// removeVirtualRegisterDead - Remove the specified kill of the virtual
|
||||
/// register from the live variable information. Returns true if the
|
||||
/// variable was marked dead at the specified instruction, false
|
||||
/// otherwise.
|
||||
bool removeVirtualRegisterDead(Register Reg, MachineInstr &MI) {
|
||||
if (!getVarInfo(Reg).removeKill(MI))
|
||||
return false;
|
||||
|
||||
bool Removed = false;
|
||||
for (unsigned i = 0, e = MI.getNumOperands(); i != e; ++i) {
|
||||
MachineOperand &MO = MI.getOperand(i);
|
||||
if (MO.isReg() && MO.isDef() && MO.getReg() == Reg) {
|
||||
MO.setIsDead(false);
|
||||
Removed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(Removed && "Register is not defined by this instruction!");
|
||||
(void)Removed;
|
||||
return true;
|
||||
}
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
void releaseMemory() override {
|
||||
VirtRegInfo.clear();
|
||||
}
|
||||
|
||||
/// getVarInfo - Return the VarInfo structure for the specified VIRTUAL
|
||||
/// register.
|
||||
VarInfo &getVarInfo(Register Reg);
|
||||
|
||||
void MarkVirtRegAliveInBlock(VarInfo& VRInfo, MachineBasicBlock* DefBlock,
|
||||
MachineBasicBlock *BB);
|
||||
void MarkVirtRegAliveInBlock(VarInfo &VRInfo, MachineBasicBlock *DefBlock,
|
||||
MachineBasicBlock *BB,
|
||||
SmallVectorImpl<MachineBasicBlock *> &WorkList);
|
||||
|
||||
void HandleVirtRegDef(Register reg, MachineInstr &MI);
|
||||
void HandleVirtRegUse(Register reg, MachineBasicBlock *MBB, MachineInstr &MI);
|
||||
|
||||
bool isLiveIn(Register Reg, const MachineBasicBlock &MBB) {
|
||||
return getVarInfo(Reg).isLiveIn(MBB, Reg, *MRI);
|
||||
}
|
||||
|
||||
/// isLiveOut - Determine if Reg is live out from MBB, when not considering
|
||||
/// PHI nodes. This means that Reg is either killed by a successor block or
|
||||
/// passed through one.
|
||||
bool isLiveOut(Register Reg, const MachineBasicBlock &MBB);
|
||||
|
||||
/// addNewBlock - Add a new basic block BB between DomBB and SuccBB. All
|
||||
/// variables that are live out of DomBB and live into SuccBB will be marked
|
||||
/// as passing live through BB. This method assumes that the machine code is
|
||||
/// still in SSA form.
|
||||
void addNewBlock(MachineBasicBlock *BB,
|
||||
MachineBasicBlock *DomBB,
|
||||
MachineBasicBlock *SuccBB);
|
||||
|
||||
void addNewBlock(MachineBasicBlock *BB,
|
||||
MachineBasicBlock *DomBB,
|
||||
MachineBasicBlock *SuccBB,
|
||||
std::vector<SparseBitVector<>> &LiveInSets);
|
||||
|
||||
/// isPHIJoin - Return true if Reg is a phi join register.
|
||||
bool isPHIJoin(Register Reg) { return PHIJoins.test(Reg.id()); }
|
||||
|
||||
/// setPHIJoin - Mark Reg as a phi join register.
|
||||
void setPHIJoin(Register Reg) { PHIJoins.set(Reg.id()); }
|
||||
};
|
||||
|
||||
} // End llvm namespace
|
||||
|
||||
#endif
|
||||
115
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LoopTraversal.h
vendored
Normal file
115
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LoopTraversal.h
vendored
Normal file
@@ -0,0 +1,115 @@
|
||||
//==------ llvm/CodeGen/LoopTraversal.h - Loop Traversal -*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
/// \file Loop Traversal logic.
|
||||
///
|
||||
/// This class provides the basic blocks traversal order used by passes like
|
||||
/// ReachingDefAnalysis and ExecutionDomainFix.
|
||||
/// It identifies basic blocks that are part of loops and should to be visited
|
||||
/// twice and returns efficient traversal order for all the blocks.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_LOOPTRAVERSAL_H
|
||||
#define LLVM_CODEGEN_LOOPTRAVERSAL_H
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MachineBasicBlock;
|
||||
class MachineFunction;
|
||||
|
||||
/// This class provides the basic blocks traversal order used by passes like
|
||||
/// ReachingDefAnalysis and ExecutionDomainFix.
|
||||
/// It identifies basic blocks that are part of loops and should to be visited
|
||||
/// twice and returns efficient traversal order for all the blocks.
|
||||
///
|
||||
/// We want to visit every instruction in every basic block in order to update
|
||||
/// it's execution domain or collect clearance information. However, for the
|
||||
/// clearance calculation, we need to know clearances from all predecessors
|
||||
/// (including any backedges), therefore we need to visit some blocks twice.
|
||||
/// As an example, consider the following loop.
|
||||
///
|
||||
///
|
||||
/// PH -> A -> B (xmm<Undef> -> xmm<Def>) -> C -> D -> EXIT
|
||||
/// ^ |
|
||||
/// +----------------------------------+
|
||||
///
|
||||
/// The iteration order this pass will return is as follows:
|
||||
/// Optimized: PH A B C A' B' C' D
|
||||
///
|
||||
/// The basic block order is constructed as follows:
|
||||
/// Once we finish processing some block, we update the counters in MBBInfos
|
||||
/// and re-process any successors that are now 'done'.
|
||||
/// We call a block that is ready for its final round of processing `done`
|
||||
/// (isBlockDone), e.g. when all predecessor information is known.
|
||||
///
|
||||
/// Note that a naive traversal order would be to do two complete passes over
|
||||
/// all basic blocks/instructions, the first for recording clearances, the
|
||||
/// second for updating clearance based on backedges.
|
||||
/// However, for functions without backedges, or functions with a lot of
|
||||
/// straight-line code, and a small loop, that would be a lot of unnecessary
|
||||
/// work (since only the BBs that are part of the loop require two passes).
|
||||
///
|
||||
/// E.g., the naive iteration order for the above example is as follows:
|
||||
/// Naive: PH A B C D A' B' C' D'
|
||||
///
|
||||
/// In the optimized approach we avoid processing D twice, because we
|
||||
/// can entirely process the predecessors before getting to D.
|
||||
class LoopTraversal {
|
||||
private:
|
||||
struct MBBInfo {
|
||||
/// Whether we have gotten to this block in primary processing yet.
|
||||
bool PrimaryCompleted = false;
|
||||
|
||||
/// The number of predecessors for which primary processing has completed
|
||||
unsigned IncomingProcessed = 0;
|
||||
|
||||
/// The value of `IncomingProcessed` at the start of primary processing
|
||||
unsigned PrimaryIncoming = 0;
|
||||
|
||||
/// The number of predecessors for which all processing steps are done.
|
||||
unsigned IncomingCompleted = 0;
|
||||
|
||||
MBBInfo() = default;
|
||||
};
|
||||
using MBBInfoMap = SmallVector<MBBInfo, 4>;
|
||||
/// Helps keep track if we processed this block and all its predecessors.
|
||||
MBBInfoMap MBBInfos;
|
||||
|
||||
public:
|
||||
struct TraversedMBBInfo {
|
||||
/// The basic block.
|
||||
MachineBasicBlock *MBB = nullptr;
|
||||
|
||||
/// True if this is the first time we process the basic block.
|
||||
bool PrimaryPass = true;
|
||||
|
||||
/// True if the block that is ready for its final round of processing.
|
||||
bool IsDone = true;
|
||||
|
||||
TraversedMBBInfo(MachineBasicBlock *BB = nullptr, bool Primary = true,
|
||||
bool Done = true)
|
||||
: MBB(BB), PrimaryPass(Primary), IsDone(Done) {}
|
||||
};
|
||||
LoopTraversal() = default;
|
||||
|
||||
/// Identifies basic blocks that are part of loops and should to be
|
||||
/// visited twice and returns efficient traversal order for all the blocks.
|
||||
typedef SmallVector<TraversedMBBInfo, 4> TraversalOrder;
|
||||
TraversalOrder traverse(MachineFunction &MF);
|
||||
|
||||
private:
|
||||
/// Returens true if the block is ready for its final round of processing.
|
||||
bool isBlockDone(MachineBasicBlock *MBB);
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_LOOPTRAVERSAL_H
|
||||
45
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LowLevelType.h
vendored
Normal file
45
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/LowLevelType.h
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
//== llvm/CodeGen/LowLevelType.h ------------------------------- -*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
/// \file
|
||||
/// Implement a low-level type suitable for MachineInstr level instruction
|
||||
/// selection.
|
||||
///
|
||||
/// This provides the CodeGen aspects of LowLevelType, such as Type conversion.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_LOWLEVELTYPE_H
|
||||
#define LLVM_CODEGEN_LOWLEVELTYPE_H
|
||||
|
||||
#include "llvm/CodeGen/ValueTypes.h"
|
||||
#include "llvm/Support/LowLevelTypeImpl.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class DataLayout;
|
||||
class Type;
|
||||
struct fltSemantics;
|
||||
|
||||
/// Construct a low-level type based on an LLVM type.
|
||||
LLT getLLTForType(Type &Ty, const DataLayout &DL);
|
||||
|
||||
/// Get a rough equivalent of an MVT for a given LLT. MVT can't distinguish
|
||||
/// pointers, so these will convert to a plain integer.
|
||||
MVT getMVTForLLT(LLT Ty);
|
||||
EVT getApproximateEVTForLLT(LLT Ty, const DataLayout &DL, LLVMContext &Ctx);
|
||||
|
||||
/// Get a rough equivalent of an LLT for a given MVT. LLT does not yet support
|
||||
/// scalarable vector types, and will assert if used.
|
||||
LLT getLLTForMVT(MVT Ty);
|
||||
|
||||
/// Get the appropriate floating point arithmetic semantic based on the bit size
|
||||
/// of the given scalar LLT.
|
||||
const llvm::fltSemantics &getFltSemanticForLLT(LLT Ty);
|
||||
}
|
||||
|
||||
#endif // LLVM_CODEGEN_LOWLEVELTYPE_H
|
||||
49
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/MBFIWrapper.h
vendored
Normal file
49
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/MBFIWrapper.h
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
//===- llvm/CodeGen/MBFIWrapper.h -------------------------------*- 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 class keeps track of branch frequencies of newly created blocks and
|
||||
// tail-merged blocks. Used by the TailDuplication and MachineBlockPlacement.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_MBFIWRAPPER_H
|
||||
#define LLVM_CODEGEN_MBFIWRAPPER_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/Support/BlockFrequency.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MachineBasicBlock;
|
||||
class MachineBlockFrequencyInfo;
|
||||
|
||||
class MBFIWrapper {
|
||||
public:
|
||||
MBFIWrapper(const MachineBlockFrequencyInfo &I) : MBFI(I) {}
|
||||
|
||||
BlockFrequency getBlockFreq(const MachineBasicBlock *MBB) const;
|
||||
void setBlockFreq(const MachineBasicBlock *MBB, BlockFrequency F);
|
||||
Optional<uint64_t> getBlockProfileCount(const MachineBasicBlock *MBB) const;
|
||||
|
||||
raw_ostream &printBlockFreq(raw_ostream &OS,
|
||||
const MachineBasicBlock *MBB) const;
|
||||
raw_ostream &printBlockFreq(raw_ostream &OS,
|
||||
const BlockFrequency Freq) const;
|
||||
void view(const Twine &Name, bool isSimple = true);
|
||||
uint64_t getEntryFreq() const;
|
||||
const MachineBlockFrequencyInfo &getMBFI() { return MBFI; }
|
||||
|
||||
private:
|
||||
const MachineBlockFrequencyInfo &MBFI;
|
||||
DenseMap<const MachineBasicBlock *, BlockFrequency> MergedBBFreq;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_MBFIWRAPPER_H
|
||||
80
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/MIRFSDiscriminator.h
vendored
Normal file
80
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/MIRFSDiscriminator.h
vendored
Normal file
@@ -0,0 +1,80 @@
|
||||
//===----- MIRFSDiscriminator.h: MIR FS Discriminator Support --0-- 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 file contains the supporting functions for adding Machine level IR
|
||||
// Flow Sensitive discriminators to the instruction debug information. With
|
||||
// this, a cloned machine instruction in a different MachineBasicBlock will
|
||||
// have its own discriminator value. This is done in a MIRAddFSDiscriminators
|
||||
// pass.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_MIRFSDISCRIMINATOR_H
|
||||
#define LLVM_CODEGEN_MIRFSDISCRIMINATOR_H
|
||||
|
||||
#include "llvm/Analysis/ProfileSummaryInfo.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
|
||||
#include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
|
||||
#include "llvm/CodeGen/MachineDominators.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
#include "llvm/CodeGen/MachineLoopInfo.h"
|
||||
#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
|
||||
#include "llvm/CodeGen/MachinePostDominators.h"
|
||||
#include "llvm/CodeGen/Passes.h"
|
||||
#include "llvm/IR/DebugInfoMetadata.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/InitializePasses.h"
|
||||
#include "llvm/ProfileData/InstrProf.h"
|
||||
#include "llvm/ProfileData/SampleProf.h"
|
||||
#include "llvm/ProfileData/SampleProfReader.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
using namespace sampleprof;
|
||||
class MIRAddFSDiscriminators : public MachineFunctionPass {
|
||||
MachineFunction *MF;
|
||||
unsigned LowBit;
|
||||
unsigned HighBit;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
/// PassNum is the sequence number this pass is called, start from 1.
|
||||
MIRAddFSDiscriminators(FSDiscriminatorPass P = FSDiscriminatorPass::Pass1)
|
||||
: MachineFunctionPass(ID) {
|
||||
LowBit = getFSPassBitBegin(P);
|
||||
HighBit = getFSPassBitEnd(P);
|
||||
assert(LowBit < HighBit && "HighBit needs to be greater than Lowbit");
|
||||
}
|
||||
|
||||
StringRef getPassName() const override {
|
||||
return "Add FS discriminators in MIR";
|
||||
}
|
||||
|
||||
/// getNumFSBBs() - Return the number of machine BBs that have FS samples.
|
||||
unsigned getNumFSBBs();
|
||||
|
||||
/// getNumFSSamples() - Return the number of samples that have flow sensitive
|
||||
/// values.
|
||||
uint64_t getNumFSSamples();
|
||||
|
||||
/// getMachineFunction - Return the current machine function.
|
||||
const MachineFunction *getMachineFunction() const { return MF; }
|
||||
|
||||
private:
|
||||
bool runOnMachineFunction(MachineFunction &) override;
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_MIRFSDISCRIMINATOR_H
|
||||
85
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/MIRFormatter.h
vendored
Normal file
85
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/MIRFormatter.h
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
//===-- llvm/CodeGen/MIRFormatter.h -----------------------------*- 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 file contains the declaration of the MIRFormatter class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_MIRFORMATTER_H
|
||||
#define LLVM_CODEGEN_MIRFORMATTER_H
|
||||
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/CodeGen/PseudoSourceValue.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MachineFunction;
|
||||
class MachineInstr;
|
||||
struct PerFunctionMIParsingState;
|
||||
|
||||
/// MIRFormater - Interface to format MIR operand based on target
|
||||
class MIRFormatter {
|
||||
public:
|
||||
typedef function_ref<bool(StringRef::iterator Loc, const Twine &)>
|
||||
ErrorCallbackType;
|
||||
|
||||
MIRFormatter() = default;
|
||||
virtual ~MIRFormatter() = default;
|
||||
|
||||
/// Implement target specific printing for machine operand immediate value, so
|
||||
/// that we can have more meaningful mnemonic than a 64-bit integer. Passing
|
||||
/// None to OpIdx means the index is unknown.
|
||||
virtual void printImm(raw_ostream &OS, const MachineInstr &MI,
|
||||
Optional<unsigned> OpIdx, int64_t Imm) const {
|
||||
OS << Imm;
|
||||
}
|
||||
|
||||
/// Implement target specific parsing of immediate mnemonics. The mnemonic is
|
||||
/// dot separated strings.
|
||||
virtual bool parseImmMnemonic(const unsigned OpCode, const unsigned OpIdx,
|
||||
StringRef Src, int64_t &Imm,
|
||||
ErrorCallbackType ErrorCallback) const {
|
||||
llvm_unreachable("target did not implement parsing MIR immediate mnemonic");
|
||||
}
|
||||
|
||||
/// Implement target specific printing of target custom pseudo source value.
|
||||
/// Default implementation is not necessarily the correct MIR serialization
|
||||
/// format.
|
||||
virtual void
|
||||
printCustomPseudoSourceValue(raw_ostream &OS, ModuleSlotTracker &MST,
|
||||
const PseudoSourceValue &PSV) const {
|
||||
PSV.printCustom(OS);
|
||||
}
|
||||
|
||||
/// Implement target specific parsing of target custom pseudo source value.
|
||||
virtual bool parseCustomPseudoSourceValue(
|
||||
StringRef Src, MachineFunction &MF, PerFunctionMIParsingState &PFS,
|
||||
const PseudoSourceValue *&PSV, ErrorCallbackType ErrorCallback) const {
|
||||
llvm_unreachable(
|
||||
"target did not implement parsing MIR custom pseudo source value");
|
||||
}
|
||||
|
||||
/// Helper functions to print IR value as MIR serialization format which will
|
||||
/// be useful for target specific printer, e.g. for printing IR value in
|
||||
/// custom pseudo source value.
|
||||
static void printIRValue(raw_ostream &OS, const Value &V,
|
||||
ModuleSlotTracker &MST);
|
||||
|
||||
/// Helper functions to parse IR value from MIR serialization format which
|
||||
/// will be useful for target specific parser, e.g. for parsing IR value for
|
||||
/// custom pseudo source value.
|
||||
static bool parseIRValue(StringRef Src, MachineFunction &MF,
|
||||
PerFunctionMIParsingState &PFS, const Value *&V,
|
||||
ErrorCallbackType ErrorCallback);
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
246
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/MIRParser/MIParser.h
vendored
Normal file
246
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/MIRParser/MIParser.h
vendored
Normal file
@@ -0,0 +1,246 @@
|
||||
//===- MIParser.h - Machine Instructions Parser -----------------*- 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 file declares the function that parses the machine instructions.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_MIRPARSER_MIPARSER_H
|
||||
#define LLVM_CODEGEN_MIRPARSER_MIPARSER_H
|
||||
|
||||
#include "llvm/ADT/DenseMap.h"
|
||||
#include "llvm/ADT/StringMap.h"
|
||||
#include "llvm/CodeGen/MachineMemOperand.h"
|
||||
#include "llvm/CodeGen/Register.h"
|
||||
#include "llvm/Support/Allocator.h"
|
||||
#include "llvm/Support/SMLoc.h"
|
||||
#include <utility>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MachineBasicBlock;
|
||||
class MachineFunction;
|
||||
class MDNode;
|
||||
class RegisterBank;
|
||||
struct SlotMapping;
|
||||
class SMDiagnostic;
|
||||
class SourceMgr;
|
||||
class StringRef;
|
||||
class TargetRegisterClass;
|
||||
class TargetSubtargetInfo;
|
||||
|
||||
struct VRegInfo {
|
||||
enum uint8_t {
|
||||
UNKNOWN, NORMAL, GENERIC, REGBANK
|
||||
} Kind = UNKNOWN;
|
||||
bool Explicit = false; ///< VReg was explicitly specified in the .mir file.
|
||||
union {
|
||||
const TargetRegisterClass *RC;
|
||||
const RegisterBank *RegBank;
|
||||
} D;
|
||||
Register VReg;
|
||||
Register PreferredReg;
|
||||
};
|
||||
|
||||
using Name2RegClassMap = StringMap<const TargetRegisterClass *>;
|
||||
using Name2RegBankMap = StringMap<const RegisterBank *>;
|
||||
|
||||
struct PerTargetMIParsingState {
|
||||
private:
|
||||
const TargetSubtargetInfo &Subtarget;
|
||||
|
||||
/// Maps from instruction names to op codes.
|
||||
StringMap<unsigned> Names2InstrOpCodes;
|
||||
|
||||
/// Maps from register names to registers.
|
||||
StringMap<Register> Names2Regs;
|
||||
|
||||
/// Maps from register mask names to register masks.
|
||||
StringMap<const uint32_t *> Names2RegMasks;
|
||||
|
||||
/// Maps from subregister names to subregister indices.
|
||||
StringMap<unsigned> Names2SubRegIndices;
|
||||
|
||||
/// Maps from target index names to target indices.
|
||||
StringMap<int> Names2TargetIndices;
|
||||
|
||||
/// Maps from direct target flag names to the direct target flag values.
|
||||
StringMap<unsigned> Names2DirectTargetFlags;
|
||||
|
||||
/// Maps from direct target flag names to the bitmask target flag values.
|
||||
StringMap<unsigned> Names2BitmaskTargetFlags;
|
||||
|
||||
/// Maps from MMO target flag names to MMO target flag values.
|
||||
StringMap<MachineMemOperand::Flags> Names2MMOTargetFlags;
|
||||
|
||||
/// Maps from register class names to register classes.
|
||||
Name2RegClassMap Names2RegClasses;
|
||||
|
||||
/// Maps from register bank names to register banks.
|
||||
Name2RegBankMap Names2RegBanks;
|
||||
|
||||
void initNames2InstrOpCodes();
|
||||
void initNames2Regs();
|
||||
void initNames2RegMasks();
|
||||
void initNames2SubRegIndices();
|
||||
void initNames2TargetIndices();
|
||||
void initNames2DirectTargetFlags();
|
||||
void initNames2BitmaskTargetFlags();
|
||||
void initNames2MMOTargetFlags();
|
||||
|
||||
void initNames2RegClasses();
|
||||
void initNames2RegBanks();
|
||||
|
||||
public:
|
||||
/// Try to convert an instruction name to an opcode. Return true if the
|
||||
/// instruction name is invalid.
|
||||
bool parseInstrName(StringRef InstrName, unsigned &OpCode);
|
||||
|
||||
/// Try to convert a register name to a register number. Return true if the
|
||||
/// register name is invalid.
|
||||
bool getRegisterByName(StringRef RegName, Register &Reg);
|
||||
|
||||
/// Check if the given identifier is a name of a register mask.
|
||||
///
|
||||
/// Return null if the identifier isn't a register mask.
|
||||
const uint32_t *getRegMask(StringRef Identifier);
|
||||
|
||||
/// Check if the given identifier is a name of a subregister index.
|
||||
///
|
||||
/// Return 0 if the name isn't a subregister index class.
|
||||
unsigned getSubRegIndex(StringRef Name);
|
||||
|
||||
/// Try to convert a name of target index to the corresponding target index.
|
||||
///
|
||||
/// Return true if the name isn't a name of a target index.
|
||||
bool getTargetIndex(StringRef Name, int &Index);
|
||||
|
||||
/// Try to convert a name of a direct target flag to the corresponding
|
||||
/// target flag.
|
||||
///
|
||||
/// Return true if the name isn't a name of a direct flag.
|
||||
bool getDirectTargetFlag(StringRef Name, unsigned &Flag);
|
||||
|
||||
/// Try to convert a name of a bitmask target flag to the corresponding
|
||||
/// target flag.
|
||||
///
|
||||
/// Return true if the name isn't a name of a bitmask target flag.
|
||||
bool getBitmaskTargetFlag(StringRef Name, unsigned &Flag);
|
||||
|
||||
/// Try to convert a name of a MachineMemOperand target flag to the
|
||||
/// corresponding target flag.
|
||||
///
|
||||
/// Return true if the name isn't a name of a target MMO flag.
|
||||
bool getMMOTargetFlag(StringRef Name, MachineMemOperand::Flags &Flag);
|
||||
|
||||
/// Check if the given identifier is a name of a register class.
|
||||
///
|
||||
/// Return null if the name isn't a register class.
|
||||
const TargetRegisterClass *getRegClass(StringRef Name);
|
||||
|
||||
/// Check if the given identifier is a name of a register bank.
|
||||
///
|
||||
/// Return null if the name isn't a register bank.
|
||||
const RegisterBank *getRegBank(StringRef Name);
|
||||
|
||||
PerTargetMIParsingState(const TargetSubtargetInfo &STI)
|
||||
: Subtarget(STI) {
|
||||
initNames2RegClasses();
|
||||
initNames2RegBanks();
|
||||
}
|
||||
|
||||
~PerTargetMIParsingState() = default;
|
||||
|
||||
void setTarget(const TargetSubtargetInfo &NewSubtarget);
|
||||
};
|
||||
|
||||
struct PerFunctionMIParsingState {
|
||||
BumpPtrAllocator Allocator;
|
||||
MachineFunction &MF;
|
||||
SourceMgr *SM;
|
||||
const SlotMapping &IRSlots;
|
||||
PerTargetMIParsingState &Target;
|
||||
|
||||
std::map<unsigned, TrackingMDNodeRef> MachineMetadataNodes;
|
||||
std::map<unsigned, std::pair<TempMDTuple, SMLoc>> MachineForwardRefMDNodes;
|
||||
|
||||
DenseMap<unsigned, MachineBasicBlock *> MBBSlots;
|
||||
DenseMap<Register, VRegInfo *> VRegInfos;
|
||||
StringMap<VRegInfo *> VRegInfosNamed;
|
||||
DenseMap<unsigned, int> FixedStackObjectSlots;
|
||||
DenseMap<unsigned, int> StackObjectSlots;
|
||||
DenseMap<unsigned, unsigned> ConstantPoolSlots;
|
||||
DenseMap<unsigned, unsigned> JumpTableSlots;
|
||||
|
||||
/// Maps from slot numbers to function's unnamed values.
|
||||
DenseMap<unsigned, const Value *> Slots2Values;
|
||||
|
||||
PerFunctionMIParsingState(MachineFunction &MF, SourceMgr &SM,
|
||||
const SlotMapping &IRSlots,
|
||||
PerTargetMIParsingState &Target);
|
||||
|
||||
VRegInfo &getVRegInfo(Register Num);
|
||||
VRegInfo &getVRegInfoNamed(StringRef RegName);
|
||||
const Value *getIRValue(unsigned Slot);
|
||||
};
|
||||
|
||||
/// Parse the machine basic block definitions, and skip the machine
|
||||
/// instructions.
|
||||
///
|
||||
/// This function runs the first parsing pass on the machine function's body.
|
||||
/// It parses only the machine basic block definitions and creates the machine
|
||||
/// basic blocks in the given machine function.
|
||||
///
|
||||
/// The machine instructions aren't parsed during the first pass because all
|
||||
/// the machine basic blocks aren't defined yet - this makes it impossible to
|
||||
/// resolve the machine basic block references.
|
||||
///
|
||||
/// Return true if an error occurred.
|
||||
bool parseMachineBasicBlockDefinitions(PerFunctionMIParsingState &PFS,
|
||||
StringRef Src, SMDiagnostic &Error);
|
||||
|
||||
/// Parse the machine instructions.
|
||||
///
|
||||
/// This function runs the second parsing pass on the machine function's body.
|
||||
/// It skips the machine basic block definitions and parses only the machine
|
||||
/// instructions and basic block attributes like liveins and successors.
|
||||
///
|
||||
/// The second parsing pass assumes that the first parsing pass already ran
|
||||
/// on the given source string.
|
||||
///
|
||||
/// Return true if an error occurred.
|
||||
bool parseMachineInstructions(PerFunctionMIParsingState &PFS, StringRef Src,
|
||||
SMDiagnostic &Error);
|
||||
|
||||
bool parseMBBReference(PerFunctionMIParsingState &PFS,
|
||||
MachineBasicBlock *&MBB, StringRef Src,
|
||||
SMDiagnostic &Error);
|
||||
|
||||
bool parseRegisterReference(PerFunctionMIParsingState &PFS,
|
||||
Register &Reg, StringRef Src,
|
||||
SMDiagnostic &Error);
|
||||
|
||||
bool parseNamedRegisterReference(PerFunctionMIParsingState &PFS, Register &Reg,
|
||||
StringRef Src, SMDiagnostic &Error);
|
||||
|
||||
bool parseVirtualRegisterReference(PerFunctionMIParsingState &PFS,
|
||||
VRegInfo *&Info, StringRef Src,
|
||||
SMDiagnostic &Error);
|
||||
|
||||
bool parseStackObjectReference(PerFunctionMIParsingState &PFS, int &FI,
|
||||
StringRef Src, SMDiagnostic &Error);
|
||||
|
||||
bool parseMDNode(PerFunctionMIParsingState &PFS, MDNode *&Node, StringRef Src,
|
||||
SMDiagnostic &Error);
|
||||
|
||||
bool parseMachineMetadata(PerFunctionMIParsingState &PFS, StringRef Src,
|
||||
SMRange SourceRange, SMDiagnostic &Error);
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_MIRPARSER_MIPARSER_H
|
||||
88
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/MIRParser/MIRParser.h
vendored
Normal file
88
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/MIRParser/MIRParser.h
vendored
Normal file
@@ -0,0 +1,88 @@
|
||||
//===- MIRParser.h - MIR serialization format parser ------------*- 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 MIR serialization library is currently a work in progress. It can't
|
||||
// serialize machine functions at this time.
|
||||
//
|
||||
// This file declares the functions that parse the MIR serialization format
|
||||
// files.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_MIRPARSER_MIRPARSER_H
|
||||
#define LLVM_CODEGEN_MIRPARSER_MIRPARSER_H
|
||||
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/Support/MemoryBuffer.h"
|
||||
#include <memory>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Function;
|
||||
class MIRParserImpl;
|
||||
class MachineModuleInfo;
|
||||
class SMDiagnostic;
|
||||
class StringRef;
|
||||
|
||||
typedef llvm::function_ref<Optional<std::string>(StringRef)>
|
||||
DataLayoutCallbackTy;
|
||||
|
||||
/// This class initializes machine functions by applying the state loaded from
|
||||
/// a MIR file.
|
||||
class MIRParser {
|
||||
std::unique_ptr<MIRParserImpl> Impl;
|
||||
|
||||
public:
|
||||
MIRParser(std::unique_ptr<MIRParserImpl> Impl);
|
||||
MIRParser(const MIRParser &) = delete;
|
||||
~MIRParser();
|
||||
|
||||
/// Parses the optional LLVM IR module in the MIR file.
|
||||
///
|
||||
/// A new, empty module is created if the LLVM IR isn't present.
|
||||
/// \returns nullptr if a parsing error occurred.
|
||||
std::unique_ptr<Module> parseIRModule(
|
||||
DataLayoutCallbackTy DataLayoutCallback = [](StringRef) { return None; });
|
||||
|
||||
/// Parses MachineFunctions in the MIR file and add them to the given
|
||||
/// MachineModuleInfo \p MMI.
|
||||
///
|
||||
/// \returns true if an error occurred.
|
||||
bool parseMachineFunctions(Module &M, MachineModuleInfo &MMI);
|
||||
};
|
||||
|
||||
/// This function is the main interface to the MIR serialization format parser.
|
||||
///
|
||||
/// It reads in a MIR file and returns a MIR parser that can parse the embedded
|
||||
/// LLVM IR module and initialize the machine functions by parsing the machine
|
||||
/// function's state.
|
||||
///
|
||||
/// \param Filename - The name of the file to parse.
|
||||
/// \param Error - Error result info.
|
||||
/// \param Context - Context which will be used for the parsed LLVM IR module.
|
||||
/// \param ProcessIRFunction - function to run on every IR function or stub
|
||||
/// loaded from the MIR file.
|
||||
std::unique_ptr<MIRParser> createMIRParserFromFile(
|
||||
StringRef Filename, SMDiagnostic &Error, LLVMContext &Context,
|
||||
std::function<void(Function &)> ProcessIRFunction = nullptr);
|
||||
|
||||
/// This function is another interface to the MIR serialization format parser.
|
||||
///
|
||||
/// It returns a MIR parser that works with the given memory buffer and that can
|
||||
/// parse the embedded LLVM IR module and initialize the machine functions by
|
||||
/// parsing the machine function's state.
|
||||
///
|
||||
/// \param Contents - The MemoryBuffer containing the machine level IR.
|
||||
/// \param Context - Context which will be used for the parsed LLVM IR module.
|
||||
std::unique_ptr<MIRParser>
|
||||
createMIRParser(std::unique_ptr<MemoryBuffer> Contents, LLVMContext &Context,
|
||||
std::function<void(Function &)> ProcessIRFunction = nullptr);
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_MIRPARSER_MIRPARSER_H
|
||||
45
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/MIRPrinter.h
vendored
Normal file
45
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/MIRPrinter.h
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
//===- MIRPrinter.h - MIR serialization format printer ----------*- 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 file declares the functions that print out the LLVM IR and the machine
|
||||
// functions using the MIR serialization format.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_MIRPRINTER_H
|
||||
#define LLVM_CODEGEN_MIRPRINTER_H
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MachineBasicBlock;
|
||||
class MachineFunction;
|
||||
class Module;
|
||||
class raw_ostream;
|
||||
template <typename T> class SmallVectorImpl;
|
||||
|
||||
/// Print LLVM IR using the MIR serialization format to the given output stream.
|
||||
void printMIR(raw_ostream &OS, const Module &M);
|
||||
|
||||
/// Print a machine function using the MIR serialization format to the given
|
||||
/// output stream.
|
||||
void printMIR(raw_ostream &OS, const MachineFunction &MF);
|
||||
|
||||
/// Determine a possible list of successors of a basic block based on the
|
||||
/// basic block machine operand being used inside the block. This should give
|
||||
/// you the correct list of successor blocks in most cases except for things
|
||||
/// like jump tables where the basic block references can't easily be found.
|
||||
/// The MIRPRinter will skip printing successors if they match the result of
|
||||
/// this function and the parser will use this function to construct a list if
|
||||
/// it is missing.
|
||||
void guessSuccessors(const MachineBasicBlock &MBB,
|
||||
SmallVectorImpl<MachineBasicBlock*> &Result,
|
||||
bool &IsFallthrough);
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
76
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/MIRSampleProfile.h
vendored
Normal file
76
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/MIRSampleProfile.h
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
//===----- MIRSampleProfile.h: SampleFDO Support in MIR ---*- 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 file contains the supporting functions for machine level Sample FDO
|
||||
// loader. This is used in Flow Sensitive SampelFDO.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_MIRSAMPLEPROFILE_H
|
||||
#define LLVM_CODEGEN_MIRSAMPLEPROFILE_H
|
||||
|
||||
#include "llvm/Analysis/ProfileSummaryInfo.h"
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/CodeGen/MachineBlockFrequencyInfo.h"
|
||||
#include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
|
||||
#include "llvm/CodeGen/MachineDominators.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
#include "llvm/CodeGen/MachineLoopInfo.h"
|
||||
#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
|
||||
#include "llvm/CodeGen/MachinePostDominators.h"
|
||||
#include "llvm/CodeGen/Passes.h"
|
||||
#include "llvm/IR/DebugInfoMetadata.h"
|
||||
#include "llvm/IR/Function.h"
|
||||
#include "llvm/IR/Module.h"
|
||||
#include "llvm/InitializePasses.h"
|
||||
#include "llvm/ProfileData/InstrProf.h"
|
||||
#include "llvm/ProfileData/SampleProf.h"
|
||||
#include "llvm/ProfileData/SampleProfReader.h"
|
||||
|
||||
#include <cassert>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
using namespace sampleprof;
|
||||
|
||||
class MIRProfileLoader;
|
||||
class MIRProfileLoaderPass : public MachineFunctionPass {
|
||||
MachineFunction *MF;
|
||||
std::string ProfileFileName;
|
||||
FSDiscriminatorPass P;
|
||||
unsigned LowBit;
|
||||
unsigned HighBit;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
/// FS bits will only use the '1' bits in the Mask.
|
||||
MIRProfileLoaderPass(std::string FileName = "",
|
||||
std::string RemappingFileName = "",
|
||||
FSDiscriminatorPass P = FSDiscriminatorPass::Pass1);
|
||||
|
||||
/// getMachineFunction - Return the last machine function computed.
|
||||
const MachineFunction *getMachineFunction() const { return MF; }
|
||||
|
||||
StringRef getPassName() const override { return "SampleFDO loader in MIR"; }
|
||||
|
||||
private:
|
||||
void init(MachineFunction &MF);
|
||||
bool runOnMachineFunction(MachineFunction &) override;
|
||||
bool doInitialization(Module &M) override;
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
std::unique_ptr<MIRProfileLoader> MIRSampleLoader;
|
||||
/// Hold the information of the basic block frequency.
|
||||
MachineBlockFrequencyInfo *MBFI;
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_MIRSAMPLEPROFILE_H
|
||||
760
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/MIRYamlMapping.h
vendored
Normal file
760
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/MIRYamlMapping.h
vendored
Normal file
@@ -0,0 +1,760 @@
|
||||
//===- MIRYamlMapping.h - Describe mapping between MIR and YAML--*- 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 file implements the mapping between various MIR data structures and
|
||||
// their corresponding YAML representation.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_MIRYAMLMAPPING_H
|
||||
#define LLVM_CODEGEN_MIRYAMLMAPPING_H
|
||||
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/CodeGen/MachineJumpTableInfo.h"
|
||||
#include "llvm/CodeGen/TargetFrameLowering.h"
|
||||
#include "llvm/Support/SMLoc.h"
|
||||
#include "llvm/Support/YAMLTraits.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
namespace yaml {
|
||||
|
||||
/// A wrapper around std::string which contains a source range that's being
|
||||
/// set during parsing.
|
||||
struct StringValue {
|
||||
std::string Value;
|
||||
SMRange SourceRange;
|
||||
|
||||
StringValue() = default;
|
||||
StringValue(std::string Value) : Value(std::move(Value)) {}
|
||||
StringValue(const char Val[]) : Value(Val) {}
|
||||
|
||||
bool operator==(const StringValue &Other) const {
|
||||
return Value == Other.Value;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct ScalarTraits<StringValue> {
|
||||
static void output(const StringValue &S, void *, raw_ostream &OS) {
|
||||
OS << S.Value;
|
||||
}
|
||||
|
||||
static StringRef input(StringRef Scalar, void *Ctx, StringValue &S) {
|
||||
S.Value = Scalar.str();
|
||||
if (const auto *Node =
|
||||
reinterpret_cast<yaml::Input *>(Ctx)->getCurrentNode())
|
||||
S.SourceRange = Node->getSourceRange();
|
||||
return "";
|
||||
}
|
||||
|
||||
static QuotingType mustQuote(StringRef S) { return needsQuotes(S); }
|
||||
};
|
||||
|
||||
struct FlowStringValue : StringValue {
|
||||
FlowStringValue() = default;
|
||||
FlowStringValue(std::string Value) : StringValue(std::move(Value)) {}
|
||||
};
|
||||
|
||||
template <> struct ScalarTraits<FlowStringValue> {
|
||||
static void output(const FlowStringValue &S, void *, raw_ostream &OS) {
|
||||
return ScalarTraits<StringValue>::output(S, nullptr, OS);
|
||||
}
|
||||
|
||||
static StringRef input(StringRef Scalar, void *Ctx, FlowStringValue &S) {
|
||||
return ScalarTraits<StringValue>::input(Scalar, Ctx, S);
|
||||
}
|
||||
|
||||
static QuotingType mustQuote(StringRef S) { return needsQuotes(S); }
|
||||
};
|
||||
|
||||
struct BlockStringValue {
|
||||
StringValue Value;
|
||||
|
||||
bool operator==(const BlockStringValue &Other) const {
|
||||
return Value == Other.Value;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct BlockScalarTraits<BlockStringValue> {
|
||||
static void output(const BlockStringValue &S, void *Ctx, raw_ostream &OS) {
|
||||
return ScalarTraits<StringValue>::output(S.Value, Ctx, OS);
|
||||
}
|
||||
|
||||
static StringRef input(StringRef Scalar, void *Ctx, BlockStringValue &S) {
|
||||
return ScalarTraits<StringValue>::input(Scalar, Ctx, S.Value);
|
||||
}
|
||||
};
|
||||
|
||||
/// A wrapper around unsigned which contains a source range that's being set
|
||||
/// during parsing.
|
||||
struct UnsignedValue {
|
||||
unsigned Value = 0;
|
||||
SMRange SourceRange;
|
||||
|
||||
UnsignedValue() = default;
|
||||
UnsignedValue(unsigned Value) : Value(Value) {}
|
||||
|
||||
bool operator==(const UnsignedValue &Other) const {
|
||||
return Value == Other.Value;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct ScalarTraits<UnsignedValue> {
|
||||
static void output(const UnsignedValue &Value, void *Ctx, raw_ostream &OS) {
|
||||
return ScalarTraits<unsigned>::output(Value.Value, Ctx, OS);
|
||||
}
|
||||
|
||||
static StringRef input(StringRef Scalar, void *Ctx, UnsignedValue &Value) {
|
||||
if (const auto *Node =
|
||||
reinterpret_cast<yaml::Input *>(Ctx)->getCurrentNode())
|
||||
Value.SourceRange = Node->getSourceRange();
|
||||
return ScalarTraits<unsigned>::input(Scalar, Ctx, Value.Value);
|
||||
}
|
||||
|
||||
static QuotingType mustQuote(StringRef Scalar) {
|
||||
return ScalarTraits<unsigned>::mustQuote(Scalar);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct ScalarEnumerationTraits<MachineJumpTableInfo::JTEntryKind> {
|
||||
static void enumeration(yaml::IO &IO,
|
||||
MachineJumpTableInfo::JTEntryKind &EntryKind) {
|
||||
IO.enumCase(EntryKind, "block-address",
|
||||
MachineJumpTableInfo::EK_BlockAddress);
|
||||
IO.enumCase(EntryKind, "gp-rel64-block-address",
|
||||
MachineJumpTableInfo::EK_GPRel64BlockAddress);
|
||||
IO.enumCase(EntryKind, "gp-rel32-block-address",
|
||||
MachineJumpTableInfo::EK_GPRel32BlockAddress);
|
||||
IO.enumCase(EntryKind, "label-difference32",
|
||||
MachineJumpTableInfo::EK_LabelDifference32);
|
||||
IO.enumCase(EntryKind, "inline", MachineJumpTableInfo::EK_Inline);
|
||||
IO.enumCase(EntryKind, "custom32", MachineJumpTableInfo::EK_Custom32);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct ScalarTraits<MaybeAlign> {
|
||||
static void output(const MaybeAlign &Alignment, void *,
|
||||
llvm::raw_ostream &out) {
|
||||
out << uint64_t(Alignment ? Alignment->value() : 0U);
|
||||
}
|
||||
static StringRef input(StringRef Scalar, void *, MaybeAlign &Alignment) {
|
||||
unsigned long long n;
|
||||
if (getAsUnsignedInteger(Scalar, 10, n))
|
||||
return "invalid number";
|
||||
if (n > 0 && !isPowerOf2_64(n))
|
||||
return "must be 0 or a power of two";
|
||||
Alignment = MaybeAlign(n);
|
||||
return StringRef();
|
||||
}
|
||||
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
|
||||
};
|
||||
|
||||
template <> struct ScalarTraits<Align> {
|
||||
static void output(const Align &Alignment, void *, llvm::raw_ostream &OS) {
|
||||
OS << Alignment.value();
|
||||
}
|
||||
static StringRef input(StringRef Scalar, void *, Align &Alignment) {
|
||||
unsigned long long N;
|
||||
if (getAsUnsignedInteger(Scalar, 10, N))
|
||||
return "invalid number";
|
||||
if (!isPowerOf2_64(N))
|
||||
return "must be a power of two";
|
||||
Alignment = Align(N);
|
||||
return StringRef();
|
||||
}
|
||||
static QuotingType mustQuote(StringRef) { return QuotingType::None; }
|
||||
};
|
||||
|
||||
} // end namespace yaml
|
||||
} // end namespace llvm
|
||||
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::StringValue)
|
||||
LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::FlowStringValue)
|
||||
LLVM_YAML_IS_FLOW_SEQUENCE_VECTOR(llvm::yaml::UnsignedValue)
|
||||
|
||||
namespace llvm {
|
||||
namespace yaml {
|
||||
|
||||
struct VirtualRegisterDefinition {
|
||||
UnsignedValue ID;
|
||||
StringValue Class;
|
||||
StringValue PreferredRegister;
|
||||
|
||||
// TODO: Serialize the target specific register hints.
|
||||
|
||||
bool operator==(const VirtualRegisterDefinition &Other) const {
|
||||
return ID == Other.ID && Class == Other.Class &&
|
||||
PreferredRegister == Other.PreferredRegister;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct MappingTraits<VirtualRegisterDefinition> {
|
||||
static void mapping(IO &YamlIO, VirtualRegisterDefinition &Reg) {
|
||||
YamlIO.mapRequired("id", Reg.ID);
|
||||
YamlIO.mapRequired("class", Reg.Class);
|
||||
YamlIO.mapOptional("preferred-register", Reg.PreferredRegister,
|
||||
StringValue()); // Don't print out when it's empty.
|
||||
}
|
||||
|
||||
static const bool flow = true;
|
||||
};
|
||||
|
||||
struct MachineFunctionLiveIn {
|
||||
StringValue Register;
|
||||
StringValue VirtualRegister;
|
||||
|
||||
bool operator==(const MachineFunctionLiveIn &Other) const {
|
||||
return Register == Other.Register &&
|
||||
VirtualRegister == Other.VirtualRegister;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct MappingTraits<MachineFunctionLiveIn> {
|
||||
static void mapping(IO &YamlIO, MachineFunctionLiveIn &LiveIn) {
|
||||
YamlIO.mapRequired("reg", LiveIn.Register);
|
||||
YamlIO.mapOptional(
|
||||
"virtual-reg", LiveIn.VirtualRegister,
|
||||
StringValue()); // Don't print the virtual register when it's empty.
|
||||
}
|
||||
|
||||
static const bool flow = true;
|
||||
};
|
||||
|
||||
/// Serializable representation of stack object from the MachineFrameInfo class.
|
||||
///
|
||||
/// The flags 'isImmutable' and 'isAliased' aren't serialized, as they are
|
||||
/// determined by the object's type and frame information flags.
|
||||
/// Dead stack objects aren't serialized.
|
||||
///
|
||||
/// The 'isPreallocated' flag is determined by the local offset.
|
||||
struct MachineStackObject {
|
||||
enum ObjectType { DefaultType, SpillSlot, VariableSized };
|
||||
UnsignedValue ID;
|
||||
StringValue Name;
|
||||
// TODO: Serialize unnamed LLVM alloca reference.
|
||||
ObjectType Type = DefaultType;
|
||||
int64_t Offset = 0;
|
||||
uint64_t Size = 0;
|
||||
MaybeAlign Alignment = None;
|
||||
TargetStackID::Value StackID;
|
||||
StringValue CalleeSavedRegister;
|
||||
bool CalleeSavedRestored = true;
|
||||
Optional<int64_t> LocalOffset;
|
||||
StringValue DebugVar;
|
||||
StringValue DebugExpr;
|
||||
StringValue DebugLoc;
|
||||
|
||||
bool operator==(const MachineStackObject &Other) const {
|
||||
return ID == Other.ID && Name == Other.Name && Type == Other.Type &&
|
||||
Offset == Other.Offset && Size == Other.Size &&
|
||||
Alignment == Other.Alignment &&
|
||||
StackID == Other.StackID &&
|
||||
CalleeSavedRegister == Other.CalleeSavedRegister &&
|
||||
CalleeSavedRestored == Other.CalleeSavedRestored &&
|
||||
LocalOffset == Other.LocalOffset && DebugVar == Other.DebugVar &&
|
||||
DebugExpr == Other.DebugExpr && DebugLoc == Other.DebugLoc;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct ScalarEnumerationTraits<MachineStackObject::ObjectType> {
|
||||
static void enumeration(yaml::IO &IO, MachineStackObject::ObjectType &Type) {
|
||||
IO.enumCase(Type, "default", MachineStackObject::DefaultType);
|
||||
IO.enumCase(Type, "spill-slot", MachineStackObject::SpillSlot);
|
||||
IO.enumCase(Type, "variable-sized", MachineStackObject::VariableSized);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct MappingTraits<MachineStackObject> {
|
||||
static void mapping(yaml::IO &YamlIO, MachineStackObject &Object) {
|
||||
YamlIO.mapRequired("id", Object.ID);
|
||||
YamlIO.mapOptional("name", Object.Name,
|
||||
StringValue()); // Don't print out an empty name.
|
||||
YamlIO.mapOptional(
|
||||
"type", Object.Type,
|
||||
MachineStackObject::DefaultType); // Don't print the default type.
|
||||
YamlIO.mapOptional("offset", Object.Offset, (int64_t)0);
|
||||
if (Object.Type != MachineStackObject::VariableSized)
|
||||
YamlIO.mapRequired("size", Object.Size);
|
||||
YamlIO.mapOptional("alignment", Object.Alignment, None);
|
||||
YamlIO.mapOptional("stack-id", Object.StackID, TargetStackID::Default);
|
||||
YamlIO.mapOptional("callee-saved-register", Object.CalleeSavedRegister,
|
||||
StringValue()); // Don't print it out when it's empty.
|
||||
YamlIO.mapOptional("callee-saved-restored", Object.CalleeSavedRestored,
|
||||
true);
|
||||
YamlIO.mapOptional("local-offset", Object.LocalOffset, Optional<int64_t>());
|
||||
YamlIO.mapOptional("debug-info-variable", Object.DebugVar,
|
||||
StringValue()); // Don't print it out when it's empty.
|
||||
YamlIO.mapOptional("debug-info-expression", Object.DebugExpr,
|
||||
StringValue()); // Don't print it out when it's empty.
|
||||
YamlIO.mapOptional("debug-info-location", Object.DebugLoc,
|
||||
StringValue()); // Don't print it out when it's empty.
|
||||
}
|
||||
|
||||
static const bool flow = true;
|
||||
};
|
||||
|
||||
/// Serializable representation of the fixed stack object from the
|
||||
/// MachineFrameInfo class.
|
||||
struct FixedMachineStackObject {
|
||||
enum ObjectType { DefaultType, SpillSlot };
|
||||
UnsignedValue ID;
|
||||
ObjectType Type = DefaultType;
|
||||
int64_t Offset = 0;
|
||||
uint64_t Size = 0;
|
||||
MaybeAlign Alignment = None;
|
||||
TargetStackID::Value StackID;
|
||||
bool IsImmutable = false;
|
||||
bool IsAliased = false;
|
||||
StringValue CalleeSavedRegister;
|
||||
bool CalleeSavedRestored = true;
|
||||
StringValue DebugVar;
|
||||
StringValue DebugExpr;
|
||||
StringValue DebugLoc;
|
||||
|
||||
bool operator==(const FixedMachineStackObject &Other) const {
|
||||
return ID == Other.ID && Type == Other.Type && Offset == Other.Offset &&
|
||||
Size == Other.Size && Alignment == Other.Alignment &&
|
||||
StackID == Other.StackID &&
|
||||
IsImmutable == Other.IsImmutable && IsAliased == Other.IsAliased &&
|
||||
CalleeSavedRegister == Other.CalleeSavedRegister &&
|
||||
CalleeSavedRestored == Other.CalleeSavedRestored &&
|
||||
DebugVar == Other.DebugVar && DebugExpr == Other.DebugExpr
|
||||
&& DebugLoc == Other.DebugLoc;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ScalarEnumerationTraits<FixedMachineStackObject::ObjectType> {
|
||||
static void enumeration(yaml::IO &IO,
|
||||
FixedMachineStackObject::ObjectType &Type) {
|
||||
IO.enumCase(Type, "default", FixedMachineStackObject::DefaultType);
|
||||
IO.enumCase(Type, "spill-slot", FixedMachineStackObject::SpillSlot);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ScalarEnumerationTraits<TargetStackID::Value> {
|
||||
static void enumeration(yaml::IO &IO, TargetStackID::Value &ID) {
|
||||
IO.enumCase(ID, "default", TargetStackID::Default);
|
||||
IO.enumCase(ID, "sgpr-spill", TargetStackID::SGPRSpill);
|
||||
IO.enumCase(ID, "scalable-vector", TargetStackID::ScalableVector);
|
||||
IO.enumCase(ID, "wasm-local", TargetStackID::WasmLocal);
|
||||
IO.enumCase(ID, "noalloc", TargetStackID::NoAlloc);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct MappingTraits<FixedMachineStackObject> {
|
||||
static void mapping(yaml::IO &YamlIO, FixedMachineStackObject &Object) {
|
||||
YamlIO.mapRequired("id", Object.ID);
|
||||
YamlIO.mapOptional(
|
||||
"type", Object.Type,
|
||||
FixedMachineStackObject::DefaultType); // Don't print the default type.
|
||||
YamlIO.mapOptional("offset", Object.Offset, (int64_t)0);
|
||||
YamlIO.mapOptional("size", Object.Size, (uint64_t)0);
|
||||
YamlIO.mapOptional("alignment", Object.Alignment, None);
|
||||
YamlIO.mapOptional("stack-id", Object.StackID, TargetStackID::Default);
|
||||
if (Object.Type != FixedMachineStackObject::SpillSlot) {
|
||||
YamlIO.mapOptional("isImmutable", Object.IsImmutable, false);
|
||||
YamlIO.mapOptional("isAliased", Object.IsAliased, false);
|
||||
}
|
||||
YamlIO.mapOptional("callee-saved-register", Object.CalleeSavedRegister,
|
||||
StringValue()); // Don't print it out when it's empty.
|
||||
YamlIO.mapOptional("callee-saved-restored", Object.CalleeSavedRestored,
|
||||
true);
|
||||
YamlIO.mapOptional("debug-info-variable", Object.DebugVar,
|
||||
StringValue()); // Don't print it out when it's empty.
|
||||
YamlIO.mapOptional("debug-info-expression", Object.DebugExpr,
|
||||
StringValue()); // Don't print it out when it's empty.
|
||||
YamlIO.mapOptional("debug-info-location", Object.DebugLoc,
|
||||
StringValue()); // Don't print it out when it's empty.
|
||||
}
|
||||
|
||||
static const bool flow = true;
|
||||
};
|
||||
|
||||
/// A serializaable representation of a reference to a stack object or fixed
|
||||
/// stack object.
|
||||
struct FrameIndex {
|
||||
// The frame index as printed. This is always a positive number, even for
|
||||
// fixed objects. To obtain the real index,
|
||||
// MachineFrameInfo::getObjectIndexBegin has to be added.
|
||||
int FI;
|
||||
bool IsFixed;
|
||||
SMRange SourceRange;
|
||||
|
||||
FrameIndex() = default;
|
||||
FrameIndex(int FI, const llvm::MachineFrameInfo &MFI);
|
||||
|
||||
Expected<int> getFI(const llvm::MachineFrameInfo &MFI) const;
|
||||
};
|
||||
|
||||
template <> struct ScalarTraits<FrameIndex> {
|
||||
static void output(const FrameIndex &FI, void *, raw_ostream &OS) {
|
||||
MachineOperand::printStackObjectReference(OS, FI.FI, FI.IsFixed, "");
|
||||
}
|
||||
|
||||
static StringRef input(StringRef Scalar, void *Ctx, FrameIndex &FI) {
|
||||
FI.IsFixed = false;
|
||||
StringRef Num;
|
||||
if (Scalar.startswith("%stack.")) {
|
||||
Num = Scalar.substr(7);
|
||||
} else if (Scalar.startswith("%fixed-stack.")) {
|
||||
Num = Scalar.substr(13);
|
||||
FI.IsFixed = true;
|
||||
} else {
|
||||
return "Invalid frame index, needs to start with %stack. or "
|
||||
"%fixed-stack.";
|
||||
}
|
||||
if (Num.consumeInteger(10, FI.FI))
|
||||
return "Invalid frame index, not a valid number";
|
||||
|
||||
if (const auto *Node =
|
||||
reinterpret_cast<yaml::Input *>(Ctx)->getCurrentNode())
|
||||
FI.SourceRange = Node->getSourceRange();
|
||||
return StringRef();
|
||||
}
|
||||
|
||||
static QuotingType mustQuote(StringRef S) { return needsQuotes(S); }
|
||||
};
|
||||
|
||||
/// Serializable representation of CallSiteInfo.
|
||||
struct CallSiteInfo {
|
||||
// Representation of call argument and register which is used to
|
||||
// transfer it.
|
||||
struct ArgRegPair {
|
||||
StringValue Reg;
|
||||
uint16_t ArgNo;
|
||||
|
||||
bool operator==(const ArgRegPair &Other) const {
|
||||
return Reg == Other.Reg && ArgNo == Other.ArgNo;
|
||||
}
|
||||
};
|
||||
|
||||
/// Identifies call instruction location in machine function.
|
||||
struct MachineInstrLoc {
|
||||
unsigned BlockNum;
|
||||
unsigned Offset;
|
||||
|
||||
bool operator==(const MachineInstrLoc &Other) const {
|
||||
return BlockNum == Other.BlockNum && Offset == Other.Offset;
|
||||
}
|
||||
};
|
||||
|
||||
MachineInstrLoc CallLocation;
|
||||
std::vector<ArgRegPair> ArgForwardingRegs;
|
||||
|
||||
bool operator==(const CallSiteInfo &Other) const {
|
||||
return CallLocation.BlockNum == Other.CallLocation.BlockNum &&
|
||||
CallLocation.Offset == Other.CallLocation.Offset;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct MappingTraits<CallSiteInfo::ArgRegPair> {
|
||||
static void mapping(IO &YamlIO, CallSiteInfo::ArgRegPair &ArgReg) {
|
||||
YamlIO.mapRequired("arg", ArgReg.ArgNo);
|
||||
YamlIO.mapRequired("reg", ArgReg.Reg);
|
||||
}
|
||||
|
||||
static const bool flow = true;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::CallSiteInfo::ArgRegPair)
|
||||
|
||||
namespace llvm {
|
||||
namespace yaml {
|
||||
|
||||
template <> struct MappingTraits<CallSiteInfo> {
|
||||
static void mapping(IO &YamlIO, CallSiteInfo &CSInfo) {
|
||||
YamlIO.mapRequired("bb", CSInfo.CallLocation.BlockNum);
|
||||
YamlIO.mapRequired("offset", CSInfo.CallLocation.Offset);
|
||||
YamlIO.mapOptional("fwdArgRegs", CSInfo.ArgForwardingRegs,
|
||||
std::vector<CallSiteInfo::ArgRegPair>());
|
||||
}
|
||||
|
||||
static const bool flow = true;
|
||||
};
|
||||
|
||||
/// Serializable representation of debug value substitutions.
|
||||
struct DebugValueSubstitution {
|
||||
unsigned SrcInst;
|
||||
unsigned SrcOp;
|
||||
unsigned DstInst;
|
||||
unsigned DstOp;
|
||||
unsigned Subreg;
|
||||
|
||||
bool operator==(const DebugValueSubstitution &Other) const {
|
||||
return std::tie(SrcInst, SrcOp, DstInst, DstOp) ==
|
||||
std::tie(Other.SrcInst, Other.SrcOp, Other.DstInst, Other.DstOp);
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct MappingTraits<DebugValueSubstitution> {
|
||||
static void mapping(IO &YamlIO, DebugValueSubstitution &Sub) {
|
||||
YamlIO.mapRequired("srcinst", Sub.SrcInst);
|
||||
YamlIO.mapRequired("srcop", Sub.SrcOp);
|
||||
YamlIO.mapRequired("dstinst", Sub.DstInst);
|
||||
YamlIO.mapRequired("dstop", Sub.DstOp);
|
||||
YamlIO.mapRequired("subreg", Sub.Subreg);
|
||||
}
|
||||
|
||||
static const bool flow = true;
|
||||
};
|
||||
} // namespace yaml
|
||||
} // namespace llvm
|
||||
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::DebugValueSubstitution)
|
||||
|
||||
namespace llvm {
|
||||
namespace yaml {
|
||||
struct MachineConstantPoolValue {
|
||||
UnsignedValue ID;
|
||||
StringValue Value;
|
||||
MaybeAlign Alignment = None;
|
||||
bool IsTargetSpecific = false;
|
||||
|
||||
bool operator==(const MachineConstantPoolValue &Other) const {
|
||||
return ID == Other.ID && Value == Other.Value &&
|
||||
Alignment == Other.Alignment &&
|
||||
IsTargetSpecific == Other.IsTargetSpecific;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct MappingTraits<MachineConstantPoolValue> {
|
||||
static void mapping(IO &YamlIO, MachineConstantPoolValue &Constant) {
|
||||
YamlIO.mapRequired("id", Constant.ID);
|
||||
YamlIO.mapOptional("value", Constant.Value, StringValue());
|
||||
YamlIO.mapOptional("alignment", Constant.Alignment, None);
|
||||
YamlIO.mapOptional("isTargetSpecific", Constant.IsTargetSpecific, false);
|
||||
}
|
||||
};
|
||||
|
||||
struct MachineJumpTable {
|
||||
struct Entry {
|
||||
UnsignedValue ID;
|
||||
std::vector<FlowStringValue> Blocks;
|
||||
|
||||
bool operator==(const Entry &Other) const {
|
||||
return ID == Other.ID && Blocks == Other.Blocks;
|
||||
}
|
||||
};
|
||||
|
||||
MachineJumpTableInfo::JTEntryKind Kind = MachineJumpTableInfo::EK_Custom32;
|
||||
std::vector<Entry> Entries;
|
||||
|
||||
bool operator==(const MachineJumpTable &Other) const {
|
||||
return Kind == Other.Kind && Entries == Other.Entries;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct MappingTraits<MachineJumpTable::Entry> {
|
||||
static void mapping(IO &YamlIO, MachineJumpTable::Entry &Entry) {
|
||||
YamlIO.mapRequired("id", Entry.ID);
|
||||
YamlIO.mapOptional("blocks", Entry.Blocks, std::vector<FlowStringValue>());
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace yaml
|
||||
} // end namespace llvm
|
||||
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineFunctionLiveIn)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::VirtualRegisterDefinition)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineStackObject)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::FixedMachineStackObject)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::CallSiteInfo)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineConstantPoolValue)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::yaml::MachineJumpTable::Entry)
|
||||
|
||||
namespace llvm {
|
||||
namespace yaml {
|
||||
|
||||
template <> struct MappingTraits<MachineJumpTable> {
|
||||
static void mapping(IO &YamlIO, MachineJumpTable &JT) {
|
||||
YamlIO.mapRequired("kind", JT.Kind);
|
||||
YamlIO.mapOptional("entries", JT.Entries,
|
||||
std::vector<MachineJumpTable::Entry>());
|
||||
}
|
||||
};
|
||||
|
||||
/// Serializable representation of MachineFrameInfo.
|
||||
///
|
||||
/// Doesn't serialize attributes like 'StackAlignment', 'IsStackRealignable' and
|
||||
/// 'RealignOption' as they are determined by the target and LLVM function
|
||||
/// attributes.
|
||||
/// It also doesn't serialize attributes like 'NumFixedObject' and
|
||||
/// 'HasVarSizedObjects' as they are determined by the frame objects themselves.
|
||||
struct MachineFrameInfo {
|
||||
bool IsFrameAddressTaken = false;
|
||||
bool IsReturnAddressTaken = false;
|
||||
bool HasStackMap = false;
|
||||
bool HasPatchPoint = false;
|
||||
uint64_t StackSize = 0;
|
||||
int OffsetAdjustment = 0;
|
||||
unsigned MaxAlignment = 0;
|
||||
bool AdjustsStack = false;
|
||||
bool HasCalls = false;
|
||||
StringValue StackProtector;
|
||||
// TODO: Serialize FunctionContextIdx
|
||||
unsigned MaxCallFrameSize = ~0u; ///< ~0u means: not computed yet.
|
||||
unsigned CVBytesOfCalleeSavedRegisters = 0;
|
||||
bool HasOpaqueSPAdjustment = false;
|
||||
bool HasVAStart = false;
|
||||
bool HasMustTailInVarArgFunc = false;
|
||||
bool HasTailCall = false;
|
||||
unsigned LocalFrameSize = 0;
|
||||
StringValue SavePoint;
|
||||
StringValue RestorePoint;
|
||||
|
||||
bool operator==(const MachineFrameInfo &Other) const {
|
||||
return IsFrameAddressTaken == Other.IsFrameAddressTaken &&
|
||||
IsReturnAddressTaken == Other.IsReturnAddressTaken &&
|
||||
HasStackMap == Other.HasStackMap &&
|
||||
HasPatchPoint == Other.HasPatchPoint &&
|
||||
StackSize == Other.StackSize &&
|
||||
OffsetAdjustment == Other.OffsetAdjustment &&
|
||||
MaxAlignment == Other.MaxAlignment &&
|
||||
AdjustsStack == Other.AdjustsStack && HasCalls == Other.HasCalls &&
|
||||
StackProtector == Other.StackProtector &&
|
||||
MaxCallFrameSize == Other.MaxCallFrameSize &&
|
||||
CVBytesOfCalleeSavedRegisters ==
|
||||
Other.CVBytesOfCalleeSavedRegisters &&
|
||||
HasOpaqueSPAdjustment == Other.HasOpaqueSPAdjustment &&
|
||||
HasVAStart == Other.HasVAStart &&
|
||||
HasMustTailInVarArgFunc == Other.HasMustTailInVarArgFunc &&
|
||||
HasTailCall == Other.HasTailCall &&
|
||||
LocalFrameSize == Other.LocalFrameSize &&
|
||||
SavePoint == Other.SavePoint && RestorePoint == Other.RestorePoint;
|
||||
}
|
||||
};
|
||||
|
||||
template <> struct MappingTraits<MachineFrameInfo> {
|
||||
static void mapping(IO &YamlIO, MachineFrameInfo &MFI) {
|
||||
YamlIO.mapOptional("isFrameAddressTaken", MFI.IsFrameAddressTaken, false);
|
||||
YamlIO.mapOptional("isReturnAddressTaken", MFI.IsReturnAddressTaken, false);
|
||||
YamlIO.mapOptional("hasStackMap", MFI.HasStackMap, false);
|
||||
YamlIO.mapOptional("hasPatchPoint", MFI.HasPatchPoint, false);
|
||||
YamlIO.mapOptional("stackSize", MFI.StackSize, (uint64_t)0);
|
||||
YamlIO.mapOptional("offsetAdjustment", MFI.OffsetAdjustment, (int)0);
|
||||
YamlIO.mapOptional("maxAlignment", MFI.MaxAlignment, (unsigned)0);
|
||||
YamlIO.mapOptional("adjustsStack", MFI.AdjustsStack, false);
|
||||
YamlIO.mapOptional("hasCalls", MFI.HasCalls, false);
|
||||
YamlIO.mapOptional("stackProtector", MFI.StackProtector,
|
||||
StringValue()); // Don't print it out when it's empty.
|
||||
YamlIO.mapOptional("maxCallFrameSize", MFI.MaxCallFrameSize, (unsigned)~0);
|
||||
YamlIO.mapOptional("cvBytesOfCalleeSavedRegisters",
|
||||
MFI.CVBytesOfCalleeSavedRegisters, 0U);
|
||||
YamlIO.mapOptional("hasOpaqueSPAdjustment", MFI.HasOpaqueSPAdjustment,
|
||||
false);
|
||||
YamlIO.mapOptional("hasVAStart", MFI.HasVAStart, false);
|
||||
YamlIO.mapOptional("hasMustTailInVarArgFunc", MFI.HasMustTailInVarArgFunc,
|
||||
false);
|
||||
YamlIO.mapOptional("hasTailCall", MFI.HasTailCall, false);
|
||||
YamlIO.mapOptional("localFrameSize", MFI.LocalFrameSize, (unsigned)0);
|
||||
YamlIO.mapOptional("savePoint", MFI.SavePoint,
|
||||
StringValue()); // Don't print it out when it's empty.
|
||||
YamlIO.mapOptional("restorePoint", MFI.RestorePoint,
|
||||
StringValue()); // Don't print it out when it's empty.
|
||||
}
|
||||
};
|
||||
|
||||
/// Targets should override this in a way that mirrors the implementation of
|
||||
/// llvm::MachineFunctionInfo.
|
||||
struct MachineFunctionInfo {
|
||||
virtual ~MachineFunctionInfo() = default;
|
||||
virtual void mappingImpl(IO &YamlIO) {}
|
||||
};
|
||||
|
||||
template <> struct MappingTraits<std::unique_ptr<MachineFunctionInfo>> {
|
||||
static void mapping(IO &YamlIO, std::unique_ptr<MachineFunctionInfo> &MFI) {
|
||||
if (MFI)
|
||||
MFI->mappingImpl(YamlIO);
|
||||
}
|
||||
};
|
||||
|
||||
struct MachineFunction {
|
||||
StringRef Name;
|
||||
MaybeAlign Alignment = None;
|
||||
bool ExposesReturnsTwice = false;
|
||||
// GISel MachineFunctionProperties.
|
||||
bool Legalized = false;
|
||||
bool RegBankSelected = false;
|
||||
bool Selected = false;
|
||||
bool FailedISel = false;
|
||||
// Register information
|
||||
bool TracksRegLiveness = false;
|
||||
bool HasWinCFI = false;
|
||||
bool FailsVerification = false;
|
||||
bool TracksDebugUserValues = false;
|
||||
std::vector<VirtualRegisterDefinition> VirtualRegisters;
|
||||
std::vector<MachineFunctionLiveIn> LiveIns;
|
||||
Optional<std::vector<FlowStringValue>> CalleeSavedRegisters;
|
||||
// TODO: Serialize the various register masks.
|
||||
// Frame information
|
||||
MachineFrameInfo FrameInfo;
|
||||
std::vector<FixedMachineStackObject> FixedStackObjects;
|
||||
std::vector<MachineStackObject> StackObjects;
|
||||
std::vector<MachineConstantPoolValue> Constants; /// Constant pool.
|
||||
std::unique_ptr<MachineFunctionInfo> MachineFuncInfo;
|
||||
std::vector<CallSiteInfo> CallSitesInfo;
|
||||
std::vector<DebugValueSubstitution> DebugValueSubstitutions;
|
||||
MachineJumpTable JumpTableInfo;
|
||||
std::vector<StringValue> MachineMetadataNodes;
|
||||
BlockStringValue Body;
|
||||
};
|
||||
|
||||
template <> struct MappingTraits<MachineFunction> {
|
||||
static void mapping(IO &YamlIO, MachineFunction &MF) {
|
||||
YamlIO.mapRequired("name", MF.Name);
|
||||
YamlIO.mapOptional("alignment", MF.Alignment, None);
|
||||
YamlIO.mapOptional("exposesReturnsTwice", MF.ExposesReturnsTwice, false);
|
||||
YamlIO.mapOptional("legalized", MF.Legalized, false);
|
||||
YamlIO.mapOptional("regBankSelected", MF.RegBankSelected, false);
|
||||
YamlIO.mapOptional("selected", MF.Selected, false);
|
||||
YamlIO.mapOptional("failedISel", MF.FailedISel, false);
|
||||
YamlIO.mapOptional("tracksRegLiveness", MF.TracksRegLiveness, false);
|
||||
YamlIO.mapOptional("hasWinCFI", MF.HasWinCFI, false);
|
||||
YamlIO.mapOptional("failsVerification", MF.FailsVerification, false);
|
||||
YamlIO.mapOptional("tracksDebugUserValues", MF.TracksDebugUserValues,
|
||||
false);
|
||||
YamlIO.mapOptional("registers", MF.VirtualRegisters,
|
||||
std::vector<VirtualRegisterDefinition>());
|
||||
YamlIO.mapOptional("liveins", MF.LiveIns,
|
||||
std::vector<MachineFunctionLiveIn>());
|
||||
YamlIO.mapOptional("calleeSavedRegisters", MF.CalleeSavedRegisters,
|
||||
Optional<std::vector<FlowStringValue>>());
|
||||
YamlIO.mapOptional("frameInfo", MF.FrameInfo, MachineFrameInfo());
|
||||
YamlIO.mapOptional("fixedStack", MF.FixedStackObjects,
|
||||
std::vector<FixedMachineStackObject>());
|
||||
YamlIO.mapOptional("stack", MF.StackObjects,
|
||||
std::vector<MachineStackObject>());
|
||||
YamlIO.mapOptional("callSites", MF.CallSitesInfo,
|
||||
std::vector<CallSiteInfo>());
|
||||
YamlIO.mapOptional("debugValueSubstitutions", MF.DebugValueSubstitutions,
|
||||
std::vector<DebugValueSubstitution>());
|
||||
YamlIO.mapOptional("constants", MF.Constants,
|
||||
std::vector<MachineConstantPoolValue>());
|
||||
YamlIO.mapOptional("machineFunctionInfo", MF.MachineFuncInfo);
|
||||
if (!YamlIO.outputting() || !MF.JumpTableInfo.Entries.empty())
|
||||
YamlIO.mapOptional("jumpTable", MF.JumpTableInfo, MachineJumpTable());
|
||||
if (!YamlIO.outputting() || !MF.MachineMetadataNodes.empty())
|
||||
YamlIO.mapOptional("machineMetadataNodes", MF.MachineMetadataNodes,
|
||||
std::vector<StringValue>());
|
||||
YamlIO.mapOptional("body", MF.Body, BlockStringValue());
|
||||
}
|
||||
};
|
||||
|
||||
} // end namespace yaml
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_MIRYAMLMAPPING_H
|
||||
55
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/MachORelocation.h
vendored
Normal file
55
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/MachORelocation.h
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
//=== MachORelocation.h - Mach-O Relocation Info ----------------*- 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 file defines the MachORelocation class.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
|
||||
#ifndef LLVM_CODEGEN_MACHORELOCATION_H
|
||||
#define LLVM_CODEGEN_MACHORELOCATION_H
|
||||
|
||||
#include "llvm/Support/DataTypes.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// MachORelocation - This struct contains information about each relocation
|
||||
/// that needs to be emitted to the file.
|
||||
/// see <mach-o/reloc.h>
|
||||
class MachORelocation {
|
||||
uint32_t r_address; // offset in the section to what is being relocated
|
||||
uint32_t r_symbolnum; // symbol index if r_extern == 1 else section index
|
||||
bool r_pcrel; // was relocated pc-relative already
|
||||
uint8_t r_length; // length = 2 ^ r_length
|
||||
bool r_extern; //
|
||||
uint8_t r_type; // if not 0, machine-specific relocation type.
|
||||
bool r_scattered; // 1 = scattered, 0 = non-scattered
|
||||
int32_t r_value; // the value the item to be relocated is referring
|
||||
// to.
|
||||
public:
|
||||
uint32_t getPackedFields() const {
|
||||
if (r_scattered)
|
||||
return (1 << 31) | (r_pcrel << 30) | ((r_length & 3) << 28) |
|
||||
((r_type & 15) << 24) | (r_address & 0x00FFFFFF);
|
||||
else
|
||||
return (r_symbolnum << 8) | (r_pcrel << 7) | ((r_length & 3) << 5) |
|
||||
(r_extern << 4) | (r_type & 15);
|
||||
}
|
||||
uint32_t getAddress() const { return r_scattered ? r_value : r_address; }
|
||||
uint32_t getRawAddress() const { return r_address; }
|
||||
|
||||
MachORelocation(uint32_t addr, uint32_t index, bool pcrel, uint8_t len,
|
||||
bool ext, uint8_t type, bool scattered = false,
|
||||
int32_t value = 0) :
|
||||
r_address(addr), r_symbolnum(index), r_pcrel(pcrel), r_length(len),
|
||||
r_extern(ext), r_type(type), r_scattered(scattered), r_value(value) {}
|
||||
};
|
||||
|
||||
} // end llvm namespace
|
||||
|
||||
#endif // LLVM_CODEGEN_MACHORELOCATION_H
|
||||
1270
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/MachineBasicBlock.h
vendored
Normal file
1270
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/MachineBasicBlock.h
vendored
Normal file
File diff suppressed because it is too large
Load Diff
106
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/MachineBlockFrequencyInfo.h
vendored
Normal file
106
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/MachineBlockFrequencyInfo.h
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
//===- MachineBlockFrequencyInfo.h - MBB Frequency Analysis -----*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Loops should be simplified before this analysis.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_MACHINEBLOCKFREQUENCYINFO_H
|
||||
#define LLVM_CODEGEN_MACHINEBLOCKFREQUENCYINFO_H
|
||||
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/Support/BlockFrequency.h"
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
template <class BlockT> class BlockFrequencyInfoImpl;
|
||||
class MachineBasicBlock;
|
||||
class MachineBranchProbabilityInfo;
|
||||
class MachineFunction;
|
||||
class MachineLoopInfo;
|
||||
class raw_ostream;
|
||||
|
||||
/// MachineBlockFrequencyInfo pass uses BlockFrequencyInfoImpl implementation
|
||||
/// to estimate machine basic block frequencies.
|
||||
class MachineBlockFrequencyInfo : public MachineFunctionPass {
|
||||
using ImplType = BlockFrequencyInfoImpl<MachineBasicBlock>;
|
||||
std::unique_ptr<ImplType> MBFI;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
MachineBlockFrequencyInfo();
|
||||
explicit MachineBlockFrequencyInfo(MachineFunction &F,
|
||||
MachineBranchProbabilityInfo &MBPI,
|
||||
MachineLoopInfo &MLI);
|
||||
~MachineBlockFrequencyInfo() override;
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override;
|
||||
|
||||
bool runOnMachineFunction(MachineFunction &F) override;
|
||||
|
||||
/// calculate - compute block frequency info for the given function.
|
||||
void calculate(const MachineFunction &F,
|
||||
const MachineBranchProbabilityInfo &MBPI,
|
||||
const MachineLoopInfo &MLI);
|
||||
|
||||
void releaseMemory() override;
|
||||
|
||||
/// getblockFreq - Return block frequency. Return 0 if we don't have the
|
||||
/// information. Please note that initial frequency is equal to 1024. It means
|
||||
/// that we should not rely on the value itself, but only on the comparison to
|
||||
/// the other block frequencies. We do this to avoid using of floating points.
|
||||
/// For example, to get the frequency of a block relative to the entry block,
|
||||
/// divide the integral value returned by this function (the
|
||||
/// BlockFrequency::getFrequency() value) by getEntryFreq().
|
||||
BlockFrequency getBlockFreq(const MachineBasicBlock *MBB) const;
|
||||
|
||||
/// Compute the frequency of the block, relative to the entry block.
|
||||
/// This API assumes getEntryFreq() is non-zero.
|
||||
float getBlockFreqRelativeToEntryBlock(const MachineBasicBlock *MBB) const {
|
||||
return getBlockFreq(MBB).getFrequency() * (1.0f / getEntryFreq());
|
||||
}
|
||||
|
||||
Optional<uint64_t> getBlockProfileCount(const MachineBasicBlock *MBB) const;
|
||||
Optional<uint64_t> getProfileCountFromFreq(uint64_t Freq) const;
|
||||
|
||||
bool isIrrLoopHeader(const MachineBasicBlock *MBB) const;
|
||||
|
||||
/// incrementally calculate block frequencies when we split edges, to avoid
|
||||
/// full CFG traversal.
|
||||
void onEdgeSplit(const MachineBasicBlock &NewPredecessor,
|
||||
const MachineBasicBlock &NewSuccessor,
|
||||
const MachineBranchProbabilityInfo &MBPI);
|
||||
|
||||
const MachineFunction *getFunction() const;
|
||||
const MachineBranchProbabilityInfo *getMBPI() const;
|
||||
|
||||
/// Pop up a ghostview window with the current block frequency propagation
|
||||
/// rendered using dot.
|
||||
void view(const Twine &Name, bool isSimple = true) const;
|
||||
|
||||
// Print the block frequency Freq to OS using the current functions entry
|
||||
// frequency to convert freq into a relative decimal form.
|
||||
raw_ostream &printBlockFreq(raw_ostream &OS, const BlockFrequency Freq) const;
|
||||
|
||||
// Convenience method that attempts to look up the frequency associated with
|
||||
// BB and print it to OS.
|
||||
raw_ostream &printBlockFreq(raw_ostream &OS,
|
||||
const MachineBasicBlock *MBB) const;
|
||||
|
||||
/// Divide a block's BlockFrequency::getFrequency() value by this value to
|
||||
/// obtain the entry block - relative frequency of said block.
|
||||
uint64_t getEntryFreq() const;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_MACHINEBLOCKFREQUENCYINFO_H
|
||||
69
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/MachineBranchProbabilityInfo.h
vendored
Normal file
69
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/MachineBranchProbabilityInfo.h
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
//=- MachineBranchProbabilityInfo.h - Branch Probability Analysis -*- 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 pass is used to evaluate branch probabilities on machine basic blocks.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_MACHINEBRANCHPROBABILITYINFO_H
|
||||
#define LLVM_CODEGEN_MACHINEBRANCHPROBABILITYINFO_H
|
||||
|
||||
#include "llvm/CodeGen/MachineBasicBlock.h"
|
||||
#include "llvm/Pass.h"
|
||||
#include "llvm/Support/BranchProbability.h"
|
||||
#include <climits>
|
||||
#include <numeric>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MachineBranchProbabilityInfo : public ImmutablePass {
|
||||
virtual void anchor();
|
||||
|
||||
// Default weight value. Used when we don't have information about the edge.
|
||||
// TODO: DEFAULT_WEIGHT makes sense during static predication, when none of
|
||||
// the successors have a weight yet. But it doesn't make sense when providing
|
||||
// weight to an edge that may have siblings with non-zero weights. This can
|
||||
// be handled various ways, but it's probably fine for an edge with unknown
|
||||
// weight to just "inherit" the non-zero weight of an adjacent successor.
|
||||
static const uint32_t DEFAULT_WEIGHT = 16;
|
||||
|
||||
public:
|
||||
static char ID;
|
||||
|
||||
MachineBranchProbabilityInfo();
|
||||
|
||||
void getAnalysisUsage(AnalysisUsage &AU) const override {
|
||||
AU.setPreservesAll();
|
||||
}
|
||||
|
||||
// Return edge probability.
|
||||
BranchProbability getEdgeProbability(const MachineBasicBlock *Src,
|
||||
const MachineBasicBlock *Dst) const;
|
||||
|
||||
// Same as above, but using a const_succ_iterator from Src. This is faster
|
||||
// when the iterator is already available.
|
||||
BranchProbability
|
||||
getEdgeProbability(const MachineBasicBlock *Src,
|
||||
MachineBasicBlock::const_succ_iterator Dst) const;
|
||||
|
||||
// A 'Hot' edge is an edge which probability is >= 80%.
|
||||
bool isEdgeHot(const MachineBasicBlock *Src,
|
||||
const MachineBasicBlock *Dst) const;
|
||||
|
||||
// Print value between 0 (0% probability) and 1 (100% probability),
|
||||
// however the value is never equal to 0, and can be 1 only iff SRC block
|
||||
// has only one successor.
|
||||
raw_ostream &printEdgeProbability(raw_ostream &OS,
|
||||
const MachineBasicBlock *Src,
|
||||
const MachineBasicBlock *Dst) const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
172
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/MachineCombinerPattern.h
vendored
Normal file
172
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/MachineCombinerPattern.h
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
//===-- llvm/CodeGen/MachineCombinerPattern.h - Instruction pattern supported by
|
||||
// combiner ------*- 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 file defines instruction pattern supported by combiner
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_MACHINECOMBINERPATTERN_H
|
||||
#define LLVM_CODEGEN_MACHINECOMBINERPATTERN_H
|
||||
|
||||
namespace llvm {
|
||||
|
||||
/// These are instruction patterns matched by the machine combiner pass.
|
||||
enum class MachineCombinerPattern {
|
||||
// These are commutative variants for reassociating a computation chain. See
|
||||
// the comments before getMachineCombinerPatterns() in TargetInstrInfo.cpp.
|
||||
REASSOC_AX_BY,
|
||||
REASSOC_AX_YB,
|
||||
REASSOC_XA_BY,
|
||||
REASSOC_XA_YB,
|
||||
|
||||
// These are patterns matched by the PowerPC to reassociate FMA chains.
|
||||
REASSOC_XY_AMM_BMM,
|
||||
REASSOC_XMM_AMM_BMM,
|
||||
|
||||
// These are patterns matched by the PowerPC to reassociate FMA and FSUB to
|
||||
// reduce register pressure.
|
||||
REASSOC_XY_BCA,
|
||||
REASSOC_XY_BAC,
|
||||
|
||||
// These are multiply-add patterns matched by the AArch64 machine combiner.
|
||||
MULADDW_OP1,
|
||||
MULADDW_OP2,
|
||||
MULSUBW_OP1,
|
||||
MULSUBW_OP2,
|
||||
MULADDWI_OP1,
|
||||
MULSUBWI_OP1,
|
||||
MULADDX_OP1,
|
||||
MULADDX_OP2,
|
||||
MULSUBX_OP1,
|
||||
MULSUBX_OP2,
|
||||
MULADDXI_OP1,
|
||||
MULSUBXI_OP1,
|
||||
// NEON integers vectors
|
||||
MULADDv8i8_OP1,
|
||||
MULADDv8i8_OP2,
|
||||
MULADDv16i8_OP1,
|
||||
MULADDv16i8_OP2,
|
||||
MULADDv4i16_OP1,
|
||||
MULADDv4i16_OP2,
|
||||
MULADDv8i16_OP1,
|
||||
MULADDv8i16_OP2,
|
||||
MULADDv2i32_OP1,
|
||||
MULADDv2i32_OP2,
|
||||
MULADDv4i32_OP1,
|
||||
MULADDv4i32_OP2,
|
||||
|
||||
MULSUBv8i8_OP1,
|
||||
MULSUBv8i8_OP2,
|
||||
MULSUBv16i8_OP1,
|
||||
MULSUBv16i8_OP2,
|
||||
MULSUBv4i16_OP1,
|
||||
MULSUBv4i16_OP2,
|
||||
MULSUBv8i16_OP1,
|
||||
MULSUBv8i16_OP2,
|
||||
MULSUBv2i32_OP1,
|
||||
MULSUBv2i32_OP2,
|
||||
MULSUBv4i32_OP1,
|
||||
MULSUBv4i32_OP2,
|
||||
|
||||
MULADDv4i16_indexed_OP1,
|
||||
MULADDv4i16_indexed_OP2,
|
||||
MULADDv8i16_indexed_OP1,
|
||||
MULADDv8i16_indexed_OP2,
|
||||
MULADDv2i32_indexed_OP1,
|
||||
MULADDv2i32_indexed_OP2,
|
||||
MULADDv4i32_indexed_OP1,
|
||||
MULADDv4i32_indexed_OP2,
|
||||
|
||||
MULSUBv4i16_indexed_OP1,
|
||||
MULSUBv4i16_indexed_OP2,
|
||||
MULSUBv8i16_indexed_OP1,
|
||||
MULSUBv8i16_indexed_OP2,
|
||||
MULSUBv2i32_indexed_OP1,
|
||||
MULSUBv2i32_indexed_OP2,
|
||||
MULSUBv4i32_indexed_OP1,
|
||||
MULSUBv4i32_indexed_OP2,
|
||||
|
||||
// Floating Point
|
||||
FMULADDH_OP1,
|
||||
FMULADDH_OP2,
|
||||
FMULSUBH_OP1,
|
||||
FMULSUBH_OP2,
|
||||
FMULADDS_OP1,
|
||||
FMULADDS_OP2,
|
||||
FMULSUBS_OP1,
|
||||
FMULSUBS_OP2,
|
||||
FMULADDD_OP1,
|
||||
FMULADDD_OP2,
|
||||
FMULSUBD_OP1,
|
||||
FMULSUBD_OP2,
|
||||
FNMULSUBH_OP1,
|
||||
FNMULSUBS_OP1,
|
||||
FNMULSUBD_OP1,
|
||||
FMLAv1i32_indexed_OP1,
|
||||
FMLAv1i32_indexed_OP2,
|
||||
FMLAv1i64_indexed_OP1,
|
||||
FMLAv1i64_indexed_OP2,
|
||||
FMLAv4f16_OP1,
|
||||
FMLAv4f16_OP2,
|
||||
FMLAv8f16_OP1,
|
||||
FMLAv8f16_OP2,
|
||||
FMLAv2f32_OP2,
|
||||
FMLAv2f32_OP1,
|
||||
FMLAv2f64_OP1,
|
||||
FMLAv2f64_OP2,
|
||||
FMLAv4i16_indexed_OP1,
|
||||
FMLAv4i16_indexed_OP2,
|
||||
FMLAv8i16_indexed_OP1,
|
||||
FMLAv8i16_indexed_OP2,
|
||||
FMLAv2i32_indexed_OP1,
|
||||
FMLAv2i32_indexed_OP2,
|
||||
FMLAv2i64_indexed_OP1,
|
||||
FMLAv2i64_indexed_OP2,
|
||||
FMLAv4f32_OP1,
|
||||
FMLAv4f32_OP2,
|
||||
FMLAv4i32_indexed_OP1,
|
||||
FMLAv4i32_indexed_OP2,
|
||||
FMLSv1i32_indexed_OP2,
|
||||
FMLSv1i64_indexed_OP2,
|
||||
FMLSv4f16_OP1,
|
||||
FMLSv4f16_OP2,
|
||||
FMLSv8f16_OP1,
|
||||
FMLSv8f16_OP2,
|
||||
FMLSv2f32_OP1,
|
||||
FMLSv2f32_OP2,
|
||||
FMLSv2f64_OP1,
|
||||
FMLSv2f64_OP2,
|
||||
FMLSv4i16_indexed_OP1,
|
||||
FMLSv4i16_indexed_OP2,
|
||||
FMLSv8i16_indexed_OP1,
|
||||
FMLSv8i16_indexed_OP2,
|
||||
FMLSv2i32_indexed_OP1,
|
||||
FMLSv2i32_indexed_OP2,
|
||||
FMLSv2i64_indexed_OP1,
|
||||
FMLSv2i64_indexed_OP2,
|
||||
FMLSv4f32_OP1,
|
||||
FMLSv4f32_OP2,
|
||||
FMLSv4i32_indexed_OP1,
|
||||
FMLSv4i32_indexed_OP2,
|
||||
|
||||
FMULv2i32_indexed_OP1,
|
||||
FMULv2i32_indexed_OP2,
|
||||
FMULv2i64_indexed_OP1,
|
||||
FMULv2i64_indexed_OP2,
|
||||
FMULv4i16_indexed_OP1,
|
||||
FMULv4i16_indexed_OP2,
|
||||
FMULv4i32_indexed_OP1,
|
||||
FMULv4i32_indexed_OP2,
|
||||
FMULv8i16_indexed_OP1,
|
||||
FMULv8i16_indexed_OP2,
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
||||
159
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/MachineConstantPool.h
vendored
Normal file
159
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/MachineConstantPool.h
vendored
Normal file
@@ -0,0 +1,159 @@
|
||||
//===- CodeGen/MachineConstantPool.h - Abstract Constant Pool ---*- 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
/// @file
|
||||
/// This file declares the MachineConstantPool class which is an abstract
|
||||
/// constant pool to keep track of constants referenced by a function.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_MACHINECONSTANTPOOL_H
|
||||
#define LLVM_CODEGEN_MACHINECONSTANTPOOL_H
|
||||
|
||||
#include "llvm/ADT/DenseSet.h"
|
||||
#include "llvm/MC/SectionKind.h"
|
||||
#include "llvm/Support/Alignment.h"
|
||||
#include <climits>
|
||||
#include <vector>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class Constant;
|
||||
class DataLayout;
|
||||
class FoldingSetNodeID;
|
||||
class MachineConstantPool;
|
||||
class raw_ostream;
|
||||
class Type;
|
||||
|
||||
/// Abstract base class for all machine specific constantpool value subclasses.
|
||||
///
|
||||
class MachineConstantPoolValue {
|
||||
virtual void anchor();
|
||||
|
||||
Type *Ty;
|
||||
|
||||
public:
|
||||
explicit MachineConstantPoolValue(Type *ty) : Ty(ty) {}
|
||||
virtual ~MachineConstantPoolValue() = default;
|
||||
|
||||
Type *getType() const { return Ty; }
|
||||
|
||||
virtual unsigned getSizeInBytes(const DataLayout &DL) const;
|
||||
|
||||
virtual int getExistingMachineCPValue(MachineConstantPool *CP,
|
||||
Align Alignment) = 0;
|
||||
|
||||
virtual void addSelectionDAGCSEId(FoldingSetNodeID &ID) = 0;
|
||||
|
||||
/// print - Implement operator<<
|
||||
virtual void print(raw_ostream &O) const = 0;
|
||||
};
|
||||
|
||||
inline raw_ostream &operator<<(raw_ostream &OS,
|
||||
const MachineConstantPoolValue &V) {
|
||||
V.print(OS);
|
||||
return OS;
|
||||
}
|
||||
|
||||
/// This class is a data container for one entry in a MachineConstantPool.
|
||||
/// It contains a pointer to the value and an offset from the start of
|
||||
/// the constant pool.
|
||||
/// An entry in a MachineConstantPool
|
||||
class MachineConstantPoolEntry {
|
||||
public:
|
||||
/// The constant itself.
|
||||
union {
|
||||
const Constant *ConstVal;
|
||||
MachineConstantPoolValue *MachineCPVal;
|
||||
} Val;
|
||||
|
||||
/// The required alignment for this entry.
|
||||
Align Alignment;
|
||||
|
||||
bool IsMachineConstantPoolEntry;
|
||||
|
||||
MachineConstantPoolEntry(const Constant *V, Align A)
|
||||
: Alignment(A), IsMachineConstantPoolEntry(false) {
|
||||
Val.ConstVal = V;
|
||||
}
|
||||
|
||||
MachineConstantPoolEntry(MachineConstantPoolValue *V, Align A)
|
||||
: Alignment(A), IsMachineConstantPoolEntry(true) {
|
||||
Val.MachineCPVal = V;
|
||||
}
|
||||
|
||||
/// isMachineConstantPoolEntry - Return true if the MachineConstantPoolEntry
|
||||
/// is indeed a target specific constantpool entry, not a wrapper over a
|
||||
/// Constant.
|
||||
bool isMachineConstantPoolEntry() const { return IsMachineConstantPoolEntry; }
|
||||
|
||||
Align getAlign() const { return Alignment; }
|
||||
|
||||
unsigned getSizeInBytes(const DataLayout &DL) const;
|
||||
|
||||
/// This method classifies the entry according to whether or not it may
|
||||
/// generate a relocation entry. This must be conservative, so if it might
|
||||
/// codegen to a relocatable entry, it should say so.
|
||||
bool needsRelocation() const;
|
||||
|
||||
SectionKind getSectionKind(const DataLayout *DL) const;
|
||||
};
|
||||
|
||||
/// The MachineConstantPool class keeps track of constants referenced by a
|
||||
/// function which must be spilled to memory. This is used for constants which
|
||||
/// are unable to be used directly as operands to instructions, which typically
|
||||
/// include floating point and large integer constants.
|
||||
///
|
||||
/// Instructions reference the address of these constant pool constants through
|
||||
/// the use of MO_ConstantPoolIndex values. When emitting assembly or machine
|
||||
/// code, these virtual address references are converted to refer to the
|
||||
/// address of the function constant pool values.
|
||||
/// The machine constant pool.
|
||||
class MachineConstantPool {
|
||||
Align PoolAlignment; ///< The alignment for the pool.
|
||||
std::vector<MachineConstantPoolEntry> Constants; ///< The pool of constants.
|
||||
/// MachineConstantPoolValues that use an existing MachineConstantPoolEntry.
|
||||
DenseSet<MachineConstantPoolValue*> MachineCPVsSharingEntries;
|
||||
const DataLayout &DL;
|
||||
|
||||
const DataLayout &getDataLayout() const { return DL; }
|
||||
|
||||
public:
|
||||
/// The only constructor.
|
||||
explicit MachineConstantPool(const DataLayout &DL)
|
||||
: PoolAlignment(1), DL(DL) {}
|
||||
~MachineConstantPool();
|
||||
|
||||
/// Return the alignment required by the whole constant pool, of which the
|
||||
/// first element must be aligned.
|
||||
Align getConstantPoolAlign() const { return PoolAlignment; }
|
||||
|
||||
/// getConstantPoolIndex - Create a new entry in the constant pool or return
|
||||
/// an existing one. User must specify the minimum required alignment for
|
||||
/// the object.
|
||||
unsigned getConstantPoolIndex(const Constant *C, Align Alignment);
|
||||
unsigned getConstantPoolIndex(MachineConstantPoolValue *V, Align Alignment);
|
||||
|
||||
/// isEmpty - Return true if this constant pool contains no constants.
|
||||
bool isEmpty() const { return Constants.empty(); }
|
||||
|
||||
const std::vector<MachineConstantPoolEntry> &getConstants() const {
|
||||
return Constants;
|
||||
}
|
||||
|
||||
/// print - Used by the MachineFunction printer to print information about
|
||||
/// constant pool objects. Implemented in MachineFunction.cpp
|
||||
void print(raw_ostream &OS) const;
|
||||
|
||||
/// dump - Call print(cerr) to be called from the debugger.
|
||||
void dump() const;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_MACHINECONSTANTPOOL_H
|
||||
31
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/MachineCycleAnalysis.h
vendored
Normal file
31
thirdparty/capstone/suite/synctools/tablegen/include/llvm/CodeGen/MachineCycleAnalysis.h
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
//===- MachineCycleAnalysis.h - Cycle Info for Machine IR -------*- 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 file defines the MachineCycleInfo class, which is a thin wrapper over
|
||||
// the Machine IR instance of GenericCycleInfo.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CODEGEN_MACHINECYCLEANALYSIS_H
|
||||
#define LLVM_CODEGEN_MACHINECYCLEANALYSIS_H
|
||||
|
||||
#include "llvm/ADT/GenericCycleInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunctionPass.h"
|
||||
#include "llvm/CodeGen/MachineSSAContext.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
extern template class GenericCycleInfo<MachineSSAContext>;
|
||||
extern template class GenericCycle<MachineSSAContext>;
|
||||
|
||||
using MachineCycleInfo = GenericCycleInfo<MachineSSAContext>;
|
||||
using MachineCycle = MachineCycleInfo::CycleT;
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif // LLVM_CODEGEN_MACHINECYCLEANALYSIS_H
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user