Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@@ -0,0 +1,7 @@
include_directories( ${CMAKE_CURRENT_BINARY_DIR}/.. ${CMAKE_CURRENT_SOURCE_DIR}/.. )
add_llvm_library(LLVMHexagonAsmParser
HexagonAsmParser.cpp
)
add_dependencies( LLVMHexagonAsmParser HexagonCommonTableGen )

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,23 @@
;===- ./lib/Target/Hexagon/AsmParser/LLVMBuild.txt --------------*- Conf -*-===;
;
; The LLVM Compiler Infrastructure
;
; This file is distributed under the University of Illinois Open Source
; License. See LICENSE.TXT for details.
;
;===------------------------------------------------------------------------===;
;
; This is an LLVMBuild description file for the components in this subdirectory.
;
; For more information on the LLVMBuild system, please see:
;
; http://llvm.org/docs/LLVMBuild.html
;
;===------------------------------------------------------------------------===;
[component_0]
type = Library
name = HexagonAsmParser
parent = Hexagon
required_libraries = MC MCParser Support HexagonDesc HexagonInfo
add_to_library_groups = Hexagon

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,488 @@
//===- BitTracker.h ---------------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_TARGET_HEXAGON_BITTRACKER_H
#define LLVM_LIB_TARGET_HEXAGON_BITTRACKER_H
#include "llvm/ADT/DenseSet.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/MachineOperand.h"
#include <cassert>
#include <cstdint>
#include <map>
#include <queue>
#include <set>
#include <utility>
namespace llvm {
class BitVector;
class ConstantInt;
class MachineRegisterInfo;
class MachineBasicBlock;
class MachineFunction;
class MachineInstr;
class raw_ostream;
class TargetRegisterClass;
class TargetRegisterInfo;
struct BitTracker {
struct BitRef;
struct RegisterRef;
struct BitValue;
struct BitMask;
struct RegisterCell;
struct MachineEvaluator;
using BranchTargetList = SetVector<const MachineBasicBlock *>;
using CellMapType = std::map<unsigned, RegisterCell>;
BitTracker(const MachineEvaluator &E, MachineFunction &F);
~BitTracker();
void run();
void trace(bool On = false) { Trace = On; }
bool has(unsigned Reg) const;
const RegisterCell &lookup(unsigned Reg) const;
RegisterCell get(RegisterRef RR) const;
void put(RegisterRef RR, const RegisterCell &RC);
void subst(RegisterRef OldRR, RegisterRef NewRR);
bool reached(const MachineBasicBlock *B) const;
void visit(const MachineInstr &MI);
void print_cells(raw_ostream &OS) const;
private:
void visitPHI(const MachineInstr &PI);
void visitNonBranch(const MachineInstr &MI);
void visitBranchesFrom(const MachineInstr &BI);
void visitUsesOf(unsigned Reg);
using CFGEdge = std::pair<int, int>;
using EdgeSetType = std::set<CFGEdge>;
using InstrSetType = std::set<const MachineInstr *>;
using EdgeQueueType = std::queue<CFGEdge>;
// Priority queue of instructions using modified registers, ordered by
// their relative position in a basic block.
struct UseQueueType {
unsigned size() const {
return Uses.size();
}
bool empty() const {
return size() == 0;
}
MachineInstr *front() const {
return Uses.top();
}
void push(MachineInstr *MI) {
if (Set.insert(MI).second)
Uses.push(MI);
}
void pop() {
Set.erase(front());
Uses.pop();
}
private:
struct Cmp {
bool operator()(const MachineInstr *MI, const MachineInstr *MJ) const;
};
std::priority_queue<MachineInstr*, std::vector<MachineInstr*>, Cmp> Uses;
DenseSet<MachineInstr*> Set; // Set to avoid adding duplicate entries.
};
void reset();
void runEdgeQueue(BitVector &BlockScanned);
void runUseQueue();
const MachineEvaluator &ME;
MachineFunction &MF;
MachineRegisterInfo &MRI;
CellMapType &Map;
EdgeSetType EdgeExec; // Executable flow graph edges.
InstrSetType InstrExec; // Executable instructions.
UseQueueType UseQ; // Work queue of register uses.
EdgeQueueType FlowQ; // Work queue of CFG edges.
DenseSet<unsigned> ReachedBB; // Cache of reached blocks.
bool Trace; // Enable tracing for debugging.
};
// Abstraction of a reference to bit at position Pos from a register Reg.
struct BitTracker::BitRef {
BitRef(unsigned R = 0, uint16_t P = 0) : Reg(R), Pos(P) {}
bool operator== (const BitRef &BR) const {
// If Reg is 0, disregard Pos.
return Reg == BR.Reg && (Reg == 0 || Pos == BR.Pos);
}
unsigned Reg;
uint16_t Pos;
};
// Abstraction of a register reference in MachineOperand. It contains the
// register number and the subregister index.
struct BitTracker::RegisterRef {
RegisterRef(unsigned R = 0, unsigned S = 0)
: Reg(R), Sub(S) {}
RegisterRef(const MachineOperand &MO)
: Reg(MO.getReg()), Sub(MO.getSubReg()) {}
unsigned Reg, Sub;
};
// Value that a single bit can take. This is outside of the context of
// any register, it is more of an abstraction of the two-element set of
// possible bit values. One extension here is the "Ref" type, which
// indicates that this bit takes the same value as the bit described by
// RefInfo.
struct BitTracker::BitValue {
enum ValueType {
Top, // Bit not yet defined.
Zero, // Bit = 0.
One, // Bit = 1.
Ref // Bit value same as the one described in RefI.
// Conceptually, there is no explicit "bottom" value: the lattice's
// bottom will be expressed as a "ref to itself", which, in the context
// of registers, could be read as "this value of this bit is defined by
// this bit".
// The ordering is:
// x <= Top,
// Self <= x, where "Self" is "ref to itself".
// This makes the value lattice different for each virtual register
// (even for each bit in the same virtual register), since the "bottom"
// for one register will be a simple "ref" for another register.
// Since we do not store the "Self" bit and register number, the meet
// operation will need to take it as a parameter.
//
// In practice there is a special case for values that are not associa-
// ted with any specific virtual register. An example would be a value
// corresponding to a bit of a physical register, or an intermediate
// value obtained in some computation (such as instruction evaluation).
// Such cases are identical to the usual Ref type, but the register
// number is 0. In such case the Pos field of the reference is ignored.
//
// What is worthy of notice is that in value V (that is a "ref"), as long
// as the RefI.Reg is not 0, it may actually be the same register as the
// one in which V will be contained. If the RefI.Pos refers to the posi-
// tion of V, then V is assumed to be "bottom" (as a "ref to itself"),
// otherwise V is taken to be identical to the referenced bit of the
// same register.
// If RefI.Reg is 0, however, such a reference to the same register is
// not possible. Any value V that is a "ref", and whose RefI.Reg is 0
// is treated as "bottom".
};
ValueType Type;
BitRef RefI;
BitValue(ValueType T = Top) : Type(T) {}
BitValue(bool B) : Type(B ? One : Zero) {}
BitValue(unsigned Reg, uint16_t Pos) : Type(Ref), RefI(Reg, Pos) {}
bool operator== (const BitValue &V) const {
if (Type != V.Type)
return false;
if (Type == Ref && !(RefI == V.RefI))
return false;
return true;
}
bool operator!= (const BitValue &V) const {
return !operator==(V);
}
bool is(unsigned T) const {
assert(T == 0 || T == 1);
return T == 0 ? Type == Zero
: (T == 1 ? Type == One : false);
}
// The "meet" operation is the "." operation in a semilattice (L, ., T, B):
// (1) x.x = x
// (2) x.y = y.x
// (3) x.(y.z) = (x.y).z
// (4) x.T = x (i.e. T = "top")
// (5) x.B = B (i.e. B = "bottom")
//
// This "meet" function will update the value of the "*this" object with
// the newly calculated one, and return "true" if the value of *this has
// changed, and "false" otherwise.
// To prove that it satisfies the conditions (1)-(5), it is sufficient
// to show that a relation
// x <= y <=> x.y = x
// defines a partial order (i.e. that "meet" is same as "infimum").
bool meet(const BitValue &V, const BitRef &Self) {
// First, check the cases where there is nothing to be done.
if (Type == Ref && RefI == Self) // Bottom.meet(V) = Bottom (i.e. This)
return false;
if (V.Type == Top) // This.meet(Top) = This
return false;
if (*this == V) // This.meet(This) = This
return false;
// At this point, we know that the value of "this" will change.
// If it is Top, it will become the same as V, otherwise it will
// become "bottom" (i.e. Self).
if (Type == Top) {
Type = V.Type;
RefI = V.RefI; // This may be irrelevant, but copy anyway.
return true;
}
// Become "bottom".
Type = Ref;
RefI = Self;
return true;
}
// Create a reference to the bit value V.
static BitValue ref(const BitValue &V);
// Create a "self".
static BitValue self(const BitRef &Self = BitRef());
bool num() const {
return Type == Zero || Type == One;
}
operator bool() const {
assert(Type == Zero || Type == One);
return Type == One;
}
friend raw_ostream &operator<<(raw_ostream &OS, const BitValue &BV);
};
// This operation must be idempotent, i.e. ref(ref(V)) == ref(V).
inline BitTracker::BitValue
BitTracker::BitValue::ref(const BitValue &V) {
if (V.Type != Ref)
return BitValue(V.Type);
if (V.RefI.Reg != 0)
return BitValue(V.RefI.Reg, V.RefI.Pos);
return self();
}
inline BitTracker::BitValue
BitTracker::BitValue::self(const BitRef &Self) {
return BitValue(Self.Reg, Self.Pos);
}
// A sequence of bits starting from index B up to and including index E.
// If E < B, the mask represents two sections: [0..E] and [B..W) where
// W is the width of the register.
struct BitTracker::BitMask {
BitMask() = default;
BitMask(uint16_t b, uint16_t e) : B(b), E(e) {}
uint16_t first() const { return B; }
uint16_t last() const { return E; }
private:
uint16_t B = 0;
uint16_t E = 0;
};
// Representation of a register: a list of BitValues.
struct BitTracker::RegisterCell {
RegisterCell(uint16_t Width = DefaultBitN) : Bits(Width) {}
uint16_t width() const {
return Bits.size();
}
const BitValue &operator[](uint16_t BitN) const {
assert(BitN < Bits.size());
return Bits[BitN];
}
BitValue &operator[](uint16_t BitN) {
assert(BitN < Bits.size());
return Bits[BitN];
}
bool meet(const RegisterCell &RC, unsigned SelfR);
RegisterCell &insert(const RegisterCell &RC, const BitMask &M);
RegisterCell extract(const BitMask &M) const; // Returns a new cell.
RegisterCell &rol(uint16_t Sh); // Rotate left.
RegisterCell &fill(uint16_t B, uint16_t E, const BitValue &V);
RegisterCell &cat(const RegisterCell &RC); // Concatenate.
uint16_t cl(bool B) const;
uint16_t ct(bool B) const;
bool operator== (const RegisterCell &RC) const;
bool operator!= (const RegisterCell &RC) const {
return !operator==(RC);
}
// Replace the ref-to-reg-0 bit values with the given register.
RegisterCell &regify(unsigned R);
// Generate a "ref" cell for the corresponding register. In the resulting
// cell each bit will be described as being the same as the corresponding
// bit in register Reg (i.e. the cell is "defined" by register Reg).
static RegisterCell self(unsigned Reg, uint16_t Width);
// Generate a "top" cell of given size.
static RegisterCell top(uint16_t Width);
// Generate a cell that is a "ref" to another cell.
static RegisterCell ref(const RegisterCell &C);
private:
// The DefaultBitN is here only to avoid frequent reallocation of the
// memory in the vector.
static const unsigned DefaultBitN = 32;
using BitValueList = SmallVector<BitValue, DefaultBitN>;
BitValueList Bits;
friend raw_ostream &operator<<(raw_ostream &OS, const RegisterCell &RC);
};
inline bool BitTracker::has(unsigned Reg) const {
return Map.find(Reg) != Map.end();
}
inline const BitTracker::RegisterCell&
BitTracker::lookup(unsigned Reg) const {
CellMapType::const_iterator F = Map.find(Reg);
assert(F != Map.end());
return F->second;
}
inline BitTracker::RegisterCell
BitTracker::RegisterCell::self(unsigned Reg, uint16_t Width) {
RegisterCell RC(Width);
for (uint16_t i = 0; i < Width; ++i)
RC.Bits[i] = BitValue::self(BitRef(Reg, i));
return RC;
}
inline BitTracker::RegisterCell
BitTracker::RegisterCell::top(uint16_t Width) {
RegisterCell RC(Width);
for (uint16_t i = 0; i < Width; ++i)
RC.Bits[i] = BitValue(BitValue::Top);
return RC;
}
inline BitTracker::RegisterCell
BitTracker::RegisterCell::ref(const RegisterCell &C) {
uint16_t W = C.width();
RegisterCell RC(W);
for (unsigned i = 0; i < W; ++i)
RC[i] = BitValue::ref(C[i]);
return RC;
}
// A class to evaluate target's instructions and update the cell maps.
// This is used internally by the bit tracker. A target that wants to
// utilize this should implement the evaluation functions (noted below)
// in a subclass of this class.
struct BitTracker::MachineEvaluator {
MachineEvaluator(const TargetRegisterInfo &T, MachineRegisterInfo &M)
: TRI(T), MRI(M) {}
virtual ~MachineEvaluator() = default;
uint16_t getRegBitWidth(const RegisterRef &RR) const;
RegisterCell getCell(const RegisterRef &RR, const CellMapType &M) const;
void putCell(const RegisterRef &RR, RegisterCell RC, CellMapType &M) const;
// A result of any operation should use refs to the source cells, not
// the cells directly. This function is a convenience wrapper to quickly
// generate a ref for a cell corresponding to a register reference.
RegisterCell getRef(const RegisterRef &RR, const CellMapType &M) const {
RegisterCell RC = getCell(RR, M);
return RegisterCell::ref(RC);
}
// Helper functions.
// Check if a cell is an immediate value (i.e. all bits are either 0 or 1).
bool isInt(const RegisterCell &A) const;
// Convert cell to an immediate value.
uint64_t toInt(const RegisterCell &A) const;
// Generate cell from an immediate value.
RegisterCell eIMM(int64_t V, uint16_t W) const;
RegisterCell eIMM(const ConstantInt *CI) const;
// Arithmetic.
RegisterCell eADD(const RegisterCell &A1, const RegisterCell &A2) const;
RegisterCell eSUB(const RegisterCell &A1, const RegisterCell &A2) const;
RegisterCell eMLS(const RegisterCell &A1, const RegisterCell &A2) const;
RegisterCell eMLU(const RegisterCell &A1, const RegisterCell &A2) const;
// Shifts.
RegisterCell eASL(const RegisterCell &A1, uint16_t Sh) const;
RegisterCell eLSR(const RegisterCell &A1, uint16_t Sh) const;
RegisterCell eASR(const RegisterCell &A1, uint16_t Sh) const;
// Logical.
RegisterCell eAND(const RegisterCell &A1, const RegisterCell &A2) const;
RegisterCell eORL(const RegisterCell &A1, const RegisterCell &A2) const;
RegisterCell eXOR(const RegisterCell &A1, const RegisterCell &A2) const;
RegisterCell eNOT(const RegisterCell &A1) const;
// Set bit, clear bit.
RegisterCell eSET(const RegisterCell &A1, uint16_t BitN) const;
RegisterCell eCLR(const RegisterCell &A1, uint16_t BitN) const;
// Count leading/trailing bits (zeros/ones).
RegisterCell eCLB(const RegisterCell &A1, bool B, uint16_t W) const;
RegisterCell eCTB(const RegisterCell &A1, bool B, uint16_t W) const;
// Sign/zero extension.
RegisterCell eSXT(const RegisterCell &A1, uint16_t FromN) const;
RegisterCell eZXT(const RegisterCell &A1, uint16_t FromN) const;
// Extract/insert
// XTR R,b,e: extract bits from A1 starting at bit b, ending at e-1.
// INS R,S,b: take R and replace bits starting from b with S.
RegisterCell eXTR(const RegisterCell &A1, uint16_t B, uint16_t E) const;
RegisterCell eINS(const RegisterCell &A1, const RegisterCell &A2,
uint16_t AtN) const;
// User-provided functions for individual targets:
// Return a sub-register mask that indicates which bits in Reg belong
// to the subregister Sub. These bits are assumed to be contiguous in
// the super-register, and have the same ordering in the sub-register
// as in the super-register. It is valid to call this function with
// Sub == 0, in this case, the function should return a mask that spans
// the entire register Reg (which is what the default implementation
// does).
virtual BitMask mask(unsigned Reg, unsigned Sub) const;
// Indicate whether a given register class should be tracked.
virtual bool track(const TargetRegisterClass *RC) const { return true; }
// Evaluate a non-branching machine instruction, given the cell map with
// the input values. Place the results in the Outputs map. Return "true"
// if evaluation succeeded, "false" otherwise.
virtual bool evaluate(const MachineInstr &MI, const CellMapType &Inputs,
CellMapType &Outputs) const;
// Evaluate a branch, given the cell map with the input values. Fill out
// a list of all possible branch targets and indicate (through a flag)
// whether the branch could fall-through. Return "true" if this information
// has been successfully computed, "false" otherwise.
virtual bool evaluate(const MachineInstr &BI, const CellMapType &Inputs,
BranchTargetList &Targets, bool &FallsThru) const = 0;
// Given a register class RC, return a register class that should be assumed
// when a register from class RC is used with a subregister of index Idx.
virtual const TargetRegisterClass&
composeWithSubRegIndex(const TargetRegisterClass &RC, unsigned Idx) const {
if (Idx == 0)
return RC;
llvm_unreachable("Unimplemented composeWithSubRegIndex");
}
// Return the size in bits of the physical register Reg.
virtual uint16_t getPhysRegBitWidth(unsigned Reg) const;
const TargetRegisterInfo &TRI;
MachineRegisterInfo &MRI;
};
} // end namespace llvm
#endif // LLVM_LIB_TARGET_HEXAGON_BITTRACKER_H

View File

@@ -0,0 +1,74 @@
set(LLVM_TARGET_DEFINITIONS Hexagon.td)
tablegen(LLVM HexagonGenAsmMatcher.inc -gen-asm-matcher)
tablegen(LLVM HexagonGenAsmWriter.inc -gen-asm-writer)
tablegen(LLVM HexagonGenDAGISel.inc -gen-dag-isel)
tablegen(LLVM HexagonGenDFAPacketizer.inc -gen-dfa-packetizer)
tablegen(LLVM HexagonGenDisassemblerTables.inc -gen-disassembler)
tablegen(LLVM HexagonGenInstrInfo.inc -gen-instr-info)
tablegen(LLVM HexagonGenMCCodeEmitter.inc -gen-emitter)
tablegen(LLVM HexagonGenRegisterInfo.inc -gen-register-info)
tablegen(LLVM HexagonGenSubtargetInfo.inc -gen-subtarget)
add_public_tablegen_target(HexagonCommonTableGen)
add_llvm_target(HexagonCodeGen
BitTracker.cpp
HexagonAsmPrinter.cpp
HexagonBitSimplify.cpp
HexagonBitTracker.cpp
HexagonBlockRanges.cpp
HexagonBranchRelaxation.cpp
HexagonCFGOptimizer.cpp
HexagonCommonGEP.cpp
HexagonConstExtenders.cpp
HexagonConstPropagation.cpp
HexagonCopyToCombine.cpp
HexagonEarlyIfConv.cpp
HexagonExpandCondsets.cpp
HexagonFixupHwLoops.cpp
HexagonFrameLowering.cpp
HexagonGatherPacketize.cpp
HexagonGenExtract.cpp
HexagonGenInsert.cpp
HexagonGenMux.cpp
HexagonGenPredicate.cpp
HexagonHardwareLoops.cpp
HexagonHazardRecognizer.cpp
HexagonInstrInfo.cpp
HexagonISelDAGToDAG.cpp
HexagonISelDAGToDAGHVX.cpp
HexagonISelLowering.cpp
HexagonISelLoweringHVX.cpp
HexagonLoopIdiomRecognition.cpp
HexagonMachineFunctionInfo.cpp
HexagonMachineScheduler.cpp
HexagonMCInstLower.cpp
HexagonNewValueJump.cpp
HexagonOptAddrMode.cpp
HexagonOptimizeSZextends.cpp
HexagonPeephole.cpp
HexagonRDFOpt.cpp
HexagonRegisterInfo.cpp
HexagonSelectionDAGInfo.cpp
HexagonSplitConst32AndConst64.cpp
HexagonSplitDouble.cpp
HexagonStoreWidening.cpp
HexagonSubtarget.cpp
HexagonTargetMachine.cpp
HexagonTargetObjectFile.cpp
HexagonTargetTransformInfo.cpp
HexagonVectorLoopCarriedReuse.cpp
HexagonVectorPrint.cpp
HexagonVLIWPacketizer.cpp
RDFCopy.cpp
RDFDeadCode.cpp
RDFGraph.cpp
RDFLiveness.cpp
RDFRegisters.cpp
)
add_subdirectory(AsmParser)
add_subdirectory(TargetInfo)
add_subdirectory(MCTargetDesc)
add_subdirectory(Disassembler)

View File

@@ -0,0 +1,3 @@
add_llvm_library(LLVMHexagonDisassembler
HexagonDisassembler.cpp
)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,23 @@
;===-- ./lib/Target/Hexagon/Disassembler/LLVMBuild.txt ---------*- Conf -*--===;
;
; The LLVM Compiler Infrastructure
;
; This file is distributed under the University of Illinois Open Source
; License. See LICENSE.TXT for details.
;
;===------------------------------------------------------------------------===;
;
; This is an LLVMBuild description file for the components in this subdirectory.
;
; For more information on the LLVMBuild system, please see:
;
; http://llvm.org/docs/LLVMBuild.html
;
;===------------------------------------------------------------------------===;
[component_0]
type = Library
name = HexagonDisassembler
parent = Hexagon
required_libraries = HexagonDesc HexagonInfo MC MCDisassembler Support
add_to_library_groups = Hexagon

View File

@@ -0,0 +1,56 @@
//=-- Hexagon.h - Top-level interface for Hexagon representation --*- C++ -*-=//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the entry points for global functions defined in the LLVM
// Hexagon back-end.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_TARGET_HEXAGON_HEXAGON_H
#define LLVM_LIB_TARGET_HEXAGON_HEXAGON_H
#define Hexagon_POINTER_SIZE 4
#define Hexagon_PointerSize (Hexagon_POINTER_SIZE)
#define Hexagon_PointerSize_Bits (Hexagon_POINTER_SIZE * 8)
#define Hexagon_WordSize Hexagon_PointerSize
#define Hexagon_WordSize_Bits Hexagon_PointerSize_Bits
// allocframe saves LR and FP on stack before allocating
// a new stack frame. This takes 8 bytes.
#define HEXAGON_LRFP_SIZE 8
// Normal instruction size (in bytes).
#define HEXAGON_INSTR_SIZE 4
// Maximum number of words and instructions in a packet.
#define HEXAGON_PACKET_SIZE 4
#define HEXAGON_MAX_PACKET_SIZE (HEXAGON_PACKET_SIZE * HEXAGON_INSTR_SIZE)
// Minimum number of instructions in an end-loop packet.
#define HEXAGON_PACKET_INNER_SIZE 2
#define HEXAGON_PACKET_OUTER_SIZE 3
// Maximum number of instructions in a packet before shuffling,
// including a compound one or a duplex or an extender.
#define HEXAGON_PRESHUFFLE_PACKET_SIZE (HEXAGON_PACKET_SIZE + 3)
// Name of the global offset table as defined by the Hexagon ABI
#define HEXAGON_GOT_SYM_NAME "_GLOBAL_OFFSET_TABLE_"
#include "MCTargetDesc/HexagonMCTargetDesc.h"
#include "llvm/CodeGen/TargetLowering.h"
#include "llvm/Target/TargetMachine.h"
namespace llvm {
class HexagonTargetMachine;
/// \brief Creates a Hexagon-specific Target Transformation Info pass.
ImmutablePass *createHexagonTargetTransformInfoPass(const HexagonTargetMachine *TM);
} // end namespace llvm;
#endif

View File

@@ -0,0 +1,360 @@
//===-- Hexagon.td - Describe the Hexagon Target Machine --*- tablegen -*--===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This is the top level entry point for the Hexagon target.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Target-independent interfaces which we are implementing
//===----------------------------------------------------------------------===//
include "llvm/Target/Target.td"
//===----------------------------------------------------------------------===//
// Hexagon Subtarget features.
//===----------------------------------------------------------------------===//
// Hexagon Architectures
include "HexagonDepArch.td"
// Hexagon ISA Extensions
def ExtensionHVX: SubtargetFeature<"hvx", "HexagonHVXVersion",
"Hexagon::ArchEnum::V60", "Hexagon HVX instructions">;
def ExtensionHVXV60: SubtargetFeature<"hvxv60", "HexagonHVXVersion",
"Hexagon::ArchEnum::V60", "Hexagon HVX instructions",
[ExtensionHVX]>;
def ExtensionHVXV62: SubtargetFeature<"hvxv62", "HexagonHVXVersion",
"Hexagon::ArchEnum::V62", "Hexagon HVX instructions",
[ExtensionHVX,ExtensionHVXV60]>;
def ExtensionHVXV65: SubtargetFeature<"hvxv65", "HexagonHVXVersion",
"Hexagon::ArchEnum::V65", "Hexagon HVX instructions",
[ExtensionHVX,ExtensionHVXV60, ExtensionHVXV62]>;
def ExtensionHVX64B
: SubtargetFeature<"hvx-length64b", "UseHVX64BOps", "true",
"Hexagon HVX 64B instructions", [ExtensionHVX]>;
def ExtensionHVX128B
: SubtargetFeature<"hvx-length128b", "UseHVX128BOps", "true",
"Hexagon HVX 128B instructions", [ExtensionHVX]>;
// This is an alias to ExtensionHVX128B to accept the hvx-double as
// an acceptable subtarget feature.
def ExtensionHVXDbl
: SubtargetFeature<"hvx-double", "UseHVX128BOps", "true",
"Hexagon HVX 128B instructions", [ExtensionHVX128B]>;
def FeatureLongCalls: SubtargetFeature<"long-calls", "UseLongCalls", "true",
"Use constant-extended calls">;
def FeatureMemNoShuf: SubtargetFeature<"mem_noshuf", "HasMemNoShuf", "false",
"Supports mem_noshuf feature">;
def FeatureDuplex : SubtargetFeature<"duplex", "EnableDuplex", "true",
"Enable generation of duplex instruction">;
//===----------------------------------------------------------------------===//
// Hexagon Instruction Predicate Definitions.
//===----------------------------------------------------------------------===//
def UseMEMOP : Predicate<"HST->useMemOps()">;
def IEEERndNearV5T : Predicate<"HST->modeIEEERndNear()">;
def UseHVX64B : Predicate<"HST->useHVX64BOps()">,
AssemblerPredicate<"ExtensionHVX64B">;
def UseHVX128B : Predicate<"HST->useHVX128BOps()">,
AssemblerPredicate<"ExtensionHVX128B">;
def UseHVX : Predicate<"HST->useHVXOps()">,
AssemblerPredicate<"ExtensionHVXV60">;
def UseHVXV60 : Predicate<"HST->useHVXOps()">,
AssemblerPredicate<"ExtensionHVXV60">;
def UseHVXV62 : Predicate<"HST->useHVXOps()">,
AssemblerPredicate<"ExtensionHVXV62">;
def UseHVXV65 : Predicate<"HST->useHVXOps()">,
AssemblerPredicate<"ExtensionHVXV65">;
def Hvx64 : HwMode<"+hvx-length64b">;
def Hvx64old : HwMode<"-hvx-double">;
def Hvx128 : HwMode<"+hvx-length128b">;
def Hvx128old : HwMode<"+hvx-double">;
//===----------------------------------------------------------------------===//
// Classes used for relation maps.
//===----------------------------------------------------------------------===//
class ImmRegShl;
// ImmRegRel - Filter class used to relate instructions having reg-reg form
// with their reg-imm counterparts.
class ImmRegRel;
// PredRel - Filter class used to relate non-predicated instructions with their
// predicated forms.
class PredRel;
// PredNewRel - Filter class used to relate predicated instructions with their
// predicate-new forms.
class PredNewRel: PredRel;
// NewValueRel - Filter class used to relate regular store instructions with
// their new-value store form.
class NewValueRel: PredNewRel;
// NewValueRel - Filter class used to relate load/store instructions having
// different addressing modes with each other.
class AddrModeRel: NewValueRel;
class PostInc_BaseImm;
class IntrinsicsRel;
//===----------------------------------------------------------------------===//
// Generate mapping table to relate non-predicate instructions with their
// predicated formats - true and false.
//
def getPredOpcode : InstrMapping {
let FilterClass = "PredRel";
// Instructions with the same BaseOpcode and isNVStore values form a row.
let RowFields = ["BaseOpcode", "isNVStore", "PNewValue", "isBrTaken", "isNT"];
// Instructions with the same predicate sense form a column.
let ColFields = ["PredSense"];
// The key column is the unpredicated instructions.
let KeyCol = [""];
// Value columns are PredSense=true and PredSense=false
let ValueCols = [["true"], ["false"]];
}
//===----------------------------------------------------------------------===//
// Generate mapping table to relate predicate-true instructions with their
// predicate-false forms
//
def getFalsePredOpcode : InstrMapping {
let FilterClass = "PredRel";
let RowFields = ["BaseOpcode", "PNewValue", "isNVStore", "isBrTaken", "isNT"];
let ColFields = ["PredSense"];
let KeyCol = ["true"];
let ValueCols = [["false"]];
}
//===----------------------------------------------------------------------===//
// Generate mapping table to relate predicate-false instructions with their
// predicate-true forms
//
def getTruePredOpcode : InstrMapping {
let FilterClass = "PredRel";
let RowFields = ["BaseOpcode", "PNewValue", "isNVStore", "isBrTaken", "isNT"];
let ColFields = ["PredSense"];
let KeyCol = ["false"];
let ValueCols = [["true"]];
}
//===----------------------------------------------------------------------===//
// Generate mapping table to relate predicated instructions with their .new
// format.
//
def getPredNewOpcode : InstrMapping {
let FilterClass = "PredNewRel";
let RowFields = ["BaseOpcode", "PredSense", "isNVStore", "isBrTaken"];
let ColFields = ["PNewValue"];
let KeyCol = [""];
let ValueCols = [["new"]];
}
//===----------------------------------------------------------------------===//
// Generate mapping table to relate .new predicated instructions with their old
// format.
//
def getPredOldOpcode : InstrMapping {
let FilterClass = "PredNewRel";
let RowFields = ["BaseOpcode", "PredSense", "isNVStore", "isBrTaken"];
let ColFields = ["PNewValue"];
let KeyCol = ["new"];
let ValueCols = [[""]];
}
//===----------------------------------------------------------------------===//
// Generate mapping table to relate store instructions with their new-value
// format.
//
def getNewValueOpcode : InstrMapping {
let FilterClass = "NewValueRel";
let RowFields = ["BaseOpcode", "PredSense", "PNewValue", "addrMode", "isNT"];
let ColFields = ["NValueST"];
let KeyCol = ["false"];
let ValueCols = [["true"]];
}
//===----------------------------------------------------------------------===//
// Generate mapping table to relate new-value store instructions with their old
// format.
//
def getNonNVStore : InstrMapping {
let FilterClass = "NewValueRel";
let RowFields = ["BaseOpcode", "PredSense", "PNewValue", "addrMode", "isNT"];
let ColFields = ["NValueST"];
let KeyCol = ["true"];
let ValueCols = [["false"]];
}
def changeAddrMode_abs_io: InstrMapping {
let FilterClass = "AddrModeRel";
let RowFields = ["CextOpcode", "PredSense", "PNewValue", "isNVStore",
"isFloat"];
let ColFields = ["addrMode"];
let KeyCol = ["Absolute"];
let ValueCols = [["BaseImmOffset"]];
}
def changeAddrMode_io_abs: InstrMapping {
let FilterClass = "AddrModeRel";
let RowFields = ["CextOpcode", "PredSense", "PNewValue", "isNVStore",
"isFloat"];
let ColFields = ["addrMode"];
let KeyCol = ["BaseImmOffset"];
let ValueCols = [["Absolute"]];
}
def changeAddrMode_io_rr: InstrMapping {
let FilterClass = "AddrModeRel";
let RowFields = ["CextOpcode", "PredSense", "PNewValue", "isNVStore"];
let ColFields = ["addrMode"];
let KeyCol = ["BaseImmOffset"];
let ValueCols = [["BaseRegOffset"]];
}
def changeAddrMode_rr_io: InstrMapping {
let FilterClass = "AddrModeRel";
let RowFields = ["CextOpcode", "PredSense", "PNewValue", "isNVStore"];
let ColFields = ["addrMode"];
let KeyCol = ["BaseRegOffset"];
let ValueCols = [["BaseImmOffset"]];
}
def changeAddrMode_pi_io: InstrMapping {
let FilterClass = "PostInc_BaseImm";
let RowFields = ["CextOpcode", "PredSense", "PNewValue", "isNVStore"];
let ColFields = ["addrMode"];
let KeyCol = ["PostInc"];
let ValueCols = [["BaseImmOffset"]];
}
def changeAddrMode_io_pi: InstrMapping {
let FilterClass = "PostInc_BaseImm";
let RowFields = ["CextOpcode", "PredSense", "PNewValue", "isNVStore"];
let ColFields = ["addrMode"];
let KeyCol = ["BaseImmOffset"];
let ValueCols = [["PostInc"]];
}
def changeAddrMode_rr_ur: InstrMapping {
let FilterClass = "ImmRegShl";
let RowFields = ["CextOpcode", "PredSense", "PNewValue", "isNVStore"];
let ColFields = ["addrMode"];
let KeyCol = ["BaseRegOffset"];
let ValueCols = [["BaseLongOffset"]];
}
def changeAddrMode_ur_rr : InstrMapping {
let FilterClass = "ImmRegShl";
let RowFields = ["CextOpcode", "PredSense", "PNewValue", "isNVStore"];
let ColFields = ["addrMode"];
let KeyCol = ["BaseLongOffset"];
let ValueCols = [["BaseRegOffset"]];
}
def getRegForm : InstrMapping {
let FilterClass = "ImmRegRel";
let RowFields = ["CextOpcode", "PredSense", "PNewValue"];
let ColFields = ["InputType"];
let KeyCol = ["imm"];
let ValueCols = [["reg"]];
}
def notTakenBranchPrediction : InstrMapping {
let FilterClass = "PredRel";
let RowFields = ["BaseOpcode", "PNewValue", "PredSense", "isBranch", "isPredicated"];
let ColFields = ["isBrTaken"];
let KeyCol = ["true"];
let ValueCols = [["false"]];
}
def takenBranchPrediction : InstrMapping {
let FilterClass = "PredRel";
let RowFields = ["BaseOpcode", "PNewValue", "PredSense", "isBranch", "isPredicated"];
let ColFields = ["isBrTaken"];
let KeyCol = ["false"];
let ValueCols = [["true"]];
}
def getRealHWInstr : InstrMapping {
let FilterClass = "IntrinsicsRel";
let RowFields = ["BaseOpcode"];
let ColFields = ["InstrType"];
let KeyCol = ["Pseudo"];
let ValueCols = [["Pseudo"], ["Real"]];
}
//===----------------------------------------------------------------------===//
// Register File, Instruction Descriptions
//===----------------------------------------------------------------------===//
include "HexagonSchedule.td"
include "HexagonRegisterInfo.td"
include "HexagonOperands.td"
include "HexagonDepOperands.td"
include "HexagonDepITypes.td"
include "HexagonInstrFormats.td"
include "HexagonDepInstrFormats.td"
include "HexagonDepInstrInfo.td"
include "HexagonPseudo.td"
include "HexagonPatterns.td"
include "HexagonPatternsV65.td"
include "HexagonDepMappings.td"
include "HexagonIntrinsics.td"
include "HexagonMapAsm2IntrinV62.gen.td"
include "HexagonMapAsm2IntrinV65.gen.td"
def HexagonInstrInfo : InstrInfo;
//===----------------------------------------------------------------------===//
// Hexagon processors supported.
//===----------------------------------------------------------------------===//
class Proc<string Name, SchedMachineModel Model,
list<SubtargetFeature> Features>
: ProcessorModel<Name, Model, Features>;
def : Proc<"hexagonv4", HexagonModelV4,
[ArchV4, FeatureDuplex]>;
def : Proc<"hexagonv5", HexagonModelV4,
[ArchV4, ArchV5, FeatureDuplex]>;
def : Proc<"hexagonv55", HexagonModelV55,
[ArchV4, ArchV5, ArchV55, FeatureDuplex]>;
def : Proc<"hexagonv60", HexagonModelV60,
[ArchV4, ArchV5, ArchV55, ArchV60, FeatureDuplex]>;
def : Proc<"hexagonv62", HexagonModelV62,
[ArchV4, ArchV5, ArchV55, ArchV60, ArchV62, FeatureDuplex]>;
def : Proc<"hexagonv65", HexagonModelV65,
[ArchV4, ArchV5, ArchV55, ArchV60, ArchV62, ArchV65,
FeatureMemNoShuf, FeatureDuplex]>;
//===----------------------------------------------------------------------===//
// Declare the target which we are implementing
//===----------------------------------------------------------------------===//
def HexagonAsmParser : AsmParser {
let ShouldEmitMatchRegisterAltName = 1;
bit HasMnemonicFirst = 0;
}
def HexagonAsmParserVariant : AsmParserVariant {
int Variant = 0;
string TokenizingCharacters = "#()=:.<>!+*-|^&";
string BreakCharacters = "";
}
def HexagonAsmWriter : AsmWriter {
string AsmWriterClassName = "InstPrinter";
bit isMCAsmWriter = 1;
}
def Hexagon : Target {
let InstructionSet = HexagonInstrInfo;
let AssemblyParsers = [HexagonAsmParser];
let AssemblyParserVariants = [HexagonAsmParserVariant];
let AssemblyWriters = [HexagonAsmWriter];
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,67 @@
//===- HexagonAsmPrinter.h - Print machine code to an Hexagon .s file -----===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Hexagon Assembly printer class.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_TARGET_HEXAGON_HEXAGONASMPRINTER_H
#define LLVM_LIB_TARGET_HEXAGON_HEXAGONASMPRINTER_H
#include "Hexagon.h"
#include "HexagonSubtarget.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineFunction.h"
#include <memory>
namespace llvm {
class MachineInstr;
class MCInst;
class raw_ostream;
class TargetMachine;
class HexagonAsmPrinter : public AsmPrinter {
const HexagonSubtarget *Subtarget = nullptr;
public:
explicit HexagonAsmPrinter(TargetMachine &TM,
std::unique_ptr<MCStreamer> Streamer);
bool runOnMachineFunction(MachineFunction &Fn) override {
Subtarget = &Fn.getSubtarget<HexagonSubtarget>();
return AsmPrinter::runOnMachineFunction(Fn);
}
StringRef getPassName() const override {
return "Hexagon Assembly Printer";
}
bool isBlockOnlyReachableByFallthrough(
const MachineBasicBlock *MBB) const override;
void EmitInstruction(const MachineInstr *MI) override;
void HexagonProcessInstruction(MCInst &Inst,
const MachineInstr &MBB);
void printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &O);
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant, const char *ExtraCode,
raw_ostream &OS) override;
bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant, const char *ExtraCode,
raw_ostream &OS) override;
static const char *getRegisterName(unsigned RegNo);
};
} // end namespace llvm
#endif // LLVM_LIB_TARGET_HEXAGON_HEXAGONASMPRINTER_H

View File

@@ -0,0 +1 @@
9e73766b6fdcaa1973936b3cac7315d9fcd3e572

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,77 @@
//===- HexagonBitTracker.h --------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_TARGET_HEXAGON_HEXAGONBITTRACKER_H
#define LLVM_LIB_TARGET_HEXAGON_HEXAGONBITTRACKER_H
#include "BitTracker.h"
#include "llvm/ADT/DenseMap.h"
#include <cstdint>
namespace llvm {
class HexagonInstrInfo;
class HexagonRegisterInfo;
class MachineFrameInfo;
class MachineFunction;
class MachineInstr;
class MachineRegisterInfo;
struct HexagonEvaluator : public BitTracker::MachineEvaluator {
using CellMapType = BitTracker::CellMapType;
using RegisterRef = BitTracker::RegisterRef;
using RegisterCell = BitTracker::RegisterCell;
using BranchTargetList = BitTracker::BranchTargetList;
HexagonEvaluator(const HexagonRegisterInfo &tri, MachineRegisterInfo &mri,
const HexagonInstrInfo &tii, MachineFunction &mf);
bool evaluate(const MachineInstr &MI, const CellMapType &Inputs,
CellMapType &Outputs) const override;
bool evaluate(const MachineInstr &BI, const CellMapType &Inputs,
BranchTargetList &Targets, bool &FallsThru) const override;
BitTracker::BitMask mask(unsigned Reg, unsigned Sub) const override;
uint16_t getPhysRegBitWidth(unsigned Reg) const override;
const TargetRegisterClass &composeWithSubRegIndex(
const TargetRegisterClass &RC, unsigned Idx) const override;
MachineFunction &MF;
MachineFrameInfo &MFI;
const HexagonInstrInfo &TII;
private:
bool evaluateLoad(const MachineInstr &MI, const CellMapType &Inputs,
CellMapType &Outputs) const;
bool evaluateFormalCopy(const MachineInstr &MI, const CellMapType &Inputs,
CellMapType &Outputs) const;
unsigned getNextPhysReg(unsigned PReg, unsigned Width) const;
unsigned getVirtRegFor(unsigned PReg) const;
// Type of formal parameter extension.
struct ExtType {
enum { SExt, ZExt };
ExtType() = default;
ExtType(char t, uint16_t w) : Type(t), Width(w) {}
char Type = 0;
uint16_t Width = 0;
};
// Map VR -> extension type.
using RegExtMap = DenseMap<unsigned, ExtType>;
RegExtMap VRX;
};
} // end namespace llvm
#endif // LLVM_LIB_TARGET_HEXAGON_HEXAGONBITTRACKER_H

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,247 @@
//===- HexagonBlockRanges.h -------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIB_TARGET_HEXAGON_HEXAGONBLOCKRANGES_H
#define LLVM_LIB_TARGET_HEXAGON_HEXAGONBLOCKRANGES_H
#include "llvm/ADT/BitVector.h"
#include <cassert>
#include <map>
#include <set>
#include <utility>
#include <vector>
namespace llvm {
class HexagonSubtarget;
class MachineBasicBlock;
class MachineFunction;
class MachineInstr;
class MachineRegisterInfo;
class raw_ostream;
class TargetInstrInfo;
class TargetRegisterInfo;
struct HexagonBlockRanges {
HexagonBlockRanges(MachineFunction &MF);
struct RegisterRef {
unsigned Reg, Sub;
bool operator<(RegisterRef R) const {
return Reg < R.Reg || (Reg == R.Reg && Sub < R.Sub);
}
};
using RegisterSet = std::set<RegisterRef>;
// This is to represent an "index", which is an abstraction of a position
// of an instruction within a basic block.
class IndexType {
public:
enum : unsigned {
None = 0,
Entry = 1,
Exit = 2,
First = 11 // 10th + 1st
};
IndexType() {}
IndexType(unsigned Idx) : Index(Idx) {}
static bool isInstr(IndexType X) { return X.Index >= First; }
operator unsigned() const;
bool operator== (unsigned x) const;
bool operator== (IndexType Idx) const;
bool operator!= (unsigned x) const;
bool operator!= (IndexType Idx) const;
IndexType operator++ ();
bool operator< (unsigned Idx) const;
bool operator< (IndexType Idx) const;
bool operator<= (IndexType Idx) const;
private:
bool operator> (IndexType Idx) const;
bool operator>= (IndexType Idx) const;
unsigned Index = None;
};
// A range of indices, essentially a representation of a live range.
// This is also used to represent "dead ranges", i.e. ranges where a
// register is dead.
class IndexRange : public std::pair<IndexType,IndexType> {
public:
IndexRange() = default;
IndexRange(IndexType Start, IndexType End, bool F = false, bool T = false)
: std::pair<IndexType,IndexType>(Start, End), Fixed(F), TiedEnd(T) {}
IndexType start() const { return first; }
IndexType end() const { return second; }
bool operator< (const IndexRange &A) const {
return start() < A.start();
}
bool overlaps(const IndexRange &A) const;
bool contains(const IndexRange &A) const;
void merge(const IndexRange &A);
bool Fixed = false; // Can be renamed? "Fixed" means "no".
bool TiedEnd = false; // The end is not a use, but a dead def tied to a use.
private:
void setStart(const IndexType &S) { first = S; }
void setEnd(const IndexType &E) { second = E; }
};
// A list of index ranges. This represents liveness of a register
// in a basic block.
class RangeList : public std::vector<IndexRange> {
public:
void add(IndexType Start, IndexType End, bool Fixed, bool TiedEnd) {
push_back(IndexRange(Start, End, Fixed, TiedEnd));
}
void add(const IndexRange &Range) {
push_back(Range);
}
void include(const RangeList &RL);
void unionize(bool MergeAdjacent = false);
void subtract(const IndexRange &Range);
private:
void addsub(const IndexRange &A, const IndexRange &B);
};
class InstrIndexMap {
public:
InstrIndexMap(MachineBasicBlock &B);
MachineInstr *getInstr(IndexType Idx) const;
IndexType getIndex(MachineInstr *MI) const;
MachineBasicBlock &getBlock() const { return Block; }
IndexType getPrevIndex(IndexType Idx) const;
IndexType getNextIndex(IndexType Idx) const;
void replaceInstr(MachineInstr *OldMI, MachineInstr *NewMI);
friend raw_ostream &operator<< (raw_ostream &OS, const InstrIndexMap &Map);
IndexType First, Last;
private:
MachineBasicBlock &Block;
std::map<IndexType,MachineInstr*> Map;
};
using RegToRangeMap = std::map<RegisterRef, RangeList>;
RegToRangeMap computeLiveMap(InstrIndexMap &IndexMap);
RegToRangeMap computeDeadMap(InstrIndexMap &IndexMap, RegToRangeMap &LiveMap);
static RegisterSet expandToSubRegs(RegisterRef R,
const MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI);
struct PrintRangeMap {
PrintRangeMap(const RegToRangeMap &M, const TargetRegisterInfo &I)
: Map(M), TRI(I) {}
friend raw_ostream &operator<< (raw_ostream &OS, const PrintRangeMap &P);
private:
const RegToRangeMap &Map;
const TargetRegisterInfo &TRI;
};
private:
RegisterSet getLiveIns(const MachineBasicBlock &B,
const MachineRegisterInfo &MRI, const TargetRegisterInfo &TRI);
void computeInitialLiveRanges(InstrIndexMap &IndexMap,
RegToRangeMap &LiveMap);
MachineFunction &MF;
const HexagonSubtarget &HST;
const TargetInstrInfo &TII;
const TargetRegisterInfo &TRI;
BitVector Reserved;
};
inline HexagonBlockRanges::IndexType::operator unsigned() const {
assert(Index >= First);
return Index;
}
inline bool HexagonBlockRanges::IndexType::operator== (unsigned x) const {
return Index == x;
}
inline bool HexagonBlockRanges::IndexType::operator== (IndexType Idx) const {
return Index == Idx.Index;
}
inline bool HexagonBlockRanges::IndexType::operator!= (unsigned x) const {
return Index != x;
}
inline bool HexagonBlockRanges::IndexType::operator!= (IndexType Idx) const {
return Index != Idx.Index;
}
inline
HexagonBlockRanges::IndexType HexagonBlockRanges::IndexType::operator++ () {
assert(Index != None);
assert(Index != Exit);
if (Index == Entry)
Index = First;
else
++Index;
return *this;
}
inline bool HexagonBlockRanges::IndexType::operator< (unsigned Idx) const {
return operator< (IndexType(Idx));
}
inline bool HexagonBlockRanges::IndexType::operator< (IndexType Idx) const {
// !(x < x).
if (Index == Idx.Index)
return false;
// !(None < x) for all x.
// !(x < None) for all x.
if (Index == None || Idx.Index == None)
return false;
// !(Exit < x) for all x.
// !(x < Entry) for all x.
if (Index == Exit || Idx.Index == Entry)
return false;
// Entry < x for all x != Entry.
// x < Exit for all x != Exit.
if (Index == Entry || Idx.Index == Exit)
return true;
return Index < Idx.Index;
}
inline bool HexagonBlockRanges::IndexType::operator<= (IndexType Idx) const {
return operator==(Idx) || operator<(Idx);
}
raw_ostream &operator<< (raw_ostream &OS, HexagonBlockRanges::IndexType Idx);
raw_ostream &operator<< (raw_ostream &OS,
const HexagonBlockRanges::IndexRange &IR);
raw_ostream &operator<< (raw_ostream &OS,
const HexagonBlockRanges::RangeList &RL);
raw_ostream &operator<< (raw_ostream &OS,
const HexagonBlockRanges::InstrIndexMap &M);
raw_ostream &operator<< (raw_ostream &OS,
const HexagonBlockRanges::PrintRangeMap &P);
} // end namespace llvm
#endif // LLVM_LIB_TARGET_HEXAGON_HEXAGONBLOCKRANGES_H

View File

@@ -0,0 +1,219 @@
//===--- HexagonBranchRelaxation.cpp - Identify and relax long jumps ------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "hexagon-brelax"
#include "Hexagon.h"
#include "HexagonInstrInfo.h"
#include "HexagonSubtarget.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/Pass.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <cstdint>
#include <cstdlib>
#include <iterator>
using namespace llvm;
// Since we have no exact knowledge of code layout, allow some safety buffer
// for jump target. This is measured in bytes.
static cl::opt<uint32_t> BranchRelaxSafetyBuffer("branch-relax-safety-buffer",
cl::init(200), cl::Hidden, cl::ZeroOrMore, cl::desc("safety buffer size"));
namespace llvm {
FunctionPass *createHexagonBranchRelaxation();
void initializeHexagonBranchRelaxationPass(PassRegistry&);
} // end namespace llvm
namespace {
struct HexagonBranchRelaxation : public MachineFunctionPass {
public:
static char ID;
HexagonBranchRelaxation() : MachineFunctionPass(ID) {
initializeHexagonBranchRelaxationPass(*PassRegistry::getPassRegistry());
}
bool runOnMachineFunction(MachineFunction &MF) override;
StringRef getPassName() const override {
return "Hexagon Branch Relaxation";
}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesCFG();
MachineFunctionPass::getAnalysisUsage(AU);
}
private:
const HexagonInstrInfo *HII;
const HexagonRegisterInfo *HRI;
bool relaxBranches(MachineFunction &MF);
void computeOffset(MachineFunction &MF,
DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset);
bool reGenerateBranch(MachineFunction &MF,
DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset);
bool isJumpOutOfRange(MachineInstr &MI,
DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset);
};
char HexagonBranchRelaxation::ID = 0;
} // end anonymous namespace
INITIALIZE_PASS(HexagonBranchRelaxation, "hexagon-brelax",
"Hexagon Branch Relaxation", false, false)
FunctionPass *llvm::createHexagonBranchRelaxation() {
return new HexagonBranchRelaxation();
}
bool HexagonBranchRelaxation::runOnMachineFunction(MachineFunction &MF) {
DEBUG(dbgs() << "****** Hexagon Branch Relaxation ******\n");
auto &HST = MF.getSubtarget<HexagonSubtarget>();
HII = HST.getInstrInfo();
HRI = HST.getRegisterInfo();
bool Changed = false;
Changed = relaxBranches(MF);
return Changed;
}
void HexagonBranchRelaxation::computeOffset(MachineFunction &MF,
DenseMap<MachineBasicBlock*, unsigned> &OffsetMap) {
// offset of the current instruction from the start.
unsigned InstOffset = 0;
for (auto &B : MF) {
if (B.getAlignment()) {
// Although we don't know the exact layout of the final code, we need
// to account for alignment padding somehow. This heuristic pads each
// aligned basic block according to the alignment value.
int ByteAlign = (1u << B.getAlignment()) - 1;
InstOffset = (InstOffset + ByteAlign) & ~(ByteAlign);
}
OffsetMap[&B] = InstOffset;
for (auto &MI : B.instrs())
InstOffset += HII->getSize(MI);
}
}
/// relaxBranches - For Hexagon, if the jump target/loop label is too far from
/// the jump/loop instruction then, we need to make sure that we have constant
/// extenders set for jumps and loops.
/// There are six iterations in this phase. It's self explanatory below.
bool HexagonBranchRelaxation::relaxBranches(MachineFunction &MF) {
// Compute the offset of each basic block
// offset of the current instruction from the start.
// map for each instruction to the beginning of the function
DenseMap<MachineBasicBlock*, unsigned> BlockToInstOffset;
computeOffset(MF, BlockToInstOffset);
return reGenerateBranch(MF, BlockToInstOffset);
}
/// Check if a given instruction is:
/// - a jump to a distant target
/// - that exceeds its immediate range
/// If both conditions are true, it requires constant extension.
bool HexagonBranchRelaxation::isJumpOutOfRange(MachineInstr &MI,
DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset) {
MachineBasicBlock &B = *MI.getParent();
auto FirstTerm = B.getFirstInstrTerminator();
if (FirstTerm == B.instr_end())
return false;
unsigned InstOffset = BlockToInstOffset[&B];
unsigned Distance = 0;
// To save time, estimate exact position of a branch instruction
// as one at the end of the MBB.
// Number of instructions times typical instruction size.
InstOffset += HII->nonDbgBBSize(&B) * HEXAGON_INSTR_SIZE;
MachineBasicBlock *TBB = nullptr, *FBB = nullptr;
SmallVector<MachineOperand, 4> Cond;
// Try to analyze this branch.
if (HII->analyzeBranch(B, TBB, FBB, Cond, false)) {
// Could not analyze it. See if this is something we can recognize.
// If it is a NVJ, it should always have its target in
// a fixed location.
if (HII->isNewValueJump(*FirstTerm))
TBB = FirstTerm->getOperand(HII->getCExtOpNum(*FirstTerm)).getMBB();
}
if (TBB && &MI == &*FirstTerm) {
Distance = std::abs((long long)InstOffset - BlockToInstOffset[TBB])
+ BranchRelaxSafetyBuffer;
return !HII->isJumpWithinBranchRange(*FirstTerm, Distance);
}
if (FBB) {
// Look for second terminator.
auto SecondTerm = std::next(FirstTerm);
assert(SecondTerm != B.instr_end() &&
(SecondTerm->isBranch() || SecondTerm->isCall()) &&
"Bad second terminator");
if (&MI != &*SecondTerm)
return false;
// Analyze the second branch in the BB.
Distance = std::abs((long long)InstOffset - BlockToInstOffset[FBB])
+ BranchRelaxSafetyBuffer;
return !HII->isJumpWithinBranchRange(*SecondTerm, Distance);
}
return false;
}
bool HexagonBranchRelaxation::reGenerateBranch(MachineFunction &MF,
DenseMap<MachineBasicBlock*, unsigned> &BlockToInstOffset) {
bool Changed = false;
for (auto &B : MF) {
for (auto &MI : B) {
if (!MI.isBranch() || !isJumpOutOfRange(MI, BlockToInstOffset))
continue;
DEBUG(dbgs() << "Long distance jump. isExtendable("
<< HII->isExtendable(MI) << ") isConstExtended("
<< HII->isConstExtended(MI) << ") " << MI);
// Since we have not merged HW loops relaxation into
// this code (yet), soften our approach for the moment.
if (!HII->isExtendable(MI) && !HII->isExtended(MI)) {
DEBUG(dbgs() << "\tUnderimplemented relax branch instruction.\n");
} else {
// Find which operand is expandable.
int ExtOpNum = HII->getCExtOpNum(MI);
MachineOperand &MO = MI.getOperand(ExtOpNum);
// This need to be something we understand. So far we assume all
// branches have only MBB address as expandable field.
// If it changes, this will need to be expanded.
assert(MO.isMBB() && "Branch with unknown expandable field type");
// Mark given operand as extended.
MO.addTargetFlag(HexagonII::HMOTF_ConstExtended);
Changed = true;
}
}
}
return Changed;
}

View File

@@ -0,0 +1,250 @@
//===- HexagonCFGOptimizer.cpp - CFG optimizations ------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "Hexagon.h"
#include "llvm/CodeGen/MachineBasicBlock.h"
#include "llvm/CodeGen/MachineBranchProbabilityInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineOperand.h"
#include "llvm/CodeGen/TargetInstrInfo.h"
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/Pass.h"
#include "llvm/Support/ErrorHandling.h"
#include <cassert>
#include <vector>
using namespace llvm;
#define DEBUG_TYPE "hexagon_cfg"
namespace llvm {
FunctionPass *createHexagonCFGOptimizer();
void initializeHexagonCFGOptimizerPass(PassRegistry&);
} // end namespace llvm
namespace {
class HexagonCFGOptimizer : public MachineFunctionPass {
private:
void InvertAndChangeJumpTarget(MachineInstr &, MachineBasicBlock *);
bool isOnFallThroughPath(MachineBasicBlock *MBB);
public:
static char ID;
HexagonCFGOptimizer() : MachineFunctionPass(ID) {
initializeHexagonCFGOptimizerPass(*PassRegistry::getPassRegistry());
}
StringRef getPassName() const override { return "Hexagon CFG Optimizer"; }
bool runOnMachineFunction(MachineFunction &Fn) override;
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().set(
MachineFunctionProperties::Property::NoVRegs);
}
};
} // end anonymous namespace
char HexagonCFGOptimizer::ID = 0;
static bool IsConditionalBranch(int Opc) {
switch (Opc) {
case Hexagon::J2_jumpt:
case Hexagon::J2_jumptpt:
case Hexagon::J2_jumpf:
case Hexagon::J2_jumpfpt:
case Hexagon::J2_jumptnew:
case Hexagon::J2_jumpfnew:
case Hexagon::J2_jumptnewpt:
case Hexagon::J2_jumpfnewpt:
return true;
}
return false;
}
static bool IsUnconditionalJump(int Opc) {
return (Opc == Hexagon::J2_jump);
}
void HexagonCFGOptimizer::InvertAndChangeJumpTarget(
MachineInstr &MI, MachineBasicBlock *NewTarget) {
const TargetInstrInfo *TII =
MI.getParent()->getParent()->getSubtarget().getInstrInfo();
int NewOpcode = 0;
switch (MI.getOpcode()) {
case Hexagon::J2_jumpt:
NewOpcode = Hexagon::J2_jumpf;
break;
case Hexagon::J2_jumpf:
NewOpcode = Hexagon::J2_jumpt;
break;
case Hexagon::J2_jumptnewpt:
NewOpcode = Hexagon::J2_jumpfnewpt;
break;
case Hexagon::J2_jumpfnewpt:
NewOpcode = Hexagon::J2_jumptnewpt;
break;
default:
llvm_unreachable("Cannot handle this case");
}
MI.setDesc(TII->get(NewOpcode));
MI.getOperand(1).setMBB(NewTarget);
}
bool HexagonCFGOptimizer::isOnFallThroughPath(MachineBasicBlock *MBB) {
if (MBB->canFallThrough())
return true;
for (MachineBasicBlock *PB : MBB->predecessors())
if (PB->isLayoutSuccessor(MBB) && PB->canFallThrough())
return true;
return false;
}
bool HexagonCFGOptimizer::runOnMachineFunction(MachineFunction &Fn) {
if (skipFunction(Fn.getFunction()))
return false;
// Loop over all of the basic blocks.
for (MachineFunction::iterator MBBb = Fn.begin(), MBBe = Fn.end();
MBBb != MBBe; ++MBBb) {
MachineBasicBlock *MBB = &*MBBb;
// Traverse the basic block.
MachineBasicBlock::iterator MII = MBB->getFirstTerminator();
if (MII != MBB->end()) {
MachineInstr &MI = *MII;
int Opc = MI.getOpcode();
if (IsConditionalBranch(Opc)) {
// (Case 1) Transform the code if the following condition occurs:
// BB1: if (p0) jump BB3
// ...falls-through to BB2 ...
// BB2: jump BB4
// ...next block in layout is BB3...
// BB3: ...
//
// Transform this to:
// BB1: if (!p0) jump BB4
// Remove BB2
// BB3: ...
//
// (Case 2) A variation occurs when BB3 contains a JMP to BB4:
// BB1: if (p0) jump BB3
// ...falls-through to BB2 ...
// BB2: jump BB4
// ...other basic blocks ...
// BB4:
// ...not a fall-thru
// BB3: ...
// jump BB4
//
// Transform this to:
// BB1: if (!p0) jump BB4
// Remove BB2
// BB3: ...
// BB4: ...
unsigned NumSuccs = MBB->succ_size();
MachineBasicBlock::succ_iterator SI = MBB->succ_begin();
MachineBasicBlock* FirstSucc = *SI;
MachineBasicBlock* SecondSucc = *(++SI);
MachineBasicBlock* LayoutSucc = nullptr;
MachineBasicBlock* JumpAroundTarget = nullptr;
if (MBB->isLayoutSuccessor(FirstSucc)) {
LayoutSucc = FirstSucc;
JumpAroundTarget = SecondSucc;
} else if (MBB->isLayoutSuccessor(SecondSucc)) {
LayoutSucc = SecondSucc;
JumpAroundTarget = FirstSucc;
} else {
// Odd case...cannot handle.
}
// The target of the unconditional branch must be JumpAroundTarget.
// TODO: If not, we should not invert the unconditional branch.
MachineBasicBlock* CondBranchTarget = nullptr;
if (MI.getOpcode() == Hexagon::J2_jumpt ||
MI.getOpcode() == Hexagon::J2_jumpf) {
CondBranchTarget = MI.getOperand(1).getMBB();
}
if (!LayoutSucc || (CondBranchTarget != JumpAroundTarget)) {
continue;
}
if ((NumSuccs == 2) && LayoutSucc && (LayoutSucc->pred_size() == 1)) {
// Ensure that BB2 has one instruction -- an unconditional jump.
if ((LayoutSucc->size() == 1) &&
IsUnconditionalJump(LayoutSucc->front().getOpcode())) {
assert(JumpAroundTarget && "jump target is needed to process second basic block");
MachineBasicBlock* UncondTarget =
LayoutSucc->front().getOperand(0).getMBB();
// Check if the layout successor of BB2 is BB3.
bool case1 = LayoutSucc->isLayoutSuccessor(JumpAroundTarget);
bool case2 = JumpAroundTarget->isSuccessor(UncondTarget) &&
!JumpAroundTarget->empty() &&
IsUnconditionalJump(JumpAroundTarget->back().getOpcode()) &&
JumpAroundTarget->pred_size() == 1 &&
JumpAroundTarget->succ_size() == 1;
if (case1 || case2) {
InvertAndChangeJumpTarget(MI, UncondTarget);
MBB->replaceSuccessor(JumpAroundTarget, UncondTarget);
// Remove the unconditional branch in LayoutSucc.
LayoutSucc->erase(LayoutSucc->begin());
LayoutSucc->replaceSuccessor(UncondTarget, JumpAroundTarget);
// This code performs the conversion for case 2, which moves
// the block to the fall-thru case (BB3 in the code above).
if (case2 && !case1) {
JumpAroundTarget->moveAfter(LayoutSucc);
// only move a block if it doesn't have a fall-thru. otherwise
// the CFG will be incorrect.
if (!isOnFallThroughPath(UncondTarget))
UncondTarget->moveAfter(JumpAroundTarget);
}
// Correct live-in information. Is used by post-RA scheduler
// The live-in to LayoutSucc is now all values live-in to
// JumpAroundTarget.
std::vector<MachineBasicBlock::RegisterMaskPair> OrigLiveIn(
LayoutSucc->livein_begin(), LayoutSucc->livein_end());
std::vector<MachineBasicBlock::RegisterMaskPair> NewLiveIn(
JumpAroundTarget->livein_begin(),
JumpAroundTarget->livein_end());
for (const auto &OrigLI : OrigLiveIn)
LayoutSucc->removeLiveIn(OrigLI.PhysReg);
for (const auto &NewLI : NewLiveIn)
LayoutSucc->addLiveIn(NewLI);
}
}
}
}
}
}
return true;
}
//===----------------------------------------------------------------------===//
// Public Constructor Functions
//===----------------------------------------------------------------------===//
INITIALIZE_PASS(HexagonCFGOptimizer, "hexagon-cfg", "Hexagon CFG Optimizer",
false, false)
FunctionPass *llvm::createHexagonCFGOptimizer() {
return new HexagonCFGOptimizer();
}

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