Initial Commit

This commit is contained in:
Sajid
2024-09-07 18:00:09 +06:00
commit 0f9a53f75a
3352 changed files with 1563708 additions and 0 deletions

View 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

View 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

View 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

View 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

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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_ */

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

View File

@@ -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

View 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

View 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

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View File

@@ -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

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

View 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

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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

View 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

View 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

View File

@@ -0,0 +1,109 @@
//===- llvm/CodeGen/MachineDominanceFrontier.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_MACHINEDOMINANCEFRONTIER_H
#define LLVM_CODEGEN_MACHINEDOMINANCEFRONTIER_H
#include "llvm/Analysis/DominanceFrontier.h"
#include "llvm/Analysis/DominanceFrontierImpl.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/Support/GenericDomTree.h"
namespace llvm {
class MachineDominanceFrontier : public MachineFunctionPass {
ForwardDominanceFrontierBase<MachineBasicBlock> Base;
public:
using DomTreeT = DomTreeBase<MachineBasicBlock>;
using DomTreeNodeT = DomTreeNodeBase<MachineBasicBlock>;
using DomSetType = DominanceFrontierBase<MachineBasicBlock, false>::DomSetType;
using iterator = DominanceFrontierBase<MachineBasicBlock, false>::iterator;
using const_iterator =
DominanceFrontierBase<MachineBasicBlock, false>::const_iterator;
MachineDominanceFrontier(const MachineDominanceFrontier &) = delete;
MachineDominanceFrontier &operator=(const MachineDominanceFrontier &) = delete;
static char ID;
MachineDominanceFrontier();
ForwardDominanceFrontierBase<MachineBasicBlock> &getBase() { return Base; }
const SmallVectorImpl<MachineBasicBlock *> &getRoots() const {
return Base.getRoots();
}
MachineBasicBlock *getRoot() const {
return Base.getRoot();
}
bool isPostDominator() const {
return Base.isPostDominator();
}
iterator begin() {
return Base.begin();
}
const_iterator begin() const {
return Base.begin();
}
iterator end() {
return Base.end();
}
const_iterator end() const {
return Base.end();
}
iterator find(MachineBasicBlock *B) {
return Base.find(B);
}
const_iterator find(MachineBasicBlock *B) const {
return Base.find(B);
}
iterator addBasicBlock(MachineBasicBlock *BB, const DomSetType &frontier) {
return Base.addBasicBlock(BB, frontier);
}
void removeBlock(MachineBasicBlock *BB) {
return Base.removeBlock(BB);
}
void addToFrontier(iterator I, MachineBasicBlock *Node) {
return Base.addToFrontier(I, Node);
}
void removeFromFrontier(iterator I, MachineBasicBlock *Node) {
return Base.removeFromFrontier(I, Node);
}
bool compareDomSet(DomSetType &DS1, const DomSetType &DS2) const {
return Base.compareDomSet(DS1, DS2);
}
bool compare(DominanceFrontierBase<MachineBasicBlock, false> &Other) const {
return Base.compare(Other);
}
bool runOnMachineFunction(MachineFunction &F) override;
void releaseMemory() override;
void getAnalysisUsage(AnalysisUsage &AU) const override;
};
} // end namespace llvm
#endif // LLVM_CODEGEN_MACHINEDOMINANCEFRONTIER_H

View File

@@ -0,0 +1,287 @@
//==- llvm/CodeGen/MachineDominators.h - Machine Dom Calculation -*- 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 classes mirroring those in llvm/Analysis/Dominators.h,
// but for target-specific code rather than target-independent IR.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CODEGEN_MACHINEDOMINATORS_H
#define LLVM_CODEGEN_MACHINEDOMINATORS_H
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/Support/GenericDomTree.h"
#include "llvm/Support/GenericDomTreeConstruction.h"
#include <cassert>
#include <memory>
namespace llvm {
template <>
inline void DominatorTreeBase<MachineBasicBlock, false>::addRoot(
MachineBasicBlock *MBB) {
this->Roots.push_back(MBB);
}
extern template class DomTreeNodeBase<MachineBasicBlock>;
extern template class DominatorTreeBase<MachineBasicBlock, false>; // DomTree
extern template class DominatorTreeBase<MachineBasicBlock, true>; // PostDomTree
using MachineDomTree = DomTreeBase<MachineBasicBlock>;
using MachineDomTreeNode = DomTreeNodeBase<MachineBasicBlock>;
//===-------------------------------------
/// DominatorTree Class - Concrete subclass of DominatorTreeBase that is used to
/// compute a normal dominator tree.
///
class MachineDominatorTree : public MachineFunctionPass {
/// Helper structure used to hold all the basic blocks
/// involved in the split of a critical edge.
struct CriticalEdge {
MachineBasicBlock *FromBB;
MachineBasicBlock *ToBB;
MachineBasicBlock *NewBB;
};
/// Pile up all the critical edges to be split.
/// The splitting of a critical edge is local and thus, it is possible
/// to apply several of those changes at the same time.
mutable SmallVector<CriticalEdge, 32> CriticalEdgesToSplit;
/// Remember all the basic blocks that are inserted during
/// edge splitting.
/// Invariant: NewBBs == all the basic blocks contained in the NewBB
/// field of all the elements of CriticalEdgesToSplit.
/// I.e., forall elt in CriticalEdgesToSplit, it exists BB in NewBBs
/// such as BB == elt.NewBB.
mutable SmallSet<MachineBasicBlock *, 32> NewBBs;
/// The DominatorTreeBase that is used to compute a normal dominator tree.
std::unique_ptr<MachineDomTree> DT;
/// Apply all the recorded critical edges to the DT.
/// This updates the underlying DT information in a way that uses
/// the fast query path of DT as much as possible.
///
/// \post CriticalEdgesToSplit.empty().
void applySplitCriticalEdges() const;
public:
static char ID; // Pass ID, replacement for typeid
MachineDominatorTree();
explicit MachineDominatorTree(MachineFunction &MF) : MachineFunctionPass(ID) {
calculate(MF);
}
MachineDomTree &getBase() {
if (!DT)
DT.reset(new MachineDomTree());
applySplitCriticalEdges();
return *DT;
}
void getAnalysisUsage(AnalysisUsage &AU) const override;
MachineBasicBlock *getRoot() const {
applySplitCriticalEdges();
return DT->getRoot();
}
MachineDomTreeNode *getRootNode() const {
applySplitCriticalEdges();
return DT->getRootNode();
}
bool runOnMachineFunction(MachineFunction &F) override;
void calculate(MachineFunction &F);
bool dominates(const MachineDomTreeNode *A,
const MachineDomTreeNode *B) const {
applySplitCriticalEdges();
return DT->dominates(A, B);
}
void getDescendants(MachineBasicBlock *A,
SmallVectorImpl<MachineBasicBlock *> &Result) {
applySplitCriticalEdges();
DT->getDescendants(A, Result);
}
bool dominates(const MachineBasicBlock *A, const MachineBasicBlock *B) const {
applySplitCriticalEdges();
return DT->dominates(A, B);
}
// dominates - Return true if A dominates B. This performs the
// special checks necessary if A and B are in the same basic block.
bool dominates(const MachineInstr *A, const MachineInstr *B) const {
applySplitCriticalEdges();
const MachineBasicBlock *BBA = A->getParent(), *BBB = B->getParent();
if (BBA != BBB) return DT->dominates(BBA, BBB);
// Loop through the basic block until we find A or B.
MachineBasicBlock::const_iterator I = BBA->begin();
for (; &*I != A && &*I != B; ++I)
/*empty*/ ;
return &*I == A;
}
bool properlyDominates(const MachineDomTreeNode *A,
const MachineDomTreeNode *B) const {
applySplitCriticalEdges();
return DT->properlyDominates(A, B);
}
bool properlyDominates(const MachineBasicBlock *A,
const MachineBasicBlock *B) const {
applySplitCriticalEdges();
return DT->properlyDominates(A, B);
}
/// findNearestCommonDominator - Find nearest common dominator basic block
/// for basic block A and B. If there is no such block then return NULL.
MachineBasicBlock *findNearestCommonDominator(MachineBasicBlock *A,
MachineBasicBlock *B) {
applySplitCriticalEdges();
return DT->findNearestCommonDominator(A, B);
}
MachineDomTreeNode *operator[](MachineBasicBlock *BB) const {
applySplitCriticalEdges();
return DT->getNode(BB);
}
/// getNode - return the (Post)DominatorTree node for the specified basic
/// block. This is the same as using operator[] on this class.
///
MachineDomTreeNode *getNode(MachineBasicBlock *BB) const {
applySplitCriticalEdges();
return DT->getNode(BB);
}
/// addNewBlock - Add a new node to the dominator tree information. This
/// creates a new node as a child of DomBB dominator node,linking it into
/// the children list of the immediate dominator.
MachineDomTreeNode *addNewBlock(MachineBasicBlock *BB,
MachineBasicBlock *DomBB) {
applySplitCriticalEdges();
return DT->addNewBlock(BB, DomBB);
}
/// changeImmediateDominator - This method is used to update the dominator
/// tree information when a node's immediate dominator changes.
///
void changeImmediateDominator(MachineBasicBlock *N,
MachineBasicBlock *NewIDom) {
applySplitCriticalEdges();
DT->changeImmediateDominator(N, NewIDom);
}
void changeImmediateDominator(MachineDomTreeNode *N,
MachineDomTreeNode *NewIDom) {
applySplitCriticalEdges();
DT->changeImmediateDominator(N, NewIDom);
}
/// eraseNode - Removes a node from the dominator tree. Block must not
/// dominate any other blocks. Removes node from its immediate dominator's
/// children list. Deletes dominator node associated with basic block BB.
void eraseNode(MachineBasicBlock *BB) {
applySplitCriticalEdges();
DT->eraseNode(BB);
}
/// splitBlock - BB is split and now it has one successor. Update dominator
/// tree to reflect this change.
void splitBlock(MachineBasicBlock* NewBB) {
applySplitCriticalEdges();
DT->splitBlock(NewBB);
}
/// isReachableFromEntry - Return true if A is dominated by the entry
/// block of the function containing it.
bool isReachableFromEntry(const MachineBasicBlock *A) {
applySplitCriticalEdges();
return DT->isReachableFromEntry(A);
}
void releaseMemory() override;
void verifyAnalysis() const override;
void print(raw_ostream &OS, const Module*) const override;
/// Record that the critical edge (FromBB, ToBB) has been
/// split with NewBB.
/// This is best to use this method instead of directly update the
/// underlying information, because this helps mitigating the
/// number of time the DT information is invalidated.
///
/// \note Do not use this method with regular edges.
///
/// \note To benefit from the compile time improvement incurred by this
/// method, the users of this method have to limit the queries to the DT
/// interface between two edges splitting. In other words, they have to
/// pack the splitting of critical edges as much as possible.
void recordSplitCriticalEdge(MachineBasicBlock *FromBB,
MachineBasicBlock *ToBB,
MachineBasicBlock *NewBB) {
bool Inserted = NewBBs.insert(NewBB).second;
(void)Inserted;
assert(Inserted &&
"A basic block inserted via edge splitting cannot appear twice");
CriticalEdgesToSplit.push_back({FromBB, ToBB, NewBB});
}
};
//===-------------------------------------
/// DominatorTree GraphTraits specialization so the DominatorTree can be
/// iterable by generic graph iterators.
///
template <class Node, class ChildIterator>
struct MachineDomTreeGraphTraitsBase {
using NodeRef = Node *;
using ChildIteratorType = ChildIterator;
static NodeRef getEntryNode(NodeRef N) { return N; }
static ChildIteratorType child_begin(NodeRef N) { return N->begin(); }
static ChildIteratorType child_end(NodeRef N) { return N->end(); }
};
template <class T> struct GraphTraits;
template <>
struct GraphTraits<MachineDomTreeNode *>
: public MachineDomTreeGraphTraitsBase<MachineDomTreeNode,
MachineDomTreeNode::const_iterator> {
};
template <>
struct GraphTraits<const MachineDomTreeNode *>
: public MachineDomTreeGraphTraitsBase<const MachineDomTreeNode,
MachineDomTreeNode::const_iterator> {
};
template <> struct GraphTraits<MachineDominatorTree*>
: public GraphTraits<MachineDomTreeNode *> {
static NodeRef getEntryNode(MachineDominatorTree *DT) {
return DT->getRootNode();
}
};
} // end namespace llvm
#endif // LLVM_CODEGEN_MACHINEDOMINATORS_H

View File

@@ -0,0 +1,796 @@
//===-- CodeGen/MachineFrameInfo.h - Abstract Stack Frame Rep. --*- 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 file defines the MachineFrameInfo class.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CODEGEN_MACHINEFRAMEINFO_H
#define LLVM_CODEGEN_MACHINEFRAMEINFO_H
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/Register.h"
#include "llvm/Support/Alignment.h"
#include "llvm/Support/DataTypes.h"
#include <cassert>
#include <vector>
namespace llvm {
class raw_ostream;
class MachineFunction;
class MachineBasicBlock;
class BitVector;
class AllocaInst;
/// The CalleeSavedInfo class tracks the information need to locate where a
/// callee saved register is in the current frame.
/// Callee saved reg can also be saved to a different register rather than
/// on the stack by setting DstReg instead of FrameIdx.
class CalleeSavedInfo {
Register Reg;
union {
int FrameIdx;
unsigned DstReg;
};
/// Flag indicating whether the register is actually restored in the epilog.
/// In most cases, if a register is saved, it is also restored. There are
/// some situations, though, when this is not the case. For example, the
/// LR register on ARM is usually saved, but on exit from the function its
/// saved value may be loaded directly into PC. Since liveness tracking of
/// physical registers treats callee-saved registers are live outside of
/// the function, LR would be treated as live-on-exit, even though in these
/// scenarios it is not. This flag is added to indicate that the saved
/// register described by this object is not restored in the epilog.
/// The long-term solution is to model the liveness of callee-saved registers
/// by implicit uses on the return instructions, however, the required
/// changes in the ARM backend would be quite extensive.
bool Restored = true;
/// Flag indicating whether the register is spilled to stack or another
/// register.
bool SpilledToReg = false;
public:
explicit CalleeSavedInfo(unsigned R, int FI = 0) : Reg(R), FrameIdx(FI) {}
// Accessors.
Register getReg() const { return Reg; }
int getFrameIdx() const { return FrameIdx; }
unsigned getDstReg() const { return DstReg; }
void setFrameIdx(int FI) {
FrameIdx = FI;
SpilledToReg = false;
}
void setDstReg(Register SpillReg) {
DstReg = SpillReg;
SpilledToReg = true;
}
bool isRestored() const { return Restored; }
void setRestored(bool R) { Restored = R; }
bool isSpilledToReg() const { return SpilledToReg; }
};
/// The MachineFrameInfo class represents an abstract stack frame until
/// prolog/epilog code is inserted. This class is key to allowing stack frame
/// representation optimizations, such as frame pointer elimination. It also
/// allows more mundane (but still important) optimizations, such as reordering
/// of abstract objects on the stack frame.
///
/// To support this, the class assigns unique integer identifiers to stack
/// objects requested clients. These identifiers are negative integers for
/// fixed stack objects (such as arguments passed on the stack) or nonnegative
/// for objects that may be reordered. Instructions which refer to stack
/// objects use a special MO_FrameIndex operand to represent these frame
/// indexes.
///
/// Because this class keeps track of all references to the stack frame, it
/// knows when a variable sized object is allocated on the stack. This is the
/// sole condition which prevents frame pointer elimination, which is an
/// important optimization on register-poor architectures. Because original
/// variable sized alloca's in the source program are the only source of
/// variable sized stack objects, it is safe to decide whether there will be
/// any variable sized objects before all stack objects are known (for
/// example, register allocator spill code never needs variable sized
/// objects).
///
/// When prolog/epilog code emission is performed, the final stack frame is
/// built and the machine instructions are modified to refer to the actual
/// stack offsets of the object, eliminating all MO_FrameIndex operands from
/// the program.
///
/// Abstract Stack Frame Information
class MachineFrameInfo {
public:
/// Stack Smashing Protection (SSP) rules require that vulnerable stack
/// allocations are located close the stack protector.
enum SSPLayoutKind {
SSPLK_None, ///< Did not trigger a stack protector. No effect on data
///< layout.
SSPLK_LargeArray, ///< Array or nested array >= SSP-buffer-size. Closest
///< to the stack protector.
SSPLK_SmallArray, ///< Array or nested array < SSP-buffer-size. 2nd closest
///< to the stack protector.
SSPLK_AddrOf ///< The address of this allocation is exposed and
///< triggered protection. 3rd closest to the protector.
};
private:
// Represent a single object allocated on the stack.
struct StackObject {
// The offset of this object from the stack pointer on entry to
// the function. This field has no meaning for a variable sized element.
int64_t SPOffset;
// The size of this object on the stack. 0 means a variable sized object,
// ~0ULL means a dead object.
uint64_t Size;
// The required alignment of this stack slot.
Align Alignment;
// If true, the value of the stack object is set before
// entering the function and is not modified inside the function. By
// default, fixed objects are immutable unless marked otherwise.
bool isImmutable;
// If true the stack object is used as spill slot. It
// cannot alias any other memory objects.
bool isSpillSlot;
/// If true, this stack slot is used to spill a value (could be deopt
/// and/or GC related) over a statepoint. We know that the address of the
/// slot can't alias any LLVM IR value. This is very similar to a Spill
/// Slot, but is created by statepoint lowering is SelectionDAG, not the
/// register allocator.
bool isStatepointSpillSlot = false;
/// Identifier for stack memory type analogous to address space. If this is
/// non-0, the meaning is target defined. Offsets cannot be directly
/// compared between objects with different stack IDs. The object may not
/// necessarily reside in the same contiguous memory block as other stack
/// objects. Objects with differing stack IDs should not be merged or
/// replaced substituted for each other.
//
/// It is assumed a target uses consecutive, increasing stack IDs starting
/// from 1.
uint8_t StackID;
/// If this stack object is originated from an Alloca instruction
/// this value saves the original IR allocation. Can be NULL.
const AllocaInst *Alloca;
// If true, the object was mapped into the local frame
// block and doesn't need additional handling for allocation beyond that.
bool PreAllocated = false;
// If true, an LLVM IR value might point to this object.
// Normally, spill slots and fixed-offset objects don't alias IR-accessible
// objects, but there are exceptions (on PowerPC, for example, some byval
// arguments have ABI-prescribed offsets).
bool isAliased;
/// If true, the object has been zero-extended.
bool isZExt = false;
/// If true, the object has been sign-extended.
bool isSExt = false;
uint8_t SSPLayout = SSPLK_None;
StackObject(uint64_t Size, Align Alignment, int64_t SPOffset,
bool IsImmutable, bool IsSpillSlot, const AllocaInst *Alloca,
bool IsAliased, uint8_t StackID = 0)
: SPOffset(SPOffset), Size(Size), Alignment(Alignment),
isImmutable(IsImmutable), isSpillSlot(IsSpillSlot), StackID(StackID),
Alloca(Alloca), isAliased(IsAliased) {}
};
/// The alignment of the stack.
Align StackAlignment;
/// Can the stack be realigned. This can be false if the target does not
/// support stack realignment, or if the user asks us not to realign the
/// stack. In this situation, overaligned allocas are all treated as dynamic
/// allocations and the target must handle them as part of DYNAMIC_STACKALLOC
/// lowering. All non-alloca stack objects have their alignment clamped to the
/// base ABI stack alignment.
/// FIXME: There is room for improvement in this case, in terms of
/// grouping overaligned allocas into a "secondary stack frame" and
/// then only use a single alloca to allocate this frame and only a
/// single virtual register to access it. Currently, without such an
/// optimization, each such alloca gets its own dynamic realignment.
bool StackRealignable;
/// Whether the function has the \c alignstack attribute.
bool ForcedRealign;
/// The list of stack objects allocated.
std::vector<StackObject> Objects;
/// This contains the number of fixed objects contained on
/// the stack. Because fixed objects are stored at a negative index in the
/// Objects list, this is also the index to the 0th object in the list.
unsigned NumFixedObjects = 0;
/// This boolean keeps track of whether any variable
/// sized objects have been allocated yet.
bool HasVarSizedObjects = false;
/// This boolean keeps track of whether there is a call
/// to builtin \@llvm.frameaddress.
bool FrameAddressTaken = false;
/// This boolean keeps track of whether there is a call
/// to builtin \@llvm.returnaddress.
bool ReturnAddressTaken = false;
/// This boolean keeps track of whether there is a call
/// to builtin \@llvm.experimental.stackmap.
bool HasStackMap = false;
/// This boolean keeps track of whether there is a call
/// to builtin \@llvm.experimental.patchpoint.
bool HasPatchPoint = false;
/// The prolog/epilog code inserter calculates the final stack
/// offsets for all of the fixed size objects, updating the Objects list
/// above. It then updates StackSize to contain the number of bytes that need
/// to be allocated on entry to the function.
uint64_t StackSize = 0;
/// The amount that a frame offset needs to be adjusted to
/// have the actual offset from the stack/frame pointer. The exact usage of
/// this is target-dependent, but it is typically used to adjust between
/// SP-relative and FP-relative offsets. E.G., if objects are accessed via
/// SP then OffsetAdjustment is zero; if FP is used, OffsetAdjustment is set
/// to the distance between the initial SP and the value in FP. For many
/// targets, this value is only used when generating debug info (via
/// TargetRegisterInfo::getFrameIndexReference); when generating code, the
/// corresponding adjustments are performed directly.
int OffsetAdjustment = 0;
/// The prolog/epilog code inserter may process objects that require greater
/// alignment than the default alignment the target provides.
/// To handle this, MaxAlignment is set to the maximum alignment
/// needed by the objects on the current frame. If this is greater than the
/// native alignment maintained by the compiler, dynamic alignment code will
/// be needed.
///
Align MaxAlignment;
/// Set to true if this function adjusts the stack -- e.g.,
/// when calling another function. This is only valid during and after
/// prolog/epilog code insertion.
bool AdjustsStack = false;
/// Set to true if this function has any function calls.
bool HasCalls = false;
/// The frame index for the stack protector.
int StackProtectorIdx = -1;
/// The frame index for the function context. Used for SjLj exceptions.
int FunctionContextIdx = -1;
/// This contains the size of the largest call frame if the target uses frame
/// setup/destroy pseudo instructions (as defined in the TargetFrameInfo
/// class). This information is important for frame pointer elimination.
/// It is only valid during and after prolog/epilog code insertion.
unsigned MaxCallFrameSize = ~0u;
/// The number of bytes of callee saved registers that the target wants to
/// report for the current function in the CodeView S_FRAMEPROC record.
unsigned CVBytesOfCalleeSavedRegisters = 0;
/// The prolog/epilog code inserter fills in this vector with each
/// callee saved register saved in either the frame or a different
/// register. Beyond its use by the prolog/ epilog code inserter,
/// this data is used for debug info and exception handling.
std::vector<CalleeSavedInfo> CSInfo;
/// Has CSInfo been set yet?
bool CSIValid = false;
/// References to frame indices which are mapped
/// into the local frame allocation block. <FrameIdx, LocalOffset>
SmallVector<std::pair<int, int64_t>, 32> LocalFrameObjects;
/// Size of the pre-allocated local frame block.
int64_t LocalFrameSize = 0;
/// Required alignment of the local object blob, which is the strictest
/// alignment of any object in it.
Align LocalFrameMaxAlign;
/// Whether the local object blob needs to be allocated together. If not,
/// PEI should ignore the isPreAllocated flags on the stack objects and
/// just allocate them normally.
bool UseLocalStackAllocationBlock = false;
/// True if the function dynamically adjusts the stack pointer through some
/// opaque mechanism like inline assembly or Win32 EH.
bool HasOpaqueSPAdjustment = false;
/// True if the function contains operations which will lower down to
/// instructions which manipulate the stack pointer.
bool HasCopyImplyingStackAdjustment = false;
/// True if the function contains a call to the llvm.vastart intrinsic.
bool HasVAStart = false;
/// True if this is a varargs function that contains a musttail call.
bool HasMustTailInVarArgFunc = false;
/// True if this function contains a tail call. If so immutable objects like
/// function arguments are no longer so. A tail call *can* override fixed
/// stack objects like arguments so we can't treat them as immutable.
bool HasTailCall = false;
/// Not null, if shrink-wrapping found a better place for the prologue.
MachineBasicBlock *Save = nullptr;
/// Not null, if shrink-wrapping found a better place for the epilogue.
MachineBasicBlock *Restore = nullptr;
public:
explicit MachineFrameInfo(unsigned StackAlignment, bool StackRealignable,
bool ForcedRealign)
: StackAlignment(assumeAligned(StackAlignment)),
StackRealignable(StackRealignable), ForcedRealign(ForcedRealign) {}
MachineFrameInfo(const MachineFrameInfo &) = delete;
/// Return true if there are any stack objects in this function.
bool hasStackObjects() const { return !Objects.empty(); }
/// This method may be called any time after instruction
/// selection is complete to determine if the stack frame for this function
/// contains any variable sized objects.
bool hasVarSizedObjects() const { return HasVarSizedObjects; }
/// Return the index for the stack protector object.
int getStackProtectorIndex() const { return StackProtectorIdx; }
void setStackProtectorIndex(int I) { StackProtectorIdx = I; }
bool hasStackProtectorIndex() const { return StackProtectorIdx != -1; }
/// Return the index for the function context object.
/// This object is used for SjLj exceptions.
int getFunctionContextIndex() const { return FunctionContextIdx; }
void setFunctionContextIndex(int I) { FunctionContextIdx = I; }
/// This method may be called any time after instruction
/// selection is complete to determine if there is a call to
/// \@llvm.frameaddress in this function.
bool isFrameAddressTaken() const { return FrameAddressTaken; }
void setFrameAddressIsTaken(bool T) { FrameAddressTaken = T; }
/// This method may be called any time after
/// instruction selection is complete to determine if there is a call to
/// \@llvm.returnaddress in this function.
bool isReturnAddressTaken() const { return ReturnAddressTaken; }
void setReturnAddressIsTaken(bool s) { ReturnAddressTaken = s; }
/// This method may be called any time after instruction
/// selection is complete to determine if there is a call to builtin
/// \@llvm.experimental.stackmap.
bool hasStackMap() const { return HasStackMap; }
void setHasStackMap(bool s = true) { HasStackMap = s; }
/// This method may be called any time after instruction
/// selection is complete to determine if there is a call to builtin
/// \@llvm.experimental.patchpoint.
bool hasPatchPoint() const { return HasPatchPoint; }
void setHasPatchPoint(bool s = true) { HasPatchPoint = s; }
/// Return the minimum frame object index.
int getObjectIndexBegin() const { return -NumFixedObjects; }
/// Return one past the maximum frame object index.
int getObjectIndexEnd() const { return (int)Objects.size()-NumFixedObjects; }
/// Return the number of fixed objects.
unsigned getNumFixedObjects() const { return NumFixedObjects; }
/// Return the number of objects.
unsigned getNumObjects() const { return Objects.size(); }
/// Map a frame index into the local object block
void mapLocalFrameObject(int ObjectIndex, int64_t Offset) {
LocalFrameObjects.push_back(std::pair<int, int64_t>(ObjectIndex, Offset));
Objects[ObjectIndex + NumFixedObjects].PreAllocated = true;
}
/// Get the local offset mapping for a for an object.
std::pair<int, int64_t> getLocalFrameObjectMap(int i) const {
assert (i >= 0 && (unsigned)i < LocalFrameObjects.size() &&
"Invalid local object reference!");
return LocalFrameObjects[i];
}
/// Return the number of objects allocated into the local object block.
int64_t getLocalFrameObjectCount() const { return LocalFrameObjects.size(); }
/// Set the size of the local object blob.
void setLocalFrameSize(int64_t sz) { LocalFrameSize = sz; }
/// Get the size of the local object blob.
int64_t getLocalFrameSize() const { return LocalFrameSize; }
/// Required alignment of the local object blob,
/// which is the strictest alignment of any object in it.
void setLocalFrameMaxAlign(Align Alignment) {
LocalFrameMaxAlign = Alignment;
}
/// Return the required alignment of the local object blob.
Align getLocalFrameMaxAlign() const { return LocalFrameMaxAlign; }
/// Get whether the local allocation blob should be allocated together or
/// let PEI allocate the locals in it directly.
bool getUseLocalStackAllocationBlock() const {
return UseLocalStackAllocationBlock;
}
/// setUseLocalStackAllocationBlock - Set whether the local allocation blob
/// should be allocated together or let PEI allocate the locals in it
/// directly.
void setUseLocalStackAllocationBlock(bool v) {
UseLocalStackAllocationBlock = v;
}
/// Return true if the object was pre-allocated into the local block.
bool isObjectPreAllocated(int ObjectIdx) const {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
return Objects[ObjectIdx+NumFixedObjects].PreAllocated;
}
/// Return the size of the specified object.
int64_t getObjectSize(int ObjectIdx) const {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
return Objects[ObjectIdx+NumFixedObjects].Size;
}
/// Change the size of the specified stack object.
void setObjectSize(int ObjectIdx, int64_t Size) {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
Objects[ObjectIdx+NumFixedObjects].Size = Size;
}
/// Return the alignment of the specified stack object.
Align getObjectAlign(int ObjectIdx) const {
assert(unsigned(ObjectIdx + NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
return Objects[ObjectIdx + NumFixedObjects].Alignment;
}
/// setObjectAlignment - Change the alignment of the specified stack object.
void setObjectAlignment(int ObjectIdx, Align Alignment) {
assert(unsigned(ObjectIdx + NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
Objects[ObjectIdx + NumFixedObjects].Alignment = Alignment;
// Only ensure max alignment for the default stack.
if (getStackID(ObjectIdx) == 0)
ensureMaxAlignment(Alignment);
}
/// Return the underlying Alloca of the specified
/// stack object if it exists. Returns 0 if none exists.
const AllocaInst* getObjectAllocation(int ObjectIdx) const {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
return Objects[ObjectIdx+NumFixedObjects].Alloca;
}
/// Return the assigned stack offset of the specified object
/// from the incoming stack pointer.
int64_t getObjectOffset(int ObjectIdx) const {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
assert(!isDeadObjectIndex(ObjectIdx) &&
"Getting frame offset for a dead object?");
return Objects[ObjectIdx+NumFixedObjects].SPOffset;
}
bool isObjectZExt(int ObjectIdx) const {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
return Objects[ObjectIdx+NumFixedObjects].isZExt;
}
void setObjectZExt(int ObjectIdx, bool IsZExt) {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
Objects[ObjectIdx+NumFixedObjects].isZExt = IsZExt;
}
bool isObjectSExt(int ObjectIdx) const {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
return Objects[ObjectIdx+NumFixedObjects].isSExt;
}
void setObjectSExt(int ObjectIdx, bool IsSExt) {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
Objects[ObjectIdx+NumFixedObjects].isSExt = IsSExt;
}
/// Set the stack frame offset of the specified object. The
/// offset is relative to the stack pointer on entry to the function.
void setObjectOffset(int ObjectIdx, int64_t SPOffset) {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
assert(!isDeadObjectIndex(ObjectIdx) &&
"Setting frame offset for a dead object?");
Objects[ObjectIdx+NumFixedObjects].SPOffset = SPOffset;
}
SSPLayoutKind getObjectSSPLayout(int ObjectIdx) const {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
return (SSPLayoutKind)Objects[ObjectIdx+NumFixedObjects].SSPLayout;
}
void setObjectSSPLayout(int ObjectIdx, SSPLayoutKind Kind) {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
assert(!isDeadObjectIndex(ObjectIdx) &&
"Setting SSP layout for a dead object?");
Objects[ObjectIdx+NumFixedObjects].SSPLayout = Kind;
}
/// Return the number of bytes that must be allocated to hold
/// all of the fixed size frame objects. This is only valid after
/// Prolog/Epilog code insertion has finalized the stack frame layout.
uint64_t getStackSize() const { return StackSize; }
/// Set the size of the stack.
void setStackSize(uint64_t Size) { StackSize = Size; }
/// Estimate and return the size of the stack frame.
uint64_t estimateStackSize(const MachineFunction &MF) const;
/// Return the correction for frame offsets.
int getOffsetAdjustment() const { return OffsetAdjustment; }
/// Set the correction for frame offsets.
void setOffsetAdjustment(int Adj) { OffsetAdjustment = Adj; }
/// Return the alignment in bytes that this function must be aligned to,
/// which is greater than the default stack alignment provided by the target.
Align getMaxAlign() const { return MaxAlignment; }
/// Make sure the function is at least Align bytes aligned.
void ensureMaxAlignment(Align Alignment);
/// Return true if this function adjusts the stack -- e.g.,
/// when calling another function. This is only valid during and after
/// prolog/epilog code insertion.
bool adjustsStack() const { return AdjustsStack; }
void setAdjustsStack(bool V) { AdjustsStack = V; }
/// Return true if the current function has any function calls.
bool hasCalls() const { return HasCalls; }
void setHasCalls(bool V) { HasCalls = V; }
/// Returns true if the function contains opaque dynamic stack adjustments.
bool hasOpaqueSPAdjustment() const { return HasOpaqueSPAdjustment; }
void setHasOpaqueSPAdjustment(bool B) { HasOpaqueSPAdjustment = B; }
/// Returns true if the function contains operations which will lower down to
/// instructions which manipulate the stack pointer.
bool hasCopyImplyingStackAdjustment() const {
return HasCopyImplyingStackAdjustment;
}
void setHasCopyImplyingStackAdjustment(bool B) {
HasCopyImplyingStackAdjustment = B;
}
/// Returns true if the function calls the llvm.va_start intrinsic.
bool hasVAStart() const { return HasVAStart; }
void setHasVAStart(bool B) { HasVAStart = B; }
/// Returns true if the function is variadic and contains a musttail call.
bool hasMustTailInVarArgFunc() const { return HasMustTailInVarArgFunc; }
void setHasMustTailInVarArgFunc(bool B) { HasMustTailInVarArgFunc = B; }
/// Returns true if the function contains a tail call.
bool hasTailCall() const { return HasTailCall; }
void setHasTailCall(bool V = true) { HasTailCall = V; }
/// Computes the maximum size of a callframe and the AdjustsStack property.
/// This only works for targets defining
/// TargetInstrInfo::getCallFrameSetupOpcode(), getCallFrameDestroyOpcode(),
/// and getFrameSize().
/// This is usually computed by the prologue epilogue inserter but some
/// targets may call this to compute it earlier.
void computeMaxCallFrameSize(const MachineFunction &MF);
/// Return the maximum size of a call frame that must be
/// allocated for an outgoing function call. This is only available if
/// CallFrameSetup/Destroy pseudo instructions are used by the target, and
/// then only during or after prolog/epilog code insertion.
///
unsigned getMaxCallFrameSize() const {
// TODO: Enable this assert when targets are fixed.
//assert(isMaxCallFrameSizeComputed() && "MaxCallFrameSize not computed yet");
if (!isMaxCallFrameSizeComputed())
return 0;
return MaxCallFrameSize;
}
bool isMaxCallFrameSizeComputed() const {
return MaxCallFrameSize != ~0u;
}
void setMaxCallFrameSize(unsigned S) { MaxCallFrameSize = S; }
/// Returns how many bytes of callee-saved registers the target pushed in the
/// prologue. Only used for debug info.
unsigned getCVBytesOfCalleeSavedRegisters() const {
return CVBytesOfCalleeSavedRegisters;
}
void setCVBytesOfCalleeSavedRegisters(unsigned S) {
CVBytesOfCalleeSavedRegisters = S;
}
/// Create a new object at a fixed location on the stack.
/// All fixed objects should be created before other objects are created for
/// efficiency. By default, fixed objects are not pointed to by LLVM IR
/// values. This returns an index with a negative value.
int CreateFixedObject(uint64_t Size, int64_t SPOffset, bool IsImmutable,
bool isAliased = false);
/// Create a spill slot at a fixed location on the stack.
/// Returns an index with a negative value.
int CreateFixedSpillStackObject(uint64_t Size, int64_t SPOffset,
bool IsImmutable = false);
/// Returns true if the specified index corresponds to a fixed stack object.
bool isFixedObjectIndex(int ObjectIdx) const {
return ObjectIdx < 0 && (ObjectIdx >= -(int)NumFixedObjects);
}
/// Returns true if the specified index corresponds
/// to an object that might be pointed to by an LLVM IR value.
bool isAliasedObjectIndex(int ObjectIdx) const {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
return Objects[ObjectIdx+NumFixedObjects].isAliased;
}
/// Returns true if the specified index corresponds to an immutable object.
bool isImmutableObjectIndex(int ObjectIdx) const {
// Tail calling functions can clobber their function arguments.
if (HasTailCall)
return false;
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
return Objects[ObjectIdx+NumFixedObjects].isImmutable;
}
/// Marks the immutability of an object.
void setIsImmutableObjectIndex(int ObjectIdx, bool IsImmutable) {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
Objects[ObjectIdx+NumFixedObjects].isImmutable = IsImmutable;
}
/// Returns true if the specified index corresponds to a spill slot.
bool isSpillSlotObjectIndex(int ObjectIdx) const {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
return Objects[ObjectIdx+NumFixedObjects].isSpillSlot;
}
bool isStatepointSpillSlotObjectIndex(int ObjectIdx) const {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
return Objects[ObjectIdx+NumFixedObjects].isStatepointSpillSlot;
}
/// \see StackID
uint8_t getStackID(int ObjectIdx) const {
return Objects[ObjectIdx+NumFixedObjects].StackID;
}
/// \see StackID
void setStackID(int ObjectIdx, uint8_t ID) {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
Objects[ObjectIdx+NumFixedObjects].StackID = ID;
// If ID > 0, MaxAlignment may now be overly conservative.
// If ID == 0, MaxAlignment will need to be updated separately.
}
/// Returns true if the specified index corresponds to a dead object.
bool isDeadObjectIndex(int ObjectIdx) const {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
return Objects[ObjectIdx+NumFixedObjects].Size == ~0ULL;
}
/// Returns true if the specified index corresponds to a variable sized
/// object.
bool isVariableSizedObjectIndex(int ObjectIdx) const {
assert(unsigned(ObjectIdx + NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
return Objects[ObjectIdx + NumFixedObjects].Size == 0;
}
void markAsStatepointSpillSlotObjectIndex(int ObjectIdx) {
assert(unsigned(ObjectIdx+NumFixedObjects) < Objects.size() &&
"Invalid Object Idx!");
Objects[ObjectIdx+NumFixedObjects].isStatepointSpillSlot = true;
assert(isStatepointSpillSlotObjectIndex(ObjectIdx) && "inconsistent");
}
/// Create a new statically sized stack object, returning
/// a nonnegative identifier to represent it.
int CreateStackObject(uint64_t Size, Align Alignment, bool isSpillSlot,
const AllocaInst *Alloca = nullptr, uint8_t ID = 0);
/// Create a new statically sized stack object that represents a spill slot,
/// returning a nonnegative identifier to represent it.
int CreateSpillStackObject(uint64_t Size, Align Alignment);
/// Remove or mark dead a statically sized stack object.
void RemoveStackObject(int ObjectIdx) {
// Mark it dead.
Objects[ObjectIdx+NumFixedObjects].Size = ~0ULL;
}
/// Notify the MachineFrameInfo object that a variable sized object has been
/// created. This must be created whenever a variable sized object is
/// created, whether or not the index returned is actually used.
int CreateVariableSizedObject(Align Alignment, const AllocaInst *Alloca);
/// Returns a reference to call saved info vector for the current function.
const std::vector<CalleeSavedInfo> &getCalleeSavedInfo() const {
return CSInfo;
}
/// \copydoc getCalleeSavedInfo()
std::vector<CalleeSavedInfo> &getCalleeSavedInfo() { return CSInfo; }
/// Used by prolog/epilog inserter to set the function's callee saved
/// information.
void setCalleeSavedInfo(std::vector<CalleeSavedInfo> CSI) {
CSInfo = std::move(CSI);
}
/// Has the callee saved info been calculated yet?
bool isCalleeSavedInfoValid() const { return CSIValid; }
void setCalleeSavedInfoValid(bool v) { CSIValid = v; }
MachineBasicBlock *getSavePoint() const { return Save; }
void setSavePoint(MachineBasicBlock *NewSave) { Save = NewSave; }
MachineBasicBlock *getRestorePoint() const { return Restore; }
void setRestorePoint(MachineBasicBlock *NewRestore) { Restore = NewRestore; }
/// Return a set of physical registers that are pristine.
///
/// Pristine registers hold a value that is useless to the current function,
/// but that must be preserved - they are callee saved registers that are not
/// saved.
///
/// Before the PrologueEpilogueInserter has placed the CSR spill code, this
/// method always returns an empty set.
BitVector getPristineRegs(const MachineFunction &MF) const;
/// Used by the MachineFunction printer to print information about
/// stack objects. Implemented in MachineFunction.cpp.
void print(const MachineFunction &MF, raw_ostream &OS) const;
/// dump - Print the function to stderr.
void dump(const MachineFunction &MF) const;
};
} // End llvm namespace
#endif

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More