1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 12:41:49 +01:00

Hexagon backend support

llvm-svn: 146412
This commit is contained in:
Tony Linthicum 2011-12-12 21:14:40 +00:00
parent 5b25b4d437
commit 61adbf8dc5
77 changed files with 24690 additions and 11 deletions

View File

@ -72,6 +72,7 @@ set(LLVM_ALL_TARGETS
CBackend
CellSPU
CppBackend
Hexagon
Mips
MBlaze
MSP430

4
autoconf/config.sub vendored
View File

@ -4,7 +4,7 @@
# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
# 2011 Free Software Foundation, Inc.
timestamp='2011-08-23'
timestamp='2011-11-02'
# This file is (in principle) common to ALL GNU software.
# The presence of a machine in this file suggests that SOME GNU software
@ -256,6 +256,7 @@ case $basic_machine in
| c4x | clipper \
| d10v | d30v | dlx | dsp16xx \
| fido | fr30 | frv \
| hexagon \
| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
| i370 | i860 | i960 | ia64 \
| ip2k | iq2000 \
@ -367,6 +368,7 @@ case $basic_machine in
| elxsi-* \
| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
| h8300-* | h8500-* \
| hexagon-* \
| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
| i*86-* | i860-* | i960-* | ia64-* \
| ip2k-* | iq2000-* \

View File

@ -357,6 +357,7 @@ AC_CACHE_CHECK([target architecture],[llvm_cv_target_arch],
mips-*) llvm_cv_target_arch="Mips" ;;
xcore-*) llvm_cv_target_arch="XCore" ;;
msp430-*) llvm_cv_target_arch="MSP430" ;;
hexagon-*) llvm_cv_target_arch="Hexagon" ;;
mblaze-*) llvm_cv_target_arch="MBlaze" ;;
ptx-*) llvm_cv_target_arch="PTX" ;;
*) llvm_cv_target_arch="Unknown" ;;
@ -503,6 +504,7 @@ else
Mips) AC_SUBST(TARGET_HAS_JIT,1) ;;
XCore) AC_SUBST(TARGET_HAS_JIT,0) ;;
MSP430) AC_SUBST(TARGET_HAS_JIT,0) ;;
Hexagon) AC_SUBST(TARGET_HAS_JIT,0) ;;
MBlaze) AC_SUBST(TARGET_HAS_JIT,0) ;;
PTX) AC_SUBST(TARGET_HAS_JIT,0) ;;
*) AC_SUBST(TARGET_HAS_JIT,0) ;;
@ -615,14 +617,14 @@ dnl Allow specific targets to be specified for building (or not)
TARGETS_TO_BUILD=""
AC_ARG_ENABLE([targets],AS_HELP_STRING([--enable-targets],
[Build specific host targets: all or target1,target2,... Valid targets are:
host, x86, x86_64, sparc, powerpc, arm, mips, spu,
host, x86, x86_64, sparc, powerpc, arm, mips, spu, hexagon,
xcore, msp430, ptx, cbe, and cpp (default=all)]),,
enableval=all)
if test "$enableval" = host-only ; then
enableval=host
fi
case "$enableval" in
all) TARGETS_TO_BUILD="X86 Sparc PowerPC ARM Mips CellSPU XCore MSP430 CBackend CppBackend MBlaze PTX" ;;
all) TARGETS_TO_BUILD="X86 Sparc PowerPC ARM Mips CellSPU XCore MSP430 CBackend CppBackend MBlaze PTX Hexagon" ;;
*)for a_target in `echo $enableval|sed -e 's/,/ /g' ` ; do
case "$a_target" in
x86) TARGETS_TO_BUILD="X86 $TARGETS_TO_BUILD" ;;
@ -636,6 +638,7 @@ case "$enableval" in
msp430) TARGETS_TO_BUILD="MSP430 $TARGETS_TO_BUILD" ;;
cbe) TARGETS_TO_BUILD="CBackend $TARGETS_TO_BUILD" ;;
cpp) TARGETS_TO_BUILD="CppBackend $TARGETS_TO_BUILD" ;;
hexagon) TARGETS_TO_BUILD="Hexagon $TARGETS_TO_BUILD" ;;
mblaze) TARGETS_TO_BUILD="MBlaze $TARGETS_TO_BUILD" ;;
ptx) TARGETS_TO_BUILD="PTX $TARGETS_TO_BUILD" ;;
host) case "$llvm_cv_target_arch" in
@ -649,6 +652,7 @@ case "$enableval" in
CellSPU|SPU) TARGETS_TO_BUILD="CellSPU $TARGETS_TO_BUILD" ;;
XCore) TARGETS_TO_BUILD="XCore $TARGETS_TO_BUILD" ;;
MSP430) TARGETS_TO_BUILD="MSP430 $TARGETS_TO_BUILD" ;;
Hexagon) TARGETS_TO_BUILD="Hexagon $TARGETS_TO_BUILD" ;;
PTX) TARGETS_TO_BUILD="PTX $TARGETS_TO_BUILD" ;;
*) AC_MSG_ERROR([Can not set target to build]) ;;
esac ;;

9
configure vendored
View File

@ -1419,7 +1419,7 @@ Optional Features:
--enable-targets Build specific host targets: all or
target1,target2,... Valid targets are: host, x86,
x86_64, sparc, powerpc, arm, mips, spu, xcore,
msp430, ptx, cbe, and cpp (default=all)
hexagon, msp430, ptx, cbe, and cpp (default=all)
--enable-cbe-printf-a Enable C Backend output with hex floating point via
%a (default is YES)
--enable-bindings Build specific language bindings:
@ -3883,6 +3883,7 @@ else
mips-*) llvm_cv_target_arch="Mips" ;;
xcore-*) llvm_cv_target_arch="XCore" ;;
msp430-*) llvm_cv_target_arch="MSP430" ;;
hexagon-*) llvm_cv_target_arch="Hexagon" ;;
mblaze-*) llvm_cv_target_arch="MBlaze" ;;
ptx-*) llvm_cv_target_arch="PTX" ;;
*) llvm_cv_target_arch="Unknown" ;;
@ -5102,6 +5103,8 @@ else
XCore) TARGET_HAS_JIT=0
;;
MSP430) TARGET_HAS_JIT=0
;;
Hexagon) TARGET_HAS_JIT=0
;;
MBlaze) TARGET_HAS_JIT=0
;;
@ -5291,7 +5294,7 @@ if test "$enableval" = host-only ; then
enableval=host
fi
case "$enableval" in
all) TARGETS_TO_BUILD="X86 Sparc PowerPC ARM Mips CellSPU XCore MSP430 CBackend CppBackend MBlaze PTX" ;;
all) TARGETS_TO_BUILD="X86 Sparc PowerPC ARM Mips CellSPU XCore MSP430 CBackend CppBackend MBlaze PTX Hexagon" ;;
*)for a_target in `echo $enableval|sed -e 's/,/ /g' ` ; do
case "$a_target" in
x86) TARGETS_TO_BUILD="X86 $TARGETS_TO_BUILD" ;;
@ -5305,6 +5308,7 @@ case "$enableval" in
msp430) TARGETS_TO_BUILD="MSP430 $TARGETS_TO_BUILD" ;;
cbe) TARGETS_TO_BUILD="CBackend $TARGETS_TO_BUILD" ;;
cpp) TARGETS_TO_BUILD="CppBackend $TARGETS_TO_BUILD" ;;
hexagon) TARGETS_TO_BUILD="Hexagon $TARGETS_TO_BUILD" ;;
mblaze) TARGETS_TO_BUILD="MBlaze $TARGETS_TO_BUILD" ;;
ptx) TARGETS_TO_BUILD="PTX $TARGETS_TO_BUILD" ;;
host) case "$llvm_cv_target_arch" in
@ -5318,6 +5322,7 @@ case "$enableval" in
CellSPU|SPU) TARGETS_TO_BUILD="CellSPU $TARGETS_TO_BUILD" ;;
XCore) TARGETS_TO_BUILD="XCore $TARGETS_TO_BUILD" ;;
MSP430) TARGETS_TO_BUILD="MSP430 $TARGETS_TO_BUILD" ;;
Hexagon) TARGETS_TO_BUILD="Hexagon $TARGETS_TO_BUILD" ;;
PTX) TARGETS_TO_BUILD="PTX $TARGETS_TO_BUILD" ;;
*) { { echo "$as_me:$LINENO: error: Can not set target to build" >&5
echo "$as_me: error: Can not set target to build" >&2;}

View File

@ -2288,6 +2288,7 @@ is the key:</p>
<th>Feature</th>
<th>ARM</th>
<th>CellSPU</th>
<th>Hexagon</th>
<th>MBlaze</th>
<th>MSP430</th>
<th>Mips</th>
@ -2302,6 +2303,7 @@ is the key:</p>
<td><a href="#feat_reliable">is generally reliable</a></td>
<td class="yes"></td> <!-- ARM -->
<td class="no"></td> <!-- CellSPU -->
<td class="yes"></td> <!-- Hexagon -->
<td class="no"></td> <!-- MBlaze -->
<td class="unknown"></td> <!-- MSP430 -->
<td class="yes"></td> <!-- Mips -->
@ -2316,6 +2318,7 @@ is the key:</p>
<td><a href="#feat_asmparser">assembly parser</a></td>
<td class="no"></td> <!-- ARM -->
<td class="no"></td> <!-- CellSPU -->
<td class="no"></td> <!-- Hexagon -->
<td class="yes"></td> <!-- MBlaze -->
<td class="no"></td> <!-- MSP430 -->
<td class="no"></td> <!-- Mips -->
@ -2330,6 +2333,7 @@ is the key:</p>
<td><a href="#feat_disassembler">disassembler</a></td>
<td class="yes"></td> <!-- ARM -->
<td class="no"></td> <!-- CellSPU -->
<td class="no"></td> <!-- Hexagon -->
<td class="yes"></td> <!-- MBlaze -->
<td class="no"></td> <!-- MSP430 -->
<td class="no"></td> <!-- Mips -->
@ -2344,6 +2348,7 @@ is the key:</p>
<td><a href="#feat_inlineasm">inline asm</a></td>
<td class="yes"></td> <!-- ARM -->
<td class="no"></td> <!-- CellSPU -->
<td class="yes"></td> <!-- Hexagon -->
<td class="yes"></td> <!-- MBlaze -->
<td class="unknown"></td> <!-- MSP430 -->
<td class="no"></td> <!-- Mips -->
@ -2358,6 +2363,7 @@ is the key:</p>
<td><a href="#feat_jit">jit</a></td>
<td class="partial"><a href="#feat_jit_arm">*</a></td> <!-- ARM -->
<td class="no"></td> <!-- CellSPU -->
<td class="no"></td> <!-- Hexagon -->
<td class="no"></td> <!-- MBlaze -->
<td class="unknown"></td> <!-- MSP430 -->
<td class="yes"></td> <!-- Mips -->
@ -2372,6 +2378,7 @@ is the key:</p>
<td><a href="#feat_objectwrite">.o&nbsp;file writing</a></td>
<td class="no"></td> <!-- ARM -->
<td class="no"></td> <!-- CellSPU -->
<td class="no"></td> <!-- Hexagon -->
<td class="yes"></td> <!-- MBlaze -->
<td class="no"></td> <!-- MSP430 -->
<td class="no"></td> <!-- Mips -->
@ -2386,6 +2393,7 @@ is the key:</p>
<td><a href="#feat_tailcall">tail calls</a></td>
<td class="yes"></td> <!-- ARM -->
<td class="no"></td> <!-- CellSPU -->
<td class="yes"></td> <!-- Hexagon -->
<td class="no"></td> <!-- MBlaze -->
<td class="unknown"></td> <!-- MSP430 -->
<td class="no"></td> <!-- Mips -->

View File

@ -45,6 +45,7 @@ public:
arm, // ARM; arm, armv.*, xscale
cellspu, // CellSPU: spu, cellspu
hexagon, // Hexagon: hexagon
mips, // MIPS: mips, mipsallegrex
mipsel, // MIPSEL: mipsel, mipsallegrexel, psp
mips64, // MIPS64: mips64

View File

@ -444,3 +444,4 @@ include "llvm/IntrinsicsARM.td"
include "llvm/IntrinsicsCellSPU.td"
include "llvm/IntrinsicsXCore.td"
include "llvm/IntrinsicsPTX.td"
include "llvm/IntrinsicsHexagon.td"

File diff suppressed because it is too large Load Diff

View File

@ -51,6 +51,13 @@ inline bool isInt<32>(int64_t x) {
return static_cast<int32_t>(x) == x;
}
/// isShiftedInt<N,S> - Checks if a signed integer is an N bit number shifted
/// left by S.
template<unsigned N, unsigned S>
inline bool isShiftedInt(int64_t x) {
return isInt<N+S>(x) && (x % (1<<S) == 0);
}
/// isUInt - Checks if an unsigned integer fits into the given bit width.
template<unsigned N>
inline bool isUInt(uint64_t x) {
@ -70,6 +77,13 @@ inline bool isUInt<32>(uint64_t x) {
return static_cast<uint32_t>(x) == x;
}
/// isShiftedUInt<N,S> - Checks if a unsigned integer is an N bit number shifted
/// left by S.
template<unsigned N, unsigned S>
inline bool isShiftedUInt(uint64_t x) {
return isUInt<N+S>(x) && (x % (1<<S) == 0);
}
/// isUIntN - Checks if an unsigned integer fits into the given (dynamic)
/// bit width.
inline bool isUIntN(unsigned N, uint64_t x) {

View File

@ -20,6 +20,7 @@ const char *Triple::getArchTypeName(ArchType Kind) {
case arm: return "arm";
case cellspu: return "cellspu";
case hexagon: return "hexagon";
case mips: return "mips";
case mipsel: return "mipsel";
case mips64: return "mips64";
@ -59,6 +60,8 @@ const char *Triple::getArchTypePrefix(ArchType Kind) {
case mblaze: return "mblaze";
case hexagon: return "hexagon";
case sparcv9:
case sparc: return "sparc";
@ -150,6 +153,8 @@ Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) {
return ppc;
if (Name == "mblaze")
return mblaze;
if (Name == "hexagon")
return hexagon;
if (Name == "sparc")
return sparc;
if (Name == "sparcv9")
@ -295,6 +300,8 @@ Triple::ArchType Triple::ParseArch(StringRef ArchName) {
return mips64;
else if (ArchName == "mips64el")
return mips64el;
else if (ArchName == "hexagon")
return hexagon;
else if (ArchName == "sparc")
return sparc;
else if (ArchName == "sparcv9")

View File

@ -0,0 +1,43 @@
set(LLVM_TARGET_DEFINITIONS Hexagon.td)
tablegen(LLVM HexagonGenRegisterInfo.inc -gen-register-info)
tablegen(LLVM HexagonGenInstrInfo.inc -gen-instr-info)
tablegen(LLVM HexagonGenAsmWriter.inc -gen-asm-writer)
tablegen(LLVM HexagonGenDAGISel.inc -gen-dag-isel)
tablegen(LLVM HexagonGenCallingConv.inc -gen-callingconv)
tablegen(LLVM HexagonGenSubtargetInfo.inc -gen-subtarget)
tablegen(LLVM HexagonGenIntrinsics.inc -gen-tgt-intrinsic)
add_public_tablegen_target(HexagonCommonTableGen)
add_llvm_target(HexagonCodeGen
HexagonAsmPrinter.cpp
HexagonCallingConvLower.cpp
HexagonCFGOptimizer.cpp
HexagonExpandPredSpillCode.cpp
HexagonFrameLowering.cpp
HexagonHardwareLoops.cpp
HexagonInstrInfo.cpp
HexagonISelDAGToDAG.cpp
HexagonISelLowering.cpp
HexagonMCAsmInfo.cpp
HexagonOptimizeSZExtends.cpp
HexagonRegisterInfo.cpp
HexagonRemoveSZExtArgs.cpp
HexagonSelectionDAGInfo.cpp
HexagonSplitTFRCondSets.cpp
HexagonSubtarget.cpp
HexagonTargetMachine.cpp
HexagonTargetObjectFile.cpp
)
add_llvm_library_dependencies(LLVMHexagonCodeGen
LLVMAsmPrinter
LLVMCodeGen
LLVMCore
LLVMHexagonInfo
LLVMSelectionDAG
LLVMSupport
LLVMTarget
)
add_subdirectory(TargetInfo)

View File

@ -0,0 +1,68 @@
//=-- 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 TARGET_Hexagon_H
#define TARGET_Hexagon_H
#include <cassert>
#include "llvm/Target/TargetLowering.h"
namespace llvm {
class FunctionPass;
class TargetMachine;
class HexagonTargetMachine;
class raw_ostream;
FunctionPass *createHexagonISelDag(HexagonTargetMachine &TM);
FunctionPass *createHexagonDelaySlotFillerPass(TargetMachine &TM);
FunctionPass *createHexagonFPMoverPass(TargetMachine &TM);
FunctionPass *createHexagonRemoveExtendOps(HexagonTargetMachine &TM);
FunctionPass *createHexagonCFGOptimizer(HexagonTargetMachine &TM);
FunctionPass* createHexagonSplitTFRCondSets(HexagonTargetMachine &TM);
FunctionPass* createHexagonExpandPredSpillCode(HexagonTargetMachine &TM);
FunctionPass *createHexagonHardwareLoops();
FunctionPass *createHexagonOptimizeSZExtends();
FunctionPass *createHexagonFixupHwLoops();
extern Target TheHexagonTarget;
} // end namespace llvm;
// Defines symbolic names for Hexagon instructions and registers.
// This defines a mapping from register name to register number.
//
#define GET_REGINFO_ENUM
#include "HexagonGenRegisterInfo.inc"
#define GET_INSTRINFO_ENUM
#include "HexagonGenInstrInfo.inc"
#define GET_SUBTARGETINFO_ENUM
#include "HexagonGenSubtargetInfo.inc"
#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
#endif

View File

@ -0,0 +1,66 @@
//===- Hexagon.td - Describe the Hexagon Target Machine ---------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Target-independent interfaces which we are implementing
//===----------------------------------------------------------------------===//
include "llvm/Target/Target.td"
//===----------------------------------------------------------------------===//
// Hexagon Subtarget features.
//
// Hexagon Archtectures
def ArchV2 : SubtargetFeature<"v2", "HexagonArchVersion", "V2",
"Hexagon v2">;
def ArchV3 : SubtargetFeature<"v3", "HexagonArchVersion", "V3",
"Hexagon v3">;
def ArchV4 : SubtargetFeature<"v4", "HexagonArchVersion", "V4",
"Hexagon v4">;
//===----------------------------------------------------------------------===//
// Register File, Calling Conv, Instruction Descriptions
//===----------------------------------------------------------------------===//
include "HexagonSchedule.td"
include "HexagonRegisterInfo.td"
include "HexagonCallingConv.td"
include "HexagonInstrInfo.td"
include "HexagonIntrinsics.td"
include "HexagonIntrinsicsDerived.td"
def HexagonInstrInfo : InstrInfo {
// Define how we want to layout our target-specific information field.
}
//===----------------------------------------------------------------------===//
// Hexagon processors supported.
//===----------------------------------------------------------------------===//
class Proc<string Name, ProcessorItineraries Itin,
list<SubtargetFeature> Features>
: Processor<Name, Itin, Features>;
def : Proc<"hexagonv2", HexagonItineraries, [ArchV2]>;
def : Proc<"hexagonv3", HexagonItineraries, [ArchV2, ArchV3]>;
def : Proc<"hexagonv4", HexagonItinerariesV4, [ArchV2, ArchV3, ArchV4]>;
//===----------------------------------------------------------------------===//
// Declare the target which we are implementing
//===----------------------------------------------------------------------===//
def Hexagon : Target {
// Pull in Instruction Info:
let InstructionSet = HexagonInstrInfo;
}

View File

@ -0,0 +1,555 @@
//===-- HexagonAsmPrinter.cpp - Print machine instrs to Hexagon assembly ----=//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains a printer that converts from our internal representation
// of machine-dependent LLVM code to Hexagon assembly language. This printer is
// the output mechanism used by `llc'.
//
// Documentation at http://developer.apple.com/documentation/DeveloperTools/
// Reference/Assembler/ASMIntroduction/chapter_1_section_1.html
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "asm-printer"
#include "Hexagon.h"
#include "HexagonTargetMachine.h"
#include "HexagonSubtarget.h"
#include "HexagonMachineFunctionInfo.h"
#include "llvm/Constants.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Module.h"
#include "llvm/Assembly/Writer.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/MC/MCSymbol.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/Mangler.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetLoweringObjectFile.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
static cl::opt<bool> AlignCalls(
"hexagon-align-calls", cl::Hidden, cl::init(true),
cl::desc("Insert falign after call instruction for Hexagon target"));
namespace {
class HexagonAsmPrinter : public AsmPrinter {
const HexagonSubtarget *Subtarget;
public:
explicit HexagonAsmPrinter(TargetMachine &TM, MCStreamer &Streamer)
: AsmPrinter(TM, Streamer) {
Subtarget = &TM.getSubtarget<HexagonSubtarget>();
}
virtual const char *getPassName() const {
return "Hexagon Assembly Printer";
}
/// printInstruction - This method is automatically generated by tablegen
/// from the instruction set description. This method returns true if the
/// machine instruction was sufficiently described to print it, otherwise it
void printInstruction(const MachineInstr *MI, raw_ostream &O);
virtual void EmitInstruction(const MachineInstr *MI);
void printOp(const MachineOperand &MO, raw_ostream &O);
/// printRegister - Print register according to target requirements.
///
void printRegister(const MachineOperand &MO, bool R0AsZero,
raw_ostream &O) {
unsigned RegNo = MO.getReg();
assert(TargetRegisterInfo::isPhysicalRegister(RegNo) && "Not physreg??");
O << getRegisterName(RegNo);
}
void printOperand(const MachineInstr *MI, unsigned OpNo, raw_ostream &OS) {
const MachineOperand &MO = MI->getOperand(OpNo);
if (MO.isReg()) {
printRegister(MO, false, OS);
} else if (MO.isImm()) {
OS << MO.getImm();
} else {
printOp(MO, OS);
}
}
bool isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) const;
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant, const char *ExtraCode,
raw_ostream &OS);
bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant, const char *ExtraCode,
raw_ostream &OS);
void printHexagonImmOperand(const MachineInstr *MI, unsigned OpNo,
raw_ostream &O) {
int value = MI->getOperand(OpNo).getImm();
O << value;
}
void printHexagonNegImmOperand(const MachineInstr *MI, unsigned OpNo,
raw_ostream &O) {
int value = MI->getOperand(OpNo).getImm();
O << -value;
}
void printHexagonMEMriOperand(const MachineInstr *MI, unsigned OpNo,
raw_ostream &O) {
const MachineOperand &MO1 = MI->getOperand(OpNo);
const MachineOperand &MO2 = MI->getOperand(OpNo+1);
O << getRegisterName(MO1.getReg())
<< " + #"
<< (int) MO2.getImm();
}
void printHexagonFrameIndexOperand(const MachineInstr *MI, unsigned OpNo,
raw_ostream &O) {
const MachineOperand &MO1 = MI->getOperand(OpNo);
const MachineOperand &MO2 = MI->getOperand(OpNo+1);
O << getRegisterName(MO1.getReg())
<< ", #"
<< MO2.getImm();
}
void printBranchOperand(const MachineInstr *MI, unsigned OpNo,
raw_ostream &O) {
// Branches can take an immediate operand. This is used by the branch
// selection pass to print $+8, an eight byte displacement from the PC.
if (MI->getOperand(OpNo).isImm()) {
O << "$+" << MI->getOperand(OpNo).getImm()*4;
} else {
printOp(MI->getOperand(OpNo), O);
}
}
void printCallOperand(const MachineInstr *MI, unsigned OpNo,
raw_ostream &O) {
}
void printAbsAddrOperand(const MachineInstr *MI, unsigned OpNo,
raw_ostream &O) {
}
void printSymbolHi(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
O << "#HI(";
if (MI->getOperand(OpNo).isImm()) {
printHexagonImmOperand(MI, OpNo, O);
} else {
printOp(MI->getOperand(OpNo), O);
}
O << ")";
}
void printSymbolLo(const MachineInstr *MI, unsigned OpNo, raw_ostream &O) {
O << "#HI(";
if (MI->getOperand(OpNo).isImm()) {
printHexagonImmOperand(MI, OpNo, O);
} else {
printOp(MI->getOperand(OpNo), O);
}
O << ")";
}
void printPredicateOperand(const MachineInstr *MI, unsigned OpNo,
raw_ostream &O);
void printAddrModeBasePlusOffset(const MachineInstr *MI, int OpNo,
raw_ostream &O);
void printGlobalOperand(const MachineInstr *MI, int OpNo, raw_ostream &O);
void printJumpTable(const MachineInstr *MI, int OpNo, raw_ostream &O);
void EmitAlignment(unsigned NumBits, const GlobalValue *GV = 0) const;
static const char *getRegisterName(unsigned RegNo);
};
} // end of anonymous namespace
// Include the auto-generated portion of the assembly writer.
#include "HexagonGenAsmWriter.inc"
void HexagonAsmPrinter::EmitAlignment(unsigned NumBits,
const GlobalValue *GV) const {
// For basic block level alignment, use falign.
if (!GV) {
OutStreamer.EmitRawText(StringRef("\t.falign"));
return;
}
AsmPrinter::EmitAlignment(NumBits, GV);
}
void HexagonAsmPrinter::printOp(const MachineOperand &MO, raw_ostream &O) {
switch (MO.getType()) {
case MachineOperand::MO_Immediate:
dbgs() << "printOp() does not handle immediate values\n";
abort();
return;
case MachineOperand::MO_MachineBasicBlock:
O << *MO.getMBB()->getSymbol();
return;
case MachineOperand::MO_JumpTableIndex:
O << *GetJTISymbol(MO.getIndex());
// FIXME: PIC relocation model.
return;
case MachineOperand::MO_ConstantPoolIndex:
O << *GetCPISymbol(MO.getIndex());
return;
case MachineOperand::MO_ExternalSymbol:
O << *GetExternalSymbolSymbol(MO.getSymbolName());
return;
case MachineOperand::MO_GlobalAddress: {
// Computing the address of a global symbol, not calling it.
O << *Mang->getSymbol(MO.getGlobal());
printOffset(MO.getOffset(), O);
return;
}
default:
O << "<unknown operand type: " << MO.getType() << ">";
return;
}
}
//
// isBlockOnlyReachableByFallthrough - We need to override this since the
// default AsmPrinter does not print labels for any basic block that
// is only reachable by a fall through. That works for all cases except
// for the case in which the basic block is reachable by a fall through but
// through an indirect from a jump table. In this case, the jump table
// will contain a label not defined by AsmPrinter.
//
bool HexagonAsmPrinter::
isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) const {
if (MBB->hasAddressTaken()) {
return false;
}
return AsmPrinter::isBlockOnlyReachableByFallthrough(MBB);
}
/// PrintAsmOperand - Print out an operand for an inline asm expression.
///
bool HexagonAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
unsigned AsmVariant,
const char *ExtraCode,
raw_ostream &OS) {
// Does this asm operand have a single letter operand modifier?
if (ExtraCode && ExtraCode[0]) {
if (ExtraCode[1] != 0) return true; // Unknown modifier.
switch (ExtraCode[0]) {
default: return true; // Unknown modifier.
case 'c': // Don't print "$" before a global var name or constant.
// Hexagon never has a prefix.
printOperand(MI, OpNo, OS);
return false;
case 'L': // Write second word of DImode reference.
// Verify that this operand has two consecutive registers.
if (!MI->getOperand(OpNo).isReg() ||
OpNo+1 == MI->getNumOperands() ||
!MI->getOperand(OpNo+1).isReg())
return true;
++OpNo; // Return the high-part.
break;
case 'I':
// Write 'i' if an integer constant, otherwise nothing. Used to print
// addi vs add, etc.
if (MI->getOperand(OpNo).isImm())
OS << "i";
return false;
}
}
printOperand(MI, OpNo, OS);
return false;
}
bool HexagonAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
unsigned OpNo, unsigned AsmVariant,
const char *ExtraCode,
raw_ostream &O) {
if (ExtraCode && ExtraCode[0])
return true; // Unknown modifier.
const MachineOperand &Base = MI->getOperand(OpNo);
const MachineOperand &Offset = MI->getOperand(OpNo+1);
if (Base.isReg())
printOperand(MI, OpNo, O);
else
assert(0 && "Unimplemented");
if (Offset.isImm()) {
if (Offset.getImm())
O << " + #" << Offset.getImm();
}
else
assert(0 && "Unimplemented");
return false;
}
void HexagonAsmPrinter::printPredicateOperand(const MachineInstr *MI,
unsigned OpNo,
raw_ostream &O) {
assert(0 && "Unimplemented");
}
/// printMachineInstruction -- Print out a single Hexagon MI in Darwin syntax to
/// the current output stream.
///
void HexagonAsmPrinter::EmitInstruction(const MachineInstr *MI) {
SmallString<128> Str;
raw_svector_ostream O(Str);
const MachineFunction* MF = MI->getParent()->getParent();
const HexagonMachineFunctionInfo* MFI =
(const HexagonMachineFunctionInfo*)
MF->getInfo<HexagonMachineFunctionInfo>();
// Print a brace for the beginning of the packet.
if (MFI->isStartPacket(MI)) {
O << "\t{" << '\n';
}
DEBUG( O << "// MI = " << *MI << '\n';);
// Indent
O << "\t";
if (MI->getOpcode() == Hexagon::ENDLOOP0) {
if (MFI->isEndPacket(MI) && MFI->isStartPacket(MI)) {
O << "\t{ nop }";
} else {
O << "}";
}
printInstruction(MI, O);
} else if (MI->getOpcode() == Hexagon::STriwt) {
//
// Handle truncated store on Hexagon.
//
O << "\tmemw(";
printHexagonMEMriOperand(MI, 0, O);
O << ") = ";
unsigned SubRegNum =
TM.getRegisterInfo()->getSubReg(MI->getOperand(2)
.getReg(), Hexagon::subreg_loreg);
const char *SubRegName = getRegisterName(SubRegNum);
O << SubRegName << '\n';
} else if (MI->getOpcode() == Hexagon::MPYI_rin) {
// Handle multipy with -ve constant on Hexagon:
// "$dst =- mpyi($src1, #$src2)"
printOperand(MI, 0, O);
O << " =- mpyi(";
printOperand(MI, 1, O);
O << ", #";
printHexagonNegImmOperand(MI, 2, O);
O << ")";
} else if (MI->getOpcode() == Hexagon::MEMw_ADDSUBi_indexed_MEM_V4) {
//
// Handle memw(Rs+u6:2) [+-]= #U5
//
O << "\tmemw("; printHexagonMEMriOperand(MI, 0, O); O << ") ";
int addend = MI->getOperand(2).getImm();
if (addend < 0)
O << "-= " << "#" << -addend << '\n';
else
O << "+= " << "#" << addend << '\n';
} else if (MI->getOpcode() == Hexagon::MEMw_ADDSUBi_MEM_V4) {
//
// Handle memw(Rs+u6:2) [+-]= #U5
//
O << "\tmemw("; printHexagonMEMriOperand(MI, 0, O); O << ") ";
int addend = MI->getOperand(2).getImm();
if (addend < 0)
O << "-= " << "#" << -addend << '\n';
else
O << "+= " << "#" << addend << '\n';
} else if (MI->getOpcode() == Hexagon::MEMh_ADDSUBi_indexed_MEM_V4) {
//
// Handle memh(Rs+u6:1) [+-]= #U5
//
O << "\tmemh("; printHexagonMEMriOperand(MI, 0, O); O << ") ";
int addend = MI->getOperand(2).getImm();
if (addend < 0)
O << "-= " << "#" << -addend << '\n';
else
O << "+= " << "#" << addend << '\n';
} else if (MI->getOpcode() == Hexagon::MEMh_ADDSUBi_MEM_V4) {
//
// Handle memh(Rs+u6:1) [+-]= #U5
//
O << "\tmemh("; printHexagonMEMriOperand(MI, 0, O); O << ") ";
int addend = MI->getOperand(2).getImm();
if (addend < 0)
O << "-= " << "#" << -addend << '\n';
else
O << "+= " << "#" << addend << '\n';
} else if (MI->getOpcode() == Hexagon::MEMb_ADDSUBi_indexed_MEM_V4) {
//
// Handle memb(Rs+u6:1) [+-]= #U5
//
O << "\tmemb("; printHexagonMEMriOperand(MI, 0, O); O << ") ";
int addend = MI->getOperand(2).getImm();
if (addend < 0)
O << "-= " << "#" << -addend << '\n';
else
O << "+= " << "#" << addend << '\n';
} else if (MI->getOpcode() == Hexagon::MEMb_ADDSUBi_MEM_V4) {
//
// Handle memb(Rs+u6:1) [+-]= #U5
//
O << "\tmemb("; printHexagonMEMriOperand(MI, 0, O); O << ") ";
int addend = MI->getOperand(2).getImm();
if (addend < 0)
O << "-= " << "#" << -addend << '\n';
else
O << "+= " << "#" << addend << '\n';
} else if (MI->getOpcode() == Hexagon::CMPbGTri_V4) {
//
// Handle Pd=cmpb.gt(Rs,#s8)
//
O << "\t";
printRegister(MI->getOperand(0), false, O);
O << " = cmpb.gt(";
printRegister(MI->getOperand(1), false, O);
O << ", ";
int val = MI->getOperand(2).getImm() >> 24;
O << "#" << val << ")" << '\n';
} else if (MI->getOpcode() == Hexagon::CMPhEQri_V4) {
//
// Handle Pd=cmph.eq(Rs,#8)
//
O << "\t";
printRegister(MI->getOperand(0), false, O);
O << " = cmph.eq(";
printRegister(MI->getOperand(1), false, O);
O << ", ";
int val = MI->getOperand(2).getImm();
assert((((0 <= val) && (val <= 127)) ||
((65408 <= val) && (val <= 65535))) &&
"Not in correct range!");
if (val >= 65408) val -= 65536;
O << "#" << val << ")" << '\n';
} else if (MI->getOpcode() == Hexagon::CMPhGTri_V4) {
//
// Handle Pd=cmph.gt(Rs,#8)
//
O << "\t";
printRegister(MI->getOperand(0), false, O);
O << " = cmph.gt(";
printRegister(MI->getOperand(1), false, O);
O << ", ";
int val = MI->getOperand(2).getImm() >> 16;
O << "#" << val << ")" << '\n';
} else {
printInstruction(MI, O);
}
// Print a brace for the end of the packet.
if (MFI->isEndPacket(MI) && MI->getOpcode() != Hexagon::ENDLOOP0) {
O << "\n\t}" << '\n';
}
if (AlignCalls && MI->getDesc().isCall()) {
O << "\n\t.falign" << "\n";
}
OutStreamer.EmitRawText(O.str());
return;
}
/// PrintUnmangledNameSafely - Print out the printable characters in the name.
/// Don't print things like \n or \0.
// static void PrintUnmangledNameSafely(const Value *V, raw_ostream &OS) {
// for (const char *Name = V->getNameStart(), *E = Name+V->getNameLen();
// Name != E; ++Name)
// if (isprint(*Name))
// OS << *Name;
// }
void HexagonAsmPrinter::printAddrModeBasePlusOffset(const MachineInstr *MI,
int OpNo, raw_ostream &O) {
const MachineOperand &MO1 = MI->getOperand(OpNo);
const MachineOperand &MO2 = MI->getOperand(OpNo+1);
O << getRegisterName(MO1.getReg())
<< " + #"
<< MO2.getImm();
}
void HexagonAsmPrinter::printGlobalOperand(const MachineInstr *MI, int OpNo,
raw_ostream &O) {
const MachineOperand &MO = MI->getOperand(OpNo);
assert( (MO.getType() == MachineOperand::MO_GlobalAddress) &&
"Expecting global address");
O << *Mang->getSymbol(MO.getGlobal());
if (MO.getOffset() != 0) {
O << " + ";
O << MO.getOffset();
}
}
void HexagonAsmPrinter::printJumpTable(const MachineInstr *MI, int OpNo,
raw_ostream &O) {
const MachineOperand &MO = MI->getOperand(OpNo);
assert( (MO.getType() == MachineOperand::MO_JumpTableIndex) &&
"Expecting jump table index");
// Hexagon_TODO: Do we need name mangling?
O << *GetJTISymbol(MO.getIndex());
}
extern "C" void LLVMInitializeHexagonAsmPrinter() {
RegisterAsmPrinter<HexagonAsmPrinter> X(TheHexagonTarget);
}

View File

@ -0,0 +1,240 @@
//===---- 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.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "hexagon_cfg"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "HexagonTargetMachine.h"
#include "HexagonSubtarget.h"
#include "HexagonMachineFunctionInfo.h"
#include <iostream>
#include "llvm/Support/CommandLine.h"
using namespace llvm;
namespace {
class HexagonCFGOptimizer : public MachineFunctionPass {
private:
HexagonTargetMachine& QTM;
const HexagonSubtarget &QST;
void InvertAndChangeJumpTarget(MachineInstr*, MachineBasicBlock*);
public:
static char ID;
HexagonCFGOptimizer(HexagonTargetMachine& TM) : MachineFunctionPass(ID),
QTM(TM),
QST(*TM.getSubtargetImpl()) {}
const char *getPassName() const {
return "Hexagon CFG Optimizer";
}
bool runOnMachineFunction(MachineFunction &Fn);
};
char HexagonCFGOptimizer::ID = 0;
static bool IsConditionalBranch(int Opc) {
return (Opc == Hexagon::JMP_Pred) || (Opc == Hexagon::JMP_PredNot)
|| (Opc == Hexagon::JMP_PredPt) || (Opc == Hexagon::JMP_PredNotPt);
}
static bool IsUnconditionalJump(int Opc) {
return (Opc == Hexagon::JMP);
}
void
HexagonCFGOptimizer::InvertAndChangeJumpTarget(MachineInstr* MI,
MachineBasicBlock* NewTarget) {
const HexagonInstrInfo *QII = QTM.getInstrInfo();
int NewOpcode = 0;
switch(MI->getOpcode()) {
case Hexagon::JMP_Pred:
NewOpcode = Hexagon::JMP_PredNot;
break;
case Hexagon::JMP_PredNot:
NewOpcode = Hexagon::JMP_Pred;
break;
case Hexagon::JMP_PredPt:
NewOpcode = Hexagon::JMP_PredNotPt;
break;
case Hexagon::JMP_PredNotPt:
NewOpcode = Hexagon::JMP_PredPt;
break;
default:
assert(0 && "Cannot handle this case");
}
MI->setDesc(QII->get(NewOpcode));
MI->getOperand(1).setMBB(NewTarget);
}
bool HexagonCFGOptimizer::runOnMachineFunction(MachineFunction &Fn) {
// 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 = NULL;
MachineBasicBlock* JumpAroundTarget = NULL;
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 = NULL;
if ((MI->getOpcode() == Hexagon::JMP_Pred) ||
(MI->getOpcode() == Hexagon::JMP_PredNot)) {
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())) {
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->size() >= 1 &&
IsUnconditionalJump(JumpAroundTarget->back().getOpcode()) &&
JumpAroundTarget->pred_size() == 1 &&
JumpAroundTarget->succ_size() == 1;
if (case1 || case2) {
InvertAndChangeJumpTarget(MI, UncondTarget);
MBB->removeSuccessor(JumpAroundTarget);
MBB->addSuccessor(UncondTarget);
// Remove the unconditional branch in LayoutSucc.
LayoutSucc->erase(LayoutSucc->begin());
LayoutSucc->removeSuccessor(UncondTarget);
LayoutSucc->addSuccessor(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 (!UncondTarget->canFallThrough()) {
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<unsigned> OrigLiveIn(LayoutSucc->livein_begin(),
LayoutSucc->livein_end());
std::vector<unsigned> NewLiveIn(JumpAroundTarget->livein_begin(),
JumpAroundTarget->livein_end());
for (unsigned i = 0; i < OrigLiveIn.size(); ++i) {
LayoutSucc->removeLiveIn(OrigLiveIn[i]);
}
for (unsigned i = 0; i < NewLiveIn.size(); ++i) {
LayoutSucc->addLiveIn(NewLiveIn[i]);
}
}
}
}
}
}
}
return true;
}
}
//===----------------------------------------------------------------------===//
// Public Constructor Functions
//===----------------------------------------------------------------------===//
FunctionPass *llvm::createHexagonCFGOptimizer(HexagonTargetMachine &TM) {
return new HexagonCFGOptimizer(TM);
}

View File

@ -0,0 +1,35 @@
//===- HexagonCallingConv.td - Calling Conventions Hexagon -*- tablegen -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This describes the calling conventions for the Hexagon architectures.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Return Value Calling Conventions
//===----------------------------------------------------------------------===//
// Hexagon 32-bit C return-value convention.
def RetCC_Hexagon32 : CallingConv<[
CCIfType<[i32], CCAssignToReg<[R0, R1, R2, R3, R4, R5]>>,
CCIfType<[i64], CCAssignToReg<[D0, D1, D2]>>,
// Alternatively, they are assigned to the stack in 4-byte aligned units.
CCAssignToStack<4, 4>
]>;
// Hexagon 32-bit C Calling convention.
def CC_Hexagon32 : CallingConv<[
// All arguments get passed in integer registers if there is space.
CCIfType<[i32, i16, i8], CCAssignToReg<[R0, R1, R2, R3, R4, R5]>>,
CCIfType<[i64], CCAssignToReg<[D0, D1, D2]>>,
// Alternatively, they are assigned to the stack in 4-byte aligned units.
CCAssignToStack<4, 4>
]>;

View File

@ -0,0 +1,207 @@
//===-- llvm/CallingConvLower.cpp - Calling Convention lowering -----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Hexagon_CCState class, used for lowering and
// implementing calling conventions. Adapted from the machine independent
// version of the class (CCState) but this handles calls to varargs functions
//
//===----------------------------------------------------------------------===//
#include "HexagonCallingConvLower.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include "Hexagon.h"
using namespace llvm;
Hexagon_CCState::Hexagon_CCState(CallingConv::ID CC, bool isVarArg,
const TargetMachine &tm,
SmallVector<CCValAssign, 16> &locs,
LLVMContext &c)
: CallingConv(CC), IsVarArg(isVarArg), TM(tm),
TRI(*TM.getRegisterInfo()), Locs(locs), Context(c) {
// No stack is used.
StackOffset = 0;
UsedRegs.resize((TRI.getNumRegs()+31)/32);
}
// 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 Hexagon_CCState::HandleByVal(unsigned ValNo, EVT ValVT,
EVT LocVT, CCValAssign::LocInfo LocInfo,
int MinSize, int MinAlign,
ISD::ArgFlagsTy ArgFlags) {
unsigned Align = ArgFlags.getByValAlign();
unsigned Size = ArgFlags.getByValSize();
if (MinSize > (int)Size)
Size = MinSize;
if (MinAlign > (int)Align)
Align = MinAlign;
unsigned Offset = AllocateStack(Size, Align);
addLoc(CCValAssign::getMem(ValNo, ValVT.getSimpleVT(), Offset,
LocVT.getSimpleVT(), LocInfo));
}
/// MarkAllocated - Mark a register and all of its aliases as allocated.
void Hexagon_CCState::MarkAllocated(unsigned Reg) {
UsedRegs[Reg/32] |= 1 << (Reg&31);
if (const unsigned *RegAliases = TRI.getAliasSet(Reg))
for (; (Reg = *RegAliases); ++RegAliases)
UsedRegs[Reg/32] |= 1 << (Reg&31);
}
/// AnalyzeFormalArguments - Analyze an ISD::FORMAL_ARGUMENTS node,
/// incorporating info about the formals into this state.
void
Hexagon_CCState::AnalyzeFormalArguments(const SmallVectorImpl<ISD::InputArg>
&Ins,
Hexagon_CCAssignFn Fn,
unsigned SretValueInRegs) {
unsigned NumArgs = Ins.size();
unsigned i = 0;
// If the function returns a small struct in registers, skip
// over the first (dummy) argument.
if (SretValueInRegs != 0) {
++i;
}
for (; i != NumArgs; ++i) {
EVT ArgVT = Ins[i].VT;
ISD::ArgFlagsTy ArgFlags = Ins[i].Flags;
if (Fn(i, ArgVT, ArgVT, CCValAssign::Full, ArgFlags, *this, 0, 0, false)) {
dbgs() << "Formal argument #" << i << " has unhandled type "
<< ArgVT.getEVTString() << "\n";
abort();
}
}
}
/// AnalyzeReturn - Analyze the returned values of an ISD::RET node,
/// incorporating info about the result values into this state.
void
Hexagon_CCState::AnalyzeReturn(const SmallVectorImpl<ISD::OutputArg> &Outs,
Hexagon_CCAssignFn Fn,
unsigned SretValueInRegs) {
// For Hexagon, Return small structures in registers.
if (SretValueInRegs != 0) {
if (SretValueInRegs <= 32) {
unsigned Reg = Hexagon::R0;
addLoc(CCValAssign::getReg(0, MVT::i32, Reg, MVT::i32,
CCValAssign::Full));
return;
}
if (SretValueInRegs <= 64) {
unsigned Reg = Hexagon::D0;
addLoc(CCValAssign::getReg(0, MVT::i64, Reg, MVT::i64,
CCValAssign::Full));
return;
}
}
// Determine which register each value should be copied into.
for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
EVT VT = Outs[i].VT;
ISD::ArgFlagsTy ArgFlags = Outs[i].Flags;
if (Fn(i, VT, VT, CCValAssign::Full, ArgFlags, *this, -1, -1, false)){
dbgs() << "Return operand #" << i << " has unhandled type "
<< VT.getEVTString() << "\n";
abort();
}
}
}
/// AnalyzeCallOperands - Analyze an ISD::CALL node, incorporating info
/// about the passed values into this state.
void
Hexagon_CCState::AnalyzeCallOperands(const SmallVectorImpl<ISD::OutputArg>
&Outs,
Hexagon_CCAssignFn Fn,
int NonVarArgsParams,
unsigned SretValueSize) {
unsigned NumOps = Outs.size();
unsigned i = 0;
// If the called function returns a small struct in registers, skip
// the first actual parameter. We do not want to pass a pointer to
// the stack location.
if (SretValueSize != 0) {
++i;
}
for (; i != NumOps; ++i) {
EVT ArgVT = Outs[i].VT;
ISD::ArgFlagsTy ArgFlags = Outs[i].Flags;
if (Fn(i, ArgVT, ArgVT, CCValAssign::Full, ArgFlags, *this,
NonVarArgsParams, i+1, false)) {
dbgs() << "Call operand #" << i << " has unhandled type "
<< ArgVT.getEVTString() << "\n";
abort();
}
}
}
/// AnalyzeCallOperands - Same as above except it takes vectors of types
/// and argument flags.
void
Hexagon_CCState::AnalyzeCallOperands(SmallVectorImpl<EVT> &ArgVTs,
SmallVectorImpl<ISD::ArgFlagsTy> &Flags,
Hexagon_CCAssignFn Fn) {
unsigned NumOps = ArgVTs.size();
for (unsigned i = 0; i != NumOps; ++i) {
EVT ArgVT = ArgVTs[i];
ISD::ArgFlagsTy ArgFlags = Flags[i];
if (Fn(i, ArgVT, ArgVT, CCValAssign::Full, ArgFlags, *this, -1, -1,
false)) {
dbgs() << "Call operand #" << i << " has unhandled type "
<< ArgVT.getEVTString() << "\n";
abort();
}
}
}
/// AnalyzeCallResult - Analyze the return values of an ISD::CALL node,
/// incorporating info about the passed values into this state.
void
Hexagon_CCState::AnalyzeCallResult(const SmallVectorImpl<ISD::InputArg> &Ins,
Hexagon_CCAssignFn Fn,
unsigned SretValueInRegs) {
for (unsigned i = 0, e = Ins.size(); i != e; ++i) {
EVT VT = Ins[i].VT;
ISD::ArgFlagsTy Flags = ISD::ArgFlagsTy();
if (Fn(i, VT, VT, CCValAssign::Full, Flags, *this, -1, -1, false)) {
dbgs() << "Call result #" << i << " has unhandled type "
<< VT.getEVTString() << "\n";
abort();
}
}
}
/// AnalyzeCallResult - Same as above except it's specialized for calls which
/// produce a single value.
void Hexagon_CCState::AnalyzeCallResult(EVT VT, Hexagon_CCAssignFn Fn) {
if (Fn(0, VT, VT, CCValAssign::Full, ISD::ArgFlagsTy(), *this, -1, -1,
false)) {
dbgs() << "Call result has unhandled type "
<< VT.getEVTString() << "\n";
abort();
}
}

View File

@ -0,0 +1,189 @@
//===-- HexagonCallingConvLower.h - Calling Conventions ---------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file declares the Hexagon_CCState class, used for lowering
// and implementing calling conventions. Adapted from the target independent
// version but this handles calls to varargs functions
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_Hexagon_CODEGEN_CALLINGCONVLOWER_H
#define LLVM_Hexagon_CODEGEN_CALLINGCONVLOWER_H
#include "llvm/ADT/SmallVector.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/CodeGen/SelectionDAGNodes.h"
#include "llvm/CodeGen/CallingConvLower.h"
//
// Need to handle varargs.
//
namespace llvm {
class TargetRegisterInfo;
class TargetMachine;
class Hexagon_CCState;
class SDNode;
/// Hexagon_CCAssignFn - This function assigns a location for Val, updating
/// State to reflect the change.
typedef bool Hexagon_CCAssignFn(unsigned ValNo, EVT ValVT,
EVT LocVT, CCValAssign::LocInfo LocInfo,
ISD::ArgFlagsTy ArgFlags, Hexagon_CCState &State,
int NonVarArgsParams,
int CurrentParam,
bool ForceMem);
/// 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 Hexagon_CCState {
CallingConv::ID CallingConv;
bool IsVarArg;
const TargetMachine &TM;
const TargetRegisterInfo &TRI;
SmallVector<CCValAssign, 16> &Locs;
LLVMContext &Context;
unsigned StackOffset;
SmallVector<uint32_t, 16> UsedRegs;
public:
Hexagon_CCState(CallingConv::ID CC, bool isVarArg, const TargetMachine &TM,
SmallVector<CCValAssign, 16> &locs, LLVMContext &c);
void addLoc(const CCValAssign &V) {
Locs.push_back(V);
}
LLVMContext &getContext() const { return Context; }
const TargetMachine &getTarget() const { return TM; }
unsigned getCallingConv() const { return CallingConv; }
bool isVarArg() const { return IsVarArg; }
unsigned getNextStackOffset() const { return StackOffset; }
/// isAllocated - Return true if the specified register (or an alias) is
/// allocated.
bool isAllocated(unsigned Reg) const {
return UsedRegs[Reg/32] & (1 << (Reg&31));
}
/// AnalyzeFormalArguments - Analyze an ISD::FORMAL_ARGUMENTS node,
/// incorporating info about the formals into this state.
void AnalyzeFormalArguments(const SmallVectorImpl<ISD::InputArg> &Ins,
Hexagon_CCAssignFn Fn, unsigned SretValueInRegs);
/// AnalyzeReturn - Analyze the returned values of an ISD::RET node,
/// incorporating info about the result values into this state.
void AnalyzeReturn(const SmallVectorImpl<ISD::OutputArg> &Outs,
Hexagon_CCAssignFn Fn, unsigned SretValueInRegs);
/// AnalyzeCallOperands - Analyze an ISD::CALL node, incorporating info
/// about the passed values into this state.
void AnalyzeCallOperands(const SmallVectorImpl<ISD::OutputArg> &Outs,
Hexagon_CCAssignFn Fn, int NonVarArgsParams,
unsigned SretValueSize);
/// AnalyzeCallOperands - Same as above except it takes vectors of types
/// and argument flags.
void AnalyzeCallOperands(SmallVectorImpl<EVT> &ArgVTs,
SmallVectorImpl<ISD::ArgFlagsTy> &Flags,
Hexagon_CCAssignFn Fn);
/// AnalyzeCallResult - Analyze the return values of an ISD::CALL node,
/// incorporating info about the passed values into this state.
void AnalyzeCallResult(const SmallVectorImpl<ISD::InputArg> &Ins,
Hexagon_CCAssignFn Fn, unsigned SretValueInRegs);
/// AnalyzeCallResult - Same as above except it's specialized for calls which
/// produce a single value.
void AnalyzeCallResult(EVT VT, Hexagon_CCAssignFn Fn);
/// getFirstUnallocated - Return the first unallocated register in the set, or
/// NumRegs if they are all allocated.
unsigned getFirstUnallocated(const unsigned *Regs, unsigned NumRegs) const {
for (unsigned i = 0; i != NumRegs; ++i)
if (!isAllocated(Regs[i]))
return i;
return NumRegs;
}
/// AllocateReg - Attempt to allocate one register. If it is not available,
/// return zero. Otherwise, return the register, marking it and any aliases
/// as allocated.
unsigned AllocateReg(unsigned Reg) {
if (isAllocated(Reg)) return 0;
MarkAllocated(Reg);
return Reg;
}
/// Version of AllocateReg with extra register to be shadowed.
unsigned AllocateReg(unsigned Reg, unsigned ShadowReg) {
if (isAllocated(Reg)) return 0;
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.
unsigned AllocateReg(const unsigned *Regs, unsigned NumRegs) {
unsigned FirstUnalloc = getFirstUnallocated(Regs, NumRegs);
if (FirstUnalloc == NumRegs)
return 0; // Didn't find the reg.
// Mark the register and any aliases as allocated.
unsigned Reg = Regs[FirstUnalloc];
MarkAllocated(Reg);
return Reg;
}
/// Version of AllocateReg with list of registers to be shadowed.
unsigned AllocateReg(const unsigned *Regs, const unsigned *ShadowRegs,
unsigned NumRegs) {
unsigned FirstUnalloc = getFirstUnallocated(Regs, NumRegs);
if (FirstUnalloc == NumRegs)
return 0; // Didn't find the reg.
// Mark the register and any aliases as allocated.
unsigned 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, unsigned Align) {
assert(Align && ((Align-1) & Align) == 0); // Align is power of 2.
StackOffset = ((StackOffset + Align-1) & ~(Align-1));
unsigned Result = StackOffset;
StackOffset += Size;
return Result;
}
// 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, EVT ValVT,
EVT LocVT, CCValAssign::LocInfo LocInfo,
int MinSize, int MinAlign, ISD::ArgFlagsTy ArgFlags);
private:
/// MarkAllocated - Mark a register and all of its aliases as allocated.
void MarkAllocated(unsigned Reg);
};
} // end namespace llvm
#endif

View File

@ -0,0 +1,184 @@
//===--- HexagonExpandPredSpillCode.cpp - Expand Predicate Spill Code ----===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===////
// The Hexagon processor has no instructions that load or store predicate
// registers directly. So, when these registers must be spilled a general
// purpose register must be found and the value copied to/from it from/to
// the predicate register. This code currently does not use the register
// scavenger mechanism available in the allocator. There are two registers
// reserved to allow spilling/restoring predicate registers. One is used to
// hold the predicate value. The other is used when stack frame offsets are
// too large.
//
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/LatencyPriorityQueue.h"
#include "llvm/CodeGen/SchedulerRegistry.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/ScheduleHazardRecognizer.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "HexagonTargetMachine.h"
#include "HexagonSubtarget.h"
#include "HexagonMachineFunctionInfo.h"
#include <map>
#include <iostream>
#include "llvm/Support/CommandLine.h"
using namespace llvm;
namespace {
class HexagonExpandPredSpillCode : public MachineFunctionPass {
HexagonTargetMachine& QTM;
const HexagonSubtarget &QST;
public:
static char ID;
HexagonExpandPredSpillCode(HexagonTargetMachine& TM) :
MachineFunctionPass(ID), QTM(TM), QST(*TM.getSubtargetImpl()) {}
const char *getPassName() const {
return "Hexagon Expand Predicate Spill Code";
}
bool runOnMachineFunction(MachineFunction &Fn);
};
char HexagonExpandPredSpillCode::ID = 0;
bool HexagonExpandPredSpillCode::runOnMachineFunction(MachineFunction &Fn) {
const HexagonInstrInfo *TII = QTM.getInstrInfo();
const HexagonRegisterInfo *RegInfo = QTM.getRegisterInfo();
// 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.
for (MachineBasicBlock::iterator MII = MBB->begin(); MII != MBB->end();
++MII) {
MachineInstr *MI = MII;
int Opc = MI->getOpcode();
if (Opc == Hexagon::STriw_pred) {
// STriw_pred [R30], ofst, SrcReg;
unsigned FP = MI->getOperand(0).getReg();
assert(FP == RegInfo->getFrameRegister() &&
"Not a Frame Pointer, Nor a Spill Slot");
assert(MI->getOperand(1).isImm() && "Not an offset");
int Offset = MI->getOperand(1).getImm();
int SrcReg = MI->getOperand(2).getReg();
assert(Hexagon::PredRegsRegClass.contains(SrcReg) &&
"Not a predicate register");
if (!TII->isValidOffset(Hexagon::STriw, Offset)) {
if (!TII->isValidOffset(Hexagon::ADD_ri, Offset)) {
BuildMI(*MBB, MII, MI->getDebugLoc(),
TII->get(Hexagon::CONST32_Int_Real),
HEXAGON_RESERVED_REG_1).addImm(Offset);
BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::ADD_rr),
HEXAGON_RESERVED_REG_1)
.addReg(FP).addReg(HEXAGON_RESERVED_REG_1);
BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::TFR_RsPd),
HEXAGON_RESERVED_REG_2).addReg(SrcReg);
BuildMI(*MBB, MII, MI->getDebugLoc(),
TII->get(Hexagon::STriw))
.addReg(HEXAGON_RESERVED_REG_1)
.addImm(0).addReg(HEXAGON_RESERVED_REG_2);
} else {
BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::ADD_ri),
HEXAGON_RESERVED_REG_1).addReg(FP).addImm(Offset);
BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::TFR_RsPd),
HEXAGON_RESERVED_REG_2).addReg(SrcReg);
BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::STriw))
.addReg(HEXAGON_RESERVED_REG_1)
.addImm(0)
.addReg(HEXAGON_RESERVED_REG_2);
}
} else {
BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::TFR_RsPd),
HEXAGON_RESERVED_REG_2).addReg(SrcReg);
BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::STriw)).
addReg(FP).addImm(Offset).addReg(HEXAGON_RESERVED_REG_2);
}
MII = MBB->erase(MI);
--MII;
} else if (Opc == Hexagon::LDriw_pred) {
// DstReg = LDriw_pred [R30], ofst.
int DstReg = MI->getOperand(0).getReg();
assert(Hexagon::PredRegsRegClass.contains(DstReg) &&
"Not a predicate register");
unsigned FP = MI->getOperand(1).getReg();
assert(FP == RegInfo->getFrameRegister() &&
"Not a Frame Pointer, Nor a Spill Slot");
assert(MI->getOperand(2).isImm() && "Not an offset");
int Offset = MI->getOperand(2).getImm();
if (!TII->isValidOffset(Hexagon::LDriw, Offset)) {
if (!TII->isValidOffset(Hexagon::ADD_ri, Offset)) {
BuildMI(*MBB, MII, MI->getDebugLoc(),
TII->get(Hexagon::CONST32_Int_Real),
HEXAGON_RESERVED_REG_1).addImm(Offset);
BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::ADD_rr),
HEXAGON_RESERVED_REG_1)
.addReg(FP)
.addReg(HEXAGON_RESERVED_REG_1);
BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::LDriw),
HEXAGON_RESERVED_REG_2)
.addReg(HEXAGON_RESERVED_REG_1)
.addImm(0);
BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::TFR_PdRs),
DstReg).addReg(HEXAGON_RESERVED_REG_2);
} else {
BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::ADD_ri),
HEXAGON_RESERVED_REG_1).addReg(FP).addImm(Offset);
BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::LDriw),
HEXAGON_RESERVED_REG_2)
.addReg(HEXAGON_RESERVED_REG_1)
.addImm(0);
BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::TFR_PdRs),
DstReg).addReg(HEXAGON_RESERVED_REG_2);
}
} else {
BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::LDriw),
HEXAGON_RESERVED_REG_2).addReg(FP).addImm(Offset);
BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::TFR_PdRs),
DstReg).addReg(HEXAGON_RESERVED_REG_2);
}
MII = MBB->erase(MI);
--MII;
}
}
}
return true;
}
}
//===----------------------------------------------------------------------===//
// Public Constructor Functions
//===----------------------------------------------------------------------===//
FunctionPass *llvm::createHexagonExpandPredSpillCode(HexagonTargetMachine &TM) {
return new HexagonExpandPredSpillCode(TM);
}

View File

@ -0,0 +1,333 @@
//==-- HexagonFrameLowering.cpp - Define frame lowering --*- C++ -*-==//
//
// 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 "HexagonInstrInfo.h"
#include "HexagonRegisterInfo.h"
#include "HexagonSubtarget.h"
#include "HexagonTargetMachine.h"
#include "HexagonMachineFunctionInfo.h"
#include "HexagonFrameLowering.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/MC/MachineLocation.h"
#include "llvm/MC/MCAsmInfo.h"
#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Type.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include <iostream>
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/Function.h"
using namespace llvm;
static cl::opt<bool> DisableDeallocRet(
"disable-hexagon-dealloc-ret",
cl::Hidden,
cl::desc("Disable Dealloc Return for Hexagon target"));
/// determineFrameLayout - Determine the size of the frame and maximum call
/// frame size.
void HexagonFrameLowering::determineFrameLayout(MachineFunction &MF) const {
MachineFrameInfo *MFI = MF.getFrameInfo();
// Get the number of bytes to allocate from the FrameInfo.
unsigned FrameSize = MFI->getStackSize();
// Get the alignments provided by the target.
unsigned TargetAlign = MF.getTarget().getFrameLowering()->getStackAlignment();
// Get the maximum call frame size of all the calls.
unsigned maxCallFrameSize = MFI->getMaxCallFrameSize();
// If we have dynamic alloca then maxCallFrameSize needs to be aligned so
// that allocations will be aligned.
if (MFI->hasVarSizedObjects())
maxCallFrameSize = RoundUpToAlignment(maxCallFrameSize, TargetAlign);
// Update maximum call frame size.
MFI->setMaxCallFrameSize(maxCallFrameSize);
// Include call frame size in total.
FrameSize += maxCallFrameSize;
// Make sure the frame is aligned.
FrameSize = RoundUpToAlignment(FrameSize, TargetAlign);
// Update frame info.
MFI->setStackSize(FrameSize);
}
void HexagonFrameLowering::emitPrologue(MachineFunction &MF) const {
MachineBasicBlock &MBB = MF.front();
MachineFrameInfo *MFI = MF.getFrameInfo();
MachineModuleInfo &MMI = MF.getMMI();
MachineBasicBlock::iterator MBBI = MBB.begin();
const HexagonRegisterInfo *QRI =
static_cast<const HexagonRegisterInfo *>(MF.getTarget().getRegisterInfo());
DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
determineFrameLayout(MF);
// Check if frame moves are needed for EH.
bool needsFrameMoves = MMI.hasDebugInfo() ||
!MF.getFunction()->needsUnwindTableEntry();
// Get the number of bytes to allocate from the FrameInfo.
int NumBytes = (int) MFI->getStackSize();
// LLVM expects allocframe not to be the first instruction in the
// basic block.
MachineBasicBlock::iterator InsertPt = MBB.begin();
//
// ALLOCA adjust regs. Iterate over ADJDYNALLOC nodes and change the offset.
//
HexagonMachineFunctionInfo *FuncInfo =
MF.getInfo<HexagonMachineFunctionInfo>();
const std::vector<MachineInstr*>& AdjustRegs =
FuncInfo->getAllocaAdjustInsts();
for (std::vector<MachineInstr*>::const_iterator i = AdjustRegs.begin(),
e = AdjustRegs.end();
i != e; ++i) {
MachineInstr* MI = *i;
assert((MI->getOpcode() == Hexagon::ADJDYNALLOC) &&
"Expected adjust alloca node");
MachineOperand& MO = MI->getOperand(2);
assert(MO.isImm() && "Expected immediate");
MO.setImm(MFI->getMaxCallFrameSize());
}
std::vector<MachineMove> &Moves = MMI.getFrameMoves();
if (needsFrameMoves) {
// Advance CFA. DW_CFA_def_cfa
unsigned FPReg = QRI->getFrameRegister();
unsigned RAReg = QRI->getRARegister();
MachineLocation Dst(MachineLocation::VirtualFP);
MachineLocation Src(FPReg, -8);
Moves.push_back(MachineMove(0, Dst, Src));
// R31 = (R31 - #4)
MachineLocation LRDst(RAReg, -4);
MachineLocation LRSrc(RAReg);
Moves.push_back(MachineMove(0, LRDst, LRSrc));
// R30 = (R30 - #8)
MachineLocation SPDst(FPReg, -8);
MachineLocation SPSrc(FPReg);
Moves.push_back(MachineMove(0, SPDst, SPSrc));
}
//
// Only insert ALLOCFRAME if we need to.
//
if (hasFP(MF)) {
// Check for overflow.
// Hexagon_TODO: Ugh! hardcoding. Is there an API that can be used?
const unsigned int ALLOCFRAME_MAX = 16384;
const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo();
if (NumBytes >= ALLOCFRAME_MAX) {
// Emit allocframe(#0).
BuildMI(MBB, InsertPt, dl, TII.get(Hexagon::ALLOCFRAME)).addImm(0);
// Subtract offset from frame pointer.
BuildMI(MBB, InsertPt, dl, TII.get(Hexagon::CONST32_Int_Real),
HEXAGON_RESERVED_REG_1).addImm(NumBytes);
BuildMI(MBB, InsertPt, dl, TII.get(Hexagon::SUB_rr),
QRI->getStackRegister()).
addReg(QRI->getStackRegister()).
addReg(HEXAGON_RESERVED_REG_1);
} else {
BuildMI(MBB, InsertPt, dl, TII.get(Hexagon::ALLOCFRAME)).addImm(NumBytes);
}
}
}
// Returns true if MBB has a machine instructions that indicates a tail call
// in the block.
bool HexagonFrameLowering::hasTailCall(MachineBasicBlock &MBB) const {
MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
unsigned RetOpcode = MBBI->getOpcode();
return RetOpcode == Hexagon::TCRETURNtg || RetOpcode == Hexagon::TCRETURNtext;}
void HexagonFrameLowering::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {
MachineBasicBlock::iterator MBBI = prior(MBB.end());
DebugLoc dl = MBBI->getDebugLoc();
//
// Only insert deallocframe if we need to.
//
if (hasFP(MF)) {
MachineBasicBlock::iterator MBBI = prior(MBB.end());
MachineBasicBlock::iterator MBBI_end = MBB.end();
//
// For Hexagon, we don't need the frame size.
//
MachineFrameInfo *MFI = MF.getFrameInfo();
int NumBytes = (int) MFI->getStackSize();
const TargetInstrInfo &TII = *MF.getTarget().getInstrInfo();
// Replace 'jumpr r31' instruction with dealloc_return for V4 and higher
// versions.
if (STI.hasV4TOps() && MBBI->getOpcode() == Hexagon::JMPR
&& !DisableDeallocRet) {
// Remove jumpr node.
MBB.erase(MBBI);
// Add dealloc_return.
BuildMI(MBB, MBBI_end, dl, TII.get(Hexagon::DEALLOC_RET_V4))
.addImm(NumBytes);
} else { // Add deallocframe for V2 and V3.
BuildMI(MBB, MBBI, dl, TII.get(Hexagon::DEALLOCFRAME)).addImm(NumBytes);
}
}
}
bool HexagonFrameLowering::hasFP(const MachineFunction &MF) const {
const MachineFrameInfo *MFI = MF.getFrameInfo();
const HexagonMachineFunctionInfo *FuncInfo =
MF.getInfo<HexagonMachineFunctionInfo>();
return (MFI->hasCalls() || (MFI->getStackSize() > 0) ||
FuncInfo->hasClobberLR() );
}
bool
HexagonFrameLowering::spillCalleeSavedRegisters(
MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
const std::vector<CalleeSavedInfo> &CSI,
const TargetRegisterInfo *TRI) const {
MachineFunction *MF = MBB.getParent();
const TargetInstrInfo &TII = *MF->getTarget().getInstrInfo();
if (CSI.empty()) {
return false;
}
// We can only schedule double loads if we spill contiguous callee-saved regs
// For instance, we cannot scheduled double-word loads if we spill r24,
// r26, and r27.
// Hexagon_TODO: We can try to double-word align odd registers for -O2 and
// above.
bool ContiguousRegs = true;
for (unsigned i = 0; i < CSI.size(); ++i) {
unsigned Reg = CSI[i].getReg();
//
// Check if we can use a double-word store.
//
const unsigned* SuperReg = TRI->getSuperRegisters(Reg);
// Assume that there is exactly one superreg.
assert(SuperReg[0] && !SuperReg[1] && "Expected exactly one superreg");
bool CanUseDblStore = false;
const TargetRegisterClass* SuperRegClass = 0;
if (ContiguousRegs && (i < CSI.size()-1)) {
const unsigned* SuperRegNext = TRI->getSuperRegisters(CSI[i+1].getReg());
assert(SuperRegNext[0] && !SuperRegNext[1] &&
"Expected exactly one superreg");
SuperRegClass = TRI->getMinimalPhysRegClass(SuperReg[0]);
CanUseDblStore = (SuperRegNext[0] == SuperReg[0]);
}
if (CanUseDblStore) {
TII.storeRegToStackSlot(MBB, MI, SuperReg[0], true,
CSI[i+1].getFrameIdx(), SuperRegClass, TRI);
MBB.addLiveIn(SuperReg[0]);
++i;
} else {
// Cannot use a double-word store.
ContiguousRegs = false;
const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
TII.storeRegToStackSlot(MBB, MI, Reg, true, CSI[i].getFrameIdx(), RC,
TRI);
MBB.addLiveIn(Reg);
}
}
return true;
}
bool HexagonFrameLowering::restoreCalleeSavedRegisters(
MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
const std::vector<CalleeSavedInfo> &CSI,
const TargetRegisterInfo *TRI) const {
MachineFunction *MF = MBB.getParent();
const TargetInstrInfo &TII = *MF->getTarget().getInstrInfo();
if (CSI.empty()) {
return false;
}
// We can only schedule double loads if we spill contiguous callee-saved regs
// For instance, we cannot scheduled double-word loads if we spill r24,
// r26, and r27.
// Hexagon_TODO: We can try to double-word align odd registers for -O2 and
// above.
bool ContiguousRegs = true;
for (unsigned i = 0; i < CSI.size(); ++i) {
unsigned Reg = CSI[i].getReg();
//
// Check if we can use a double-word load.
//
const unsigned* SuperReg = TRI->getSuperRegisters(Reg);
const TargetRegisterClass* SuperRegClass = 0;
// Assume that there is exactly one superreg.
assert(SuperReg[0] && !SuperReg[1] && "Expected exactly one superreg");
bool CanUseDblLoad = false;
if (ContiguousRegs && (i < CSI.size()-1)) {
const unsigned* SuperRegNext = TRI->getSuperRegisters(CSI[i+1].getReg());
assert(SuperRegNext[0] && !SuperRegNext[1] &&
"Expected exactly one superreg");
SuperRegClass = TRI->getMinimalPhysRegClass(SuperReg[0]);
CanUseDblLoad = (SuperRegNext[0] == SuperReg[0]);
}
if (CanUseDblLoad) {
TII.loadRegFromStackSlot(MBB, MI, SuperReg[0], CSI[i+1].getFrameIdx(),
SuperRegClass, TRI);
MBB.addLiveIn(SuperReg[0]);
++i;
} else {
// Cannot use a double-word load.
ContiguousRegs = false;
const TargetRegisterClass *RC = TRI->getMinimalPhysRegClass(Reg);
TII.loadRegFromStackSlot(MBB, MI, Reg, CSI[i].getFrameIdx(), RC, TRI);
MBB.addLiveIn(Reg);
}
}
return true;
}
int HexagonFrameLowering::getFrameIndexOffset(const MachineFunction &MF,
int FI) const {
return MF.getFrameInfo()->getObjectOffset(FI);
}

View File

@ -0,0 +1,50 @@
//=- HexagonFrameLowering.h - Define frame lowering for Hexagon --*- C++ -*--=//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef HEXAGON_FRAMEINFO_H
#define HEXAGON_FRAMEINFO_H
#include "Hexagon.h"
#include "HexagonSubtarget.h"
#include "llvm/Target/TargetFrameLowering.h"
namespace llvm {
class HexagonFrameLowering : public TargetFrameLowering {
private:
const HexagonSubtarget &STI;
void determineFrameLayout(MachineFunction &MF) const;
public:
explicit HexagonFrameLowering(const HexagonSubtarget &sti)
: TargetFrameLowering(StackGrowsDown, 8, 0), STI(sti) {
}
/// emitProlog/emitEpilog - These methods insert prolog and epilog code into
/// the function.
void emitPrologue(MachineFunction &MF) const;
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const;
virtual bool
spillCalleeSavedRegisters(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
const std::vector<CalleeSavedInfo> &CSI,
const TargetRegisterInfo *TRI) const;
virtual bool
restoreCalleeSavedRegisters(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MI,
const std::vector<CalleeSavedInfo> &CSI,
const TargetRegisterInfo *TRI) const;
int getFrameIndexOffset(const MachineFunction &MF, int FI) const;
bool hasFP(const MachineFunction &MF) const;
bool hasTailCall(MachineBasicBlock &MBB) const;
};
} // End llvm namespace
#endif

View File

@ -0,0 +1,644 @@
//===-- HexagonHardwareLoops.cpp - Identify and generate hardware loops ---===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass identifies loops where we can generate the Hexagon hardware
// loop instruction. The hardware loop can perform loop branches with a
// zero-cycle overhead.
//
// The pattern that defines the induction variable can changed depending on
// prior optimizations. For example, the IndVarSimplify phase run by 'opt'
// normalizes induction variables, and the Loop Strength Reduction pass
// run by 'llc' may also make changes to the induction variable.
// The pattern detected by this phase is due to running Strength Reduction.
//
// Criteria for hardware loops:
// - Countable loops (w/ ind. var for a trip count)
// - Assumes loops are normalized by IndVarSimplify
// - Try inner-most loops first
// - No nested hardware loops.
// - No function calls in loops.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "hwloops"
#include "llvm/Constants.h"
#include "llvm/PassSupport.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetInstrInfo.h"
#include <algorithm>
#include "Hexagon.h"
#include "HexagonTargetMachine.h"
using namespace llvm;
STATISTIC(NumHWLoops, "Number of loops converted to hardware loops");
namespace {
class CountValue;
struct HexagonHardwareLoops : public MachineFunctionPass {
MachineLoopInfo *MLI;
MachineRegisterInfo *MRI;
const TargetInstrInfo *TII;
public:
static char ID; // Pass identification, replacement for typeid
HexagonHardwareLoops() : MachineFunctionPass(ID) {}
virtual bool runOnMachineFunction(MachineFunction &MF);
const char *getPassName() const { return "Hexagon Hardware Loops"; }
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesCFG();
AU.addRequired<MachineDominatorTree>();
AU.addPreserved<MachineDominatorTree>();
AU.addRequired<MachineLoopInfo>();
AU.addPreserved<MachineLoopInfo>();
MachineFunctionPass::getAnalysisUsage(AU);
}
private:
/// getCanonicalInductionVariable - Check to see if the loop has a canonical
/// induction variable.
/// Should be defined in MachineLoop. Based upon version in class Loop.
const MachineInstr *getCanonicalInductionVariable(MachineLoop *L) const;
/// getTripCount - Return a loop-invariant LLVM register indicating the
/// number of times the loop will be executed. If the trip-count cannot
/// be determined, this return null.
CountValue *getTripCount(MachineLoop *L) const;
/// isInductionOperation - Return true if the instruction matches the
/// pattern for an opertion that defines an induction variable.
bool isInductionOperation(const MachineInstr *MI, unsigned IVReg) const;
/// isInvalidOperation - Return true if the instruction is not valid within
/// a hardware loop.
bool isInvalidLoopOperation(const MachineInstr *MI) const;
/// containsInavlidInstruction - Return true if the loop contains an
/// instruction that inhibits using the hardware loop.
bool containsInvalidInstruction(MachineLoop *L) const;
/// converToHardwareLoop - Given a loop, check if we can convert it to a
/// hardware loop. If so, then perform the conversion and return true.
bool convertToHardwareLoop(MachineLoop *L);
};
char HexagonHardwareLoops::ID = 0;
// CountValue class - Abstraction for a trip count of a loop. A
// smaller vesrsion of the MachineOperand class without the concerns
// of changing the operand representation.
class CountValue {
public:
enum CountValueType {
CV_Register,
CV_Immediate
};
private:
CountValueType Kind;
union Values {
unsigned RegNum;
int64_t ImmVal;
Values(unsigned r) : RegNum(r) {}
Values(int64_t i) : ImmVal(i) {}
} Contents;
bool isNegative;
public:
CountValue(unsigned r, bool neg) : Kind(CV_Register), Contents(r),
isNegative(neg) {}
explicit CountValue(int64_t i) : Kind(CV_Immediate), Contents(i),
isNegative(i < 0) {}
CountValueType getType() const { return Kind; }
bool isReg() const { return Kind == CV_Register; }
bool isImm() const { return Kind == CV_Immediate; }
bool isNeg() const { return isNegative; }
unsigned getReg() const {
assert(isReg() && "Wrong CountValue accessor");
return Contents.RegNum;
}
void setReg(unsigned Val) {
Contents.RegNum = Val;
}
int64_t getImm() const {
assert(isImm() && "Wrong CountValue accessor");
if (isNegative) {
return -Contents.ImmVal;
}
return Contents.ImmVal;
}
void setImm(int64_t Val) {
Contents.ImmVal = Val;
}
void print(raw_ostream &OS, const TargetMachine *TM = 0) const {
if (isReg()) { OS << PrintReg(getReg()); }
if (isImm()) { OS << getImm(); }
}
};
struct HexagonFixupHwLoops : public MachineFunctionPass {
public:
static char ID; // Pass identification, replacement for typeid.
HexagonFixupHwLoops() : MachineFunctionPass(ID) {}
virtual bool runOnMachineFunction(MachineFunction &MF);
const char *getPassName() const { return "Hexagon Hardware Loop Fixup"; }
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesCFG();
MachineFunctionPass::getAnalysisUsage(AU);
}
private:
/// Maximum distance between the loop instr and the basic block.
/// Just an estimate.
static const unsigned MAX_LOOP_DISTANCE = 200;
/// fixupLoopInstrs - Check the offset between each loop instruction and
/// the loop basic block to determine if we can use the LOOP instruction
/// or if we need to set the LC/SA registers explicitly.
bool fixupLoopInstrs(MachineFunction &MF);
/// convertLoopInstr - Add the instruction to set the LC and SA registers
/// explicitly.
void convertLoopInstr(MachineFunction &MF,
MachineBasicBlock::iterator &MII,
RegScavenger &RS);
};
char HexagonFixupHwLoops::ID = 0;
} // end anonymous namespace
/// isHardwareLoop - Returns true if the instruction is a hardware loop
/// instruction.
static bool isHardwareLoop(const MachineInstr *MI) {
return MI->getOpcode() == Hexagon::LOOP0_r ||
MI->getOpcode() == Hexagon::LOOP0_i;
}
/// isCompareEquals - Returns true if the instruction is a compare equals
/// instruction with an immediate operand.
static bool isCompareEqualsImm(const MachineInstr *MI) {
return MI->getOpcode() == Hexagon::CMPEQri;
}
/// createHexagonHardwareLoops - Factory for creating
/// the hardware loop phase.
FunctionPass *llvm::createHexagonHardwareLoops() {
return new HexagonHardwareLoops();
}
bool HexagonHardwareLoops::runOnMachineFunction(MachineFunction &MF) {
DEBUG(dbgs() << "********* Hexagon Hardware Loops *********\n");
bool Changed = false;
// get the loop information
MLI = &getAnalysis<MachineLoopInfo>();
// get the register information
MRI = &MF.getRegInfo();
// the target specific instructio info.
TII = MF.getTarget().getInstrInfo();
for (MachineLoopInfo::iterator I = MLI->begin(), E = MLI->end();
I != E; ++I) {
MachineLoop *L = *I;
if (!L->getParentLoop()) {
Changed |= convertToHardwareLoop(L);
}
}
return Changed;
}
/// getCanonicalInductionVariable - Check to see if the loop has a canonical
/// induction variable. We check for a simple recurrence pattern - an
/// integer recurrence that decrements by one each time through the loop and
/// ends at zero. If so, return the phi node that corresponds to it.
///
/// Based upon the similar code in LoopInfo except this code is specific to
/// the machine.
/// This method assumes that the IndVarSimplify pass has been run by 'opt'.
///
const MachineInstr
*HexagonHardwareLoops::getCanonicalInductionVariable(MachineLoop *L) const {
MachineBasicBlock *TopMBB = L->getTopBlock();
MachineBasicBlock::pred_iterator PI = TopMBB->pred_begin();
assert(PI != TopMBB->pred_end() &&
"Loop must have more than one incoming edge!");
MachineBasicBlock *Backedge = *PI++;
if (PI == TopMBB->pred_end()) return 0; // dead loop
MachineBasicBlock *Incoming = *PI++;
if (PI != TopMBB->pred_end()) return 0; // multiple backedges?
// make sure there is one incoming and one backedge and determine which
// is which.
if (L->contains(Incoming)) {
if (L->contains(Backedge))
return 0;
std::swap(Incoming, Backedge);
} else if (!L->contains(Backedge))
return 0;
// Loop over all of the PHI nodes, looking for a canonical induction variable:
// - The PHI node is "reg1 = PHI reg2, BB1, reg3, BB2".
// - The recurrence comes from the backedge.
// - the definition is an induction operatio.n
for (MachineBasicBlock::iterator I = TopMBB->begin(), E = TopMBB->end();
I != E && I->isPHI(); ++I) {
const MachineInstr *MPhi = &*I;
unsigned DefReg = MPhi->getOperand(0).getReg();
for (unsigned i = 1; i != MPhi->getNumOperands(); i += 2) {
// Check each operand for the value from the backedge.
MachineBasicBlock *MBB = MPhi->getOperand(i+1).getMBB();
if (L->contains(MBB)) { // operands comes from the backedge
// Check if the definition is an induction operation.
const MachineInstr *DI = MRI->getVRegDef(MPhi->getOperand(i).getReg());
if (isInductionOperation(DI, DefReg)) {
return MPhi;
}
}
}
}
return 0;
}
/// getTripCount - Return a loop-invariant LLVM value indicating the
/// number of times the loop will be executed. The trip count can
/// be either a register or a constant value. If the trip-count
/// cannot be determined, this returns null.
///
/// We find the trip count from the phi instruction that defines the
/// induction variable. We follow the links to the CMP instruction
/// to get the trip count.
///
/// Based upon getTripCount in LoopInfo.
///
CountValue *HexagonHardwareLoops::getTripCount(MachineLoop *L) const {
// Check that the loop has a induction variable.
const MachineInstr *IV_Inst = getCanonicalInductionVariable(L);
if (IV_Inst == 0) return 0;
// Canonical loops will end with a 'cmpeq_ri IV, Imm',
// if Imm is 0, get the count from the PHI opnd
// if Imm is -M, than M is the count
// Otherwise, Imm is the count
const MachineOperand *IV_Opnd;
const MachineOperand *InitialValue;
if (!L->contains(IV_Inst->getOperand(2).getMBB())) {
InitialValue = &IV_Inst->getOperand(1);
IV_Opnd = &IV_Inst->getOperand(3);
} else {
InitialValue = &IV_Inst->getOperand(3);
IV_Opnd = &IV_Inst->getOperand(1);
}
// Look for the cmp instruction to determine if we
// can get a useful trip count. The trip count can
// be either a register or an immediate. The location
// of the value depends upon the type (reg or imm).
while ((IV_Opnd = IV_Opnd->getNextOperandForReg())) {
const MachineInstr *MI = IV_Opnd->getParent();
if (L->contains(MI) && isCompareEqualsImm(MI)) {
const MachineOperand &MO = MI->getOperand(2);
assert(MO.isImm() && "IV Cmp Operand should be 0");
int64_t ImmVal = MO.getImm();
const MachineInstr *IV_DefInstr = MRI->getVRegDef(IV_Opnd->getReg());
assert(L->contains(IV_DefInstr->getParent()) &&
"IV definition should occurs in loop");
int64_t iv_value = IV_DefInstr->getOperand(2).getImm();
if (ImmVal == 0) {
// Make sure the induction variable changes by one on each iteration.
if (iv_value != 1 && iv_value != -1) {
return 0;
}
return new CountValue(InitialValue->getReg(), iv_value > 0);
} else {
assert(InitialValue->isReg() && "Expecting register for init value");
const MachineInstr *DefInstr = MRI->getVRegDef(InitialValue->getReg());
if (DefInstr && DefInstr->getOpcode() == Hexagon::TFRI) {
int64_t count = ImmVal - DefInstr->getOperand(1).getImm();
if ((count % iv_value) != 0) {
return 0;
}
return new CountValue(count/iv_value);
}
}
}
}
return 0;
}
/// isInductionOperation - return true if the operation is matches the
/// pattern that defines an induction variable:
/// add iv, c
///
bool
HexagonHardwareLoops::isInductionOperation(const MachineInstr *MI,
unsigned IVReg) const {
return (MI->getOpcode() ==
Hexagon::ADD_ri && MI->getOperand(1).getReg() == IVReg);
}
/// isInvalidOperation - Return true if the operation is invalid within
/// hardware loop.
bool
HexagonHardwareLoops::isInvalidLoopOperation(const MachineInstr *MI) const {
// call is not allowed because the callee may use a hardware loop
if (MI->getDesc().isCall()) {
return true;
}
// do not allow nested hardware loops
if (isHardwareLoop(MI)) {
return true;
}
// check if the instruction defines a hardware loop register
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
const MachineOperand &MO = MI->getOperand(i);
if (MO.isReg() && MO.isDef() &&
(MO.getReg() == Hexagon::LC0 || MO.getReg() == Hexagon::LC1 ||
MO.getReg() == Hexagon::SA0 || MO.getReg() == Hexagon::SA0)) {
return true;
}
}
return false;
}
/// containsInvalidInstruction - Return true if the loop contains
/// an instruction that inhibits the use of the hardware loop function.
///
bool HexagonHardwareLoops::containsInvalidInstruction(MachineLoop *L) const {
const std::vector<MachineBasicBlock*> Blocks = L->getBlocks();
for (unsigned i = 0, e = Blocks.size(); i != e; ++i) {
MachineBasicBlock *MBB = Blocks[i];
for (MachineBasicBlock::iterator
MII = MBB->begin(), E = MBB->end(); MII != E; ++MII) {
const MachineInstr *MI = &*MII;
if (isInvalidLoopOperation(MI)) {
return true;
}
}
}
return false;
}
/// converToHardwareLoop - check if the loop is a candidate for
/// converting to a hardware loop. If so, then perform the
/// transformation.
///
/// This function works on innermost loops first. A loop can
/// be converted if it is a counting loop; either a register
/// value or an immediate.
///
/// The code makes several assumptions about the representation
/// of the loop in llvm.
bool HexagonHardwareLoops::convertToHardwareLoop(MachineLoop *L) {
bool Changed = false;
// Process nested loops first.
for (MachineLoop::iterator I = L->begin(), E = L->end(); I != E; ++I) {
Changed |= convertToHardwareLoop(*I);
}
// If a nested loop has been converted, then we can't convert this loop.
if (Changed) {
return Changed;
}
// Are we able to determine the trip count for the loop?
CountValue *TripCount = getTripCount(L);
if (TripCount == 0) {
return false;
}
// Does the loop contain any invalid instructions?
if (containsInvalidInstruction(L)) {
return false;
}
MachineBasicBlock *Preheader = L->getLoopPreheader();
// No preheader means there's not place for the loop instr.
if (Preheader == 0) {
return false;
}
MachineBasicBlock::iterator InsertPos = Preheader->getFirstTerminator();
MachineBasicBlock *LastMBB = L->getExitingBlock();
// Don't generate hw loop if the loop has more than one exit.
if (LastMBB == 0) {
return false;
}
MachineBasicBlock::iterator LastI = LastMBB->getFirstTerminator();
// Determine the loop start.
MachineBasicBlock *LoopStart = L->getTopBlock();
if (L->getLoopLatch() != LastMBB) {
// When the exit and latch are not the same, use the latch block as the
// start.
// The loop start address is used only after the 1st iteration, and the loop
// latch may contains instrs. that need to be executed after the 1st iter.
LoopStart = L->getLoopLatch();
// Make sure the latch is a successor of the exit, otherwise it won't work.
if (!LastMBB->isSuccessor(LoopStart)) {
return false;
}
}
// Convert the loop to a hardware loop
DEBUG(dbgs() << "Change to hardware loop at "; L->dump());
if (TripCount->isReg()) {
// Create a copy of the loop count register.
MachineFunction *MF = LastMBB->getParent();
const TargetRegisterClass *RC =
MF->getRegInfo().getRegClass(TripCount->getReg());
unsigned CountReg = MF->getRegInfo().createVirtualRegister(RC);
BuildMI(*Preheader, InsertPos, InsertPos->getDebugLoc(),
TII->get(TargetOpcode::COPY), CountReg).addReg(TripCount->getReg());
if (TripCount->isNeg()) {
unsigned CountReg1 = CountReg;
CountReg = MF->getRegInfo().createVirtualRegister(RC);
BuildMI(*Preheader, InsertPos, InsertPos->getDebugLoc(),
TII->get(Hexagon::NEG), CountReg).addReg(CountReg1);
}
// Add the Loop instruction to the begining of the loop.
BuildMI(*Preheader, InsertPos, InsertPos->getDebugLoc(),
TII->get(Hexagon::LOOP0_r)).addMBB(LoopStart).addReg(CountReg);
} else {
assert(TripCount->isImm() && "Expecting immedate vaule for trip count");
// Add the Loop immediate instruction to the beginning of the loop.
int64_t CountImm = TripCount->getImm();
BuildMI(*Preheader, InsertPos, InsertPos->getDebugLoc(),
TII->get(Hexagon::LOOP0_i)).addMBB(LoopStart).addImm(CountImm);
}
// Make sure the loop start always has a reference in the CFG. We need to
// create a BlockAddress operand to get this mechanism to work both the
// MachineBasicBlock and BasicBlock objects need the flag set.
LoopStart->setHasAddressTaken();
// This line is needed to set the hasAddressTaken flag on the BasicBlock
// object
BlockAddress::get(const_cast<BasicBlock *>(LoopStart->getBasicBlock()));
// Replace the loop branch with an endloop instruction.
DebugLoc dl = LastI->getDebugLoc();
BuildMI(*LastMBB, LastI, dl, TII->get(Hexagon::ENDLOOP0)).addMBB(LoopStart);
// The loop ends with either:
// - a conditional branch followed by an unconditional branch, or
// - a conditional branch to the loop start.
if (LastI->getOpcode() == Hexagon::JMP_Pred ||
LastI->getOpcode() == Hexagon::JMP_PredNot) {
// delete one and change/add an uncond. branch to out of the loop
MachineBasicBlock *BranchTarget = LastI->getOperand(1).getMBB();
LastI = LastMBB->erase(LastI);
if (!L->contains(BranchTarget)) {
if (LastI != LastMBB->end()) {
TII->RemoveBranch(*LastMBB);
}
SmallVector<MachineOperand, 0> Cond;
TII->InsertBranch(*LastMBB, BranchTarget, 0, Cond, dl);
}
} else {
// Conditional branch to loop start; just delete it.
LastMBB->erase(LastI);
}
delete TripCount;
++NumHWLoops;
return true;
}
/// createHexagonFixupHwLoops - Factory for creating the hardware loop
/// phase.
FunctionPass *llvm::createHexagonFixupHwLoops() {
return new HexagonFixupHwLoops();
}
bool HexagonFixupHwLoops::runOnMachineFunction(MachineFunction &MF) {
DEBUG(dbgs() << "****** Hexagon Hardware Loop Fixup ******\n");
bool Changed = fixupLoopInstrs(MF);
return Changed;
}
/// fixupLoopInsts - For Hexagon, if the loop label is to far from the
/// loop instruction then we need to set the LC0 and SA0 registers
/// explicitly instead of using LOOP(start,count). This function
/// checks the distance, and generates register assignments if needed.
///
/// This function makes two passes over the basic blocks. The first
/// pass computes the offset of the basic block from the start.
/// The second pass checks all the loop instructions.
bool HexagonFixupHwLoops::fixupLoopInstrs(MachineFunction &MF) {
// Offset of the current instruction from the start.
unsigned InstOffset = 0;
// Map for each basic block to it's first instruction.
DenseMap<MachineBasicBlock*, unsigned> BlockToInstOffset;
// First pass - compute the offset of each basic block.
for (MachineFunction::iterator MBB = MF.begin(), MBBe = MF.end();
MBB != MBBe; ++MBB) {
BlockToInstOffset[MBB] = InstOffset;
InstOffset += (MBB->size() * 4);
}
// Second pass - check each loop instruction to see if it needs to
// be converted.
InstOffset = 0;
bool Changed = false;
RegScavenger RS;
// Loop over all the basic blocks.
for (MachineFunction::iterator MBB = MF.begin(), MBBe = MF.end();
MBB != MBBe; ++MBB) {
InstOffset = BlockToInstOffset[MBB];
RS.enterBasicBlock(MBB);
// Loop over all the instructions.
MachineBasicBlock::iterator MIE = MBB->end();
MachineBasicBlock::iterator MII = MBB->begin();
while (MII != MIE) {
if (isHardwareLoop(MII)) {
RS.forward(MII);
assert(MII->getOperand(0).isMBB() &&
"Expect a basic block as loop operand");
int diff = InstOffset - BlockToInstOffset[MII->getOperand(0).getMBB()];
diff = (diff > 0 ? diff : -diff);
if ((unsigned)diff > MAX_LOOP_DISTANCE) {
// Convert to explicity setting LC0 and SA0.
convertLoopInstr(MF, MII, RS);
MII = MBB->erase(MII);
Changed = true;
} else {
++MII;
}
} else {
++MII;
}
InstOffset += 4;
}
}
return Changed;
}
/// convertLoopInstr - convert a loop instruction to a sequence of instructions
/// that set the lc and sa register explicitly.
void HexagonFixupHwLoops::convertLoopInstr(MachineFunction &MF,
MachineBasicBlock::iterator &MII,
RegScavenger &RS) {
const TargetInstrInfo *TII = MF.getTarget().getInstrInfo();
MachineBasicBlock *MBB = MII->getParent();
DebugLoc DL = MII->getDebugLoc();
unsigned Scratch = RS.scavengeRegister(Hexagon::IntRegsRegisterClass, MII, 0);
// First, set the LC0 with the trip count.
if (MII->getOperand(1).isReg()) {
// Trip count is a register
BuildMI(*MBB, MII, DL, TII->get(Hexagon::TFCR), Hexagon::LC0)
.addReg(MII->getOperand(1).getReg());
} else {
// Trip count is an immediate.
BuildMI(*MBB, MII, DL, TII->get(Hexagon::TFRI), Scratch)
.addImm(MII->getOperand(1).getImm());
BuildMI(*MBB, MII, DL, TII->get(Hexagon::TFCR), Hexagon::LC0)
.addReg(Scratch);
}
// Then, set the SA0 with the loop start address.
BuildMI(*MBB, MII, DL, TII->get(Hexagon::CONST32_Label), Scratch)
.addMBB(MII->getOperand(0).getMBB());
BuildMI(*MBB, MII, DL, TII->get(Hexagon::TFCR), Hexagon::SA0).addReg(Scratch);
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,162 @@
//==-- HexagonISelLowering.h - Hexagon DAG Lowering Interface ----*- C++ -*-==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the interfaces that Hexagon uses to lower LLVM code into a
// selection DAG.
//
//===----------------------------------------------------------------------===//
#ifndef Hexagon_ISELLOWERING_H
#define Hexagon_ISELLOWERING_H
#include "llvm/Target/TargetLowering.h"
#include "llvm/CallingConv.h"
#include "llvm/CodeGen/CallingConvLower.h"
#include "Hexagon.h"
namespace llvm {
namespace HexagonISD {
enum {
FIRST_NUMBER = ISD::BUILTIN_OP_END,
CONST32,
CONST32_GP, // For marking data present in GP.
SETCC,
ADJDYNALLOC,
ARGEXTEND,
CMPICC, // Compare two GPR operands, set icc.
CMPFCC, // Compare two FP operands, set fcc.
BRICC, // Branch to dest on icc condition
BRFCC, // Branch to dest on fcc condition
SELECT_ICC, // Select between two values using the current ICC flags.
SELECT_FCC, // Select between two values using the current FCC flags.
Hi, Lo, // Hi/Lo operations, typically on a global address.
FTOI, // FP to Int within a FP register.
ITOF, // Int to FP within a FP register.
CALL, // A call instruction.
RET_FLAG, // Return with a flag operand.
BR_JT, // Jump table.
BARRIER, // Memory barrier.
WrapperJT,
TC_RETURN
};
}
class HexagonTargetLowering : public TargetLowering {
int VarArgsFrameOffset; // Frame offset to start of varargs area.
bool CanReturnSmallStruct(const Function* CalleeFn,
unsigned& RetSize) const;
public:
HexagonTargetMachine &TM;
explicit HexagonTargetLowering(HexagonTargetMachine &targetmachine);
/// IsEligibleForTailCallOptimization - Check whether the call is eligible
/// for tail call optimization. Targets which want to do tail call
/// optimization should implement this function.
bool
IsEligibleForTailCallOptimization(SDValue Callee,
CallingConv::ID CalleeCC,
bool isVarArg,
bool isCalleeStructRet,
bool isCallerStructRet,
const
SmallVectorImpl<ISD::OutputArg> &Outs,
const SmallVectorImpl<SDValue> &OutVals,
const SmallVectorImpl<ISD::InputArg> &Ins,
SelectionDAG& DAG) const;
virtual bool isTruncateFree(Type *Ty1, Type *Ty2) const;
virtual bool isTruncateFree(EVT VT1, EVT VT2) const;
virtual SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const;
virtual const char *getTargetNodeName(unsigned Opcode) const;
SDValue LowerBR_JT(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerINLINEASM(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerEH_LABEL(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerFormalArguments(SDValue Chain,
CallingConv::ID CallConv, bool isVarArg,
const SmallVectorImpl<ISD::InputArg> &Ins,
DebugLoc dl, SelectionDAG &DAG,
SmallVectorImpl<SDValue> &InVals) const;
SDValue LowerGLOBALADDRESS(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerCall(SDValue Chain, SDValue Callee,
CallingConv::ID CallConv, bool isVarArg,
bool &isTailCall,
const SmallVectorImpl<ISD::OutputArg> &Outs,
const SmallVectorImpl<SDValue> &OutVals,
const SmallVectorImpl<ISD::InputArg> &Ins,
DebugLoc dl, SelectionDAG &DAG,
SmallVectorImpl<SDValue> &InVals) const;
SDValue LowerCallResult(SDValue Chain, SDValue InFlag,
CallingConv::ID CallConv, bool isVarArg,
const SmallVectorImpl<ISD::InputArg> &Ins,
DebugLoc dl, SelectionDAG &DAG,
SmallVectorImpl<SDValue> &InVals,
const SmallVectorImpl<SDValue> &OutVals,
SDValue Callee) const;
SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerMEMBARRIER(SDValue Op, SelectionDAG& DAG) const;
SDValue LowerATOMIC_FENCE(SDValue Op, SelectionDAG& DAG) const;
SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const;
SDValue LowerReturn(SDValue Chain,
CallingConv::ID CallConv, bool isVarArg,
const SmallVectorImpl<ISD::OutputArg> &Outs,
const SmallVectorImpl<SDValue> &OutVals,
DebugLoc dl, SelectionDAG &DAG) const;
virtual MachineBasicBlock
*EmitInstrWithCustomInserter(MachineInstr *MI,
MachineBasicBlock *BB) const;
SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG) const;
virtual EVT getSetCCResultType(EVT VT) const {
return MVT::i1;
}
virtual bool getPostIndexedAddressParts(SDNode *N, SDNode *Op,
SDValue &Base, SDValue &Offset,
ISD::MemIndexedMode &AM,
SelectionDAG &DAG) const;
std::pair<unsigned, const TargetRegisterClass*>
getRegForInlineAsmConstraint(const std::string &Constraint,
EVT VT) const;
// Intrinsics
virtual SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op,
SelectionDAG &DAG) const;
/// isLegalAddressingMode - Return true if the addressing mode represented
/// by AM is legal for this target, for a load/store of the specified type.
/// The type may be VoidTy, in which case only return true if the addressing
/// mode is legal for a load/store of any legal type.
/// TODO: Handle pre/postinc as well.
virtual bool isLegalAddressingMode(const AddrMode &AM, Type *Ty) const;
/// isLegalICmpImmediate - Return true if the specified immediate is legal
/// icmp immediate, that is the target has icmp instructions which can
/// compare a register against the immediate without having to materialize
/// the immediate into a register.
virtual bool isLegalICmpImmediate(int64_t Imm) const;
};
} // end namespace llvm
#endif // Hexagon_ISELLOWERING_H

View File

@ -0,0 +1,491 @@
//=- HexagonImmediates.td - Hexagon immediate processing --*- tablegen -*-=//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illnois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// From IA64's InstrInfo file
def s32Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def s16Imm : Operand<i32> {
let PrintMethod = "printHexagonImmOperand";
}
def s12Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def s11Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def s11_0Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def s11_1Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def s11_2Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def s11_3Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def s10Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def s8Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def s9Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def s8Imm64 : Operand<i64> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def s6Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def s4Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def s4_0Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def s4_1Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def s4_2Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def s4_3Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def u64Imm : Operand<i64> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def u32Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def u16Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def u16_0Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def u16_1Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def u16_2Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def u11_3Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def u10Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def u9Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def u8Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def u7Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def u6Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def u6_0Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def u6_1Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def u6_2Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def u6_3Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def u5Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def u4Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def u3Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def u2Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def n8Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
def m6Imm : Operand<i32> {
// For now, we use a generic print function for all operands.
let PrintMethod = "printHexagonImmOperand";
}
//
// Immediate predicates
//
def s32ImmPred : PatLeaf<(i32 imm), [{
// immS16 predicate - True if the immediate fits in a 16-bit sign extended
// field.
int64_t v = (int64_t)N->getSExtValue();
return isInt<32>(v);
}]>;
def s32_24ImmPred : PatLeaf<(i32 imm), [{
// s32_24ImmPred predicate - True if the immediate fits in a 32-bit sign
// extended field that is a multiple of 0x1000000.
int64_t v = (int64_t)N->getSExtValue();
return isShiftedInt<32,24>(v);
}]>;
def s32_16s8ImmPred : PatLeaf<(i32 imm), [{
// s32_16s8ImmPred predicate - True if the immediate fits in a 32-bit sign
// extended field that is a multiple of 0x10000.
int64_t v = (int64_t)N->getSExtValue();
return isShiftedInt<24,16>(v);
}]>;
def s16ImmPred : PatLeaf<(i32 imm), [{
// immS16 predicate - True if the immediate fits in a 16-bit sign extended
// field.
int64_t v = (int64_t)N->getSExtValue();
return isInt<16>(v);
}]>;
def s13ImmPred : PatLeaf<(i32 imm), [{
// immS13 predicate - True if the immediate fits in a 13-bit sign extended
// field.
int64_t v = (int64_t)N->getSExtValue();
return isInt<13>(v);
}]>;
def s12ImmPred : PatLeaf<(i32 imm), [{
// immS16 predicate - True if the immediate fits in a 16-bit sign extended
// field.
int64_t v = (int64_t)N->getSExtValue();
return isInt<12>(v);
}]>;
def s11_0ImmPred : PatLeaf<(i32 imm), [{
// immS16 predicate - True if the immediate fits in a 16-bit sign extended
// field.
int64_t v = (int64_t)N->getSExtValue();
return isInt<11>(v);
}]>;
def s11_1ImmPred : PatLeaf<(i32 imm), [{
// immS16 predicate - True if the immediate fits in a 16-bit sign extended
// field.
int64_t v = (int64_t)N->getSExtValue();
return isShiftedInt<11,1>(v);
}]>;
def s11_2ImmPred : PatLeaf<(i32 imm), [{
// immS16 predicate - True if the immediate fits in a 16-bit sign extended
// field.
int64_t v = (int64_t)N->getSExtValue();
return isShiftedInt<11,2>(v);
}]>;
def s11_3ImmPred : PatLeaf<(i32 imm), [{
// immS16 predicate - True if the immediate fits in a 16-bit sign extended
// field.
int64_t v = (int64_t)N->getSExtValue();
return isShiftedInt<11,3>(v);
}]>;
def s10ImmPred : PatLeaf<(i32 imm), [{
// s10ImmPred predicate - True if the immediate fits in a 10-bit sign extended
// field.
int64_t v = (int64_t)N->getSExtValue();
return isInt<10>(v);
}]>;
def s9ImmPred : PatLeaf<(i32 imm), [{
// s9ImmPred predicate - True if the immediate fits in a 9-bit sign extended
// field.
int64_t v = (int64_t)N->getSExtValue();
return isInt<9>(v);
}]>;
def s8ImmPred : PatLeaf<(i32 imm), [{
// s8ImmPred predicate - True if the immediate fits in a 8-bit sign extended
// field.
int64_t v = (int64_t)N->getSExtValue();
return isInt<8>(v);
}]>;
def s8Imm64Pred : PatLeaf<(i64 imm), [{
// s8ImmPred predicate - True if the immediate fits in a 8-bit sign extended
// field.
int64_t v = (int64_t)N->getSExtValue();
return isInt<8>(v);
}]>;
def s6ImmPred : PatLeaf<(i32 imm), [{
// s6ImmPred predicate - True if the immediate fits in a 6-bit sign extended
// field.
int64_t v = (int64_t)N->getSExtValue();
return isInt<6>(v);
}]>;
def s4_0ImmPred : PatLeaf<(i32 imm), [{
// s4_0ImmPred predicate - True if the immediate fits in a 4-bit sign extended
// field.
int64_t v = (int64_t)N->getSExtValue();
return isInt<4>(v);
}]>;
def s4_1ImmPred : PatLeaf<(i32 imm), [{
// s4_1ImmPred predicate - True if the immediate fits in a 4-bit sign extended
// field of 2.
int64_t v = (int64_t)N->getSExtValue();
return isShiftedInt<4,1>(v);
}]>;
def s4_2ImmPred : PatLeaf<(i32 imm), [{
// s4_2ImmPred predicate - True if the immediate fits in a 4-bit sign extended
// field that is a multiple of 4.
int64_t v = (int64_t)N->getSExtValue();
return isShiftedInt<4,2>(v);
}]>;
def s4_3ImmPred : PatLeaf<(i32 imm), [{
// s4_3ImmPred predicate - True if the immediate fits in a 4-bit sign extended
// field that is a multiple of 8.
int64_t v = (int64_t)N->getSExtValue();
return isShiftedInt<4,3>(v);
}]>;
def u64ImmPred : PatLeaf<(i64 imm), [{
// immS16 predicate - True if the immediate fits in a 16-bit sign extended
// field.
// Adding "N ||" to supress gcc unused warning.
return (N || true);
}]>;
def u32ImmPred : PatLeaf<(i32 imm), [{
// immS16 predicate - True if the immediate fits in a 16-bit sign extended
// field.
int64_t v = (int64_t)N->getSExtValue();
return isUInt<32>(v);
}]>;
def u16ImmPred : PatLeaf<(i32 imm), [{
// u16ImmPred predicate - True if the immediate fits in a 16-bit unsigned
// field.
int64_t v = (int64_t)N->getSExtValue();
return isUInt<16>(v);
}]>;
def u16_s8ImmPred : PatLeaf<(i32 imm), [{
// u16_s8ImmPred predicate - True if the immediate fits in a 16-bit sign
// extended s8 field.
int64_t v = (int64_t)N->getSExtValue();
return isShiftedUInt<16,8>(v);
}]>;
def u9ImmPred : PatLeaf<(i32 imm), [{
// u9ImmPred predicate - True if the immediate fits in a 9-bit unsigned
// field.
int64_t v = (int64_t)N->getSExtValue();
return isUInt<9>(v);
}]>;
def u8ImmPred : PatLeaf<(i32 imm), [{
// u8ImmPred predicate - True if the immediate fits in a 8-bit unsigned
// field.
int64_t v = (int64_t)N->getSExtValue();
return isUInt<8>(v);
}]>;
def u7ImmPred : PatLeaf<(i32 imm), [{
// u7ImmPred predicate - True if the immediate fits in a 8-bit unsigned
// field.
int64_t v = (int64_t)N->getSExtValue();
return isUInt<7>(v);
}]>;
def u6ImmPred : PatLeaf<(i32 imm), [{
// u6ImmPred predicate - True if the immediate fits in a 6-bit unsigned
// field.
int64_t v = (int64_t)N->getSExtValue();
return isUInt<6>(v);
}]>;
def u6_0ImmPred : PatLeaf<(i32 imm), [{
// u6_0ImmPred predicate - True if the immediate fits in a 6-bit unsigned
// field. Same as u6ImmPred.
int64_t v = (int64_t)N->getSExtValue();
return isUInt<6>(v);
}]>;
def u6_1ImmPred : PatLeaf<(i32 imm), [{
// u6_1ImmPred predicate - True if the immediate fits in a 6-bit unsigned
// field that is 1 bit alinged - multiple of 2.
int64_t v = (int64_t)N->getSExtValue();
return isShiftedUInt<6,1>(v);
}]>;
def u6_2ImmPred : PatLeaf<(i32 imm), [{
// u6_2ImmPred predicate - True if the immediate fits in a 6-bit unsigned
// field that is 2 bits alinged - multiple of 4.
int64_t v = (int64_t)N->getSExtValue();
return isShiftedUInt<6,2>(v);
}]>;
def u6_3ImmPred : PatLeaf<(i32 imm), [{
// u6_3ImmPred predicate - True if the immediate fits in a 6-bit unsigned
// field that is 3 bits alinged - multiple of 8.
int64_t v = (int64_t)N->getSExtValue();
return isShiftedUInt<6,3>(v);
}]>;
def u5ImmPred : PatLeaf<(i32 imm), [{
// u5ImmPred predicate - True if the immediate fits in a 5-bit unsigned
// field.
int64_t v = (int64_t)N->getSExtValue();
return isUInt<5>(v);
}]>;
def u3ImmPred : PatLeaf<(i32 imm), [{
// u3ImmPred predicate - True if the immediate fits in a 3-bit unsigned
// field.
int64_t v = (int64_t)N->getSExtValue();
return isUInt<3>(v);
}]>;
def u2ImmPred : PatLeaf<(i32 imm), [{
// u2ImmPred predicate - True if the immediate fits in a 2-bit unsigned
// field.
int64_t v = (int64_t)N->getSExtValue();
return isUInt<2>(v);
}]>;
def u1ImmPred : PatLeaf<(i1 imm), [{
// u1ImmPred predicate - True if the immediate fits in a 1-bit unsigned
// field.
int64_t v = (int64_t)N->getSExtValue();
return isUInt<1>(v);
}]>;
def m6ImmPred : PatLeaf<(i32 imm), [{
// m6ImmPred predicate - True if the immediate is negative and fits in
// a 6-bit negative number.
int64_t v = (int64_t)N->getSExtValue();
return isInt<6>(v);
}]>;
//InN means negative integers in [-(2^N - 1), 0]
def n8ImmPred : PatLeaf<(i32 imm), [{
// n8ImmPred predicate - True if the immediate fits in a 8-bit unsigned
// field.
int64_t v = (int64_t)N->getSExtValue();
return (-255 <= v && v <= 0);
}]>;

View File

@ -0,0 +1,242 @@
//==- HexagonInstrFormats.td - Hexagon Instruction Formats --*- tablegen -*-==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
class InstHexagon<dag outs, dag ins, string asmstr, list<dag> pattern,
string cstr,
InstrItinClass itin> : Instruction {
field bits<32> Inst;
let Namespace = "Hexagon";
/* Commented out for Hexagon
bits<2> op;
let Inst{31-30} = op; */ // Top two bits are the 'op' field
dag OutOperandList = outs;
dag InOperandList = ins;
let AsmString = asmstr;
let Pattern = pattern;
let Constraints = cstr;
let Itinerary = itin;
}
//----------------------------------------------------------------------------//
// Intruction Classes Definitions +
//----------------------------------------------------------------------------//
// LD Instruction Class in V2/V3/V4.
// Definition of the instruction class NOT CHANGED.
class LDInst<dag outs, dag ins, string asmstr, list<dag> pattern>
: InstHexagon<outs, ins, asmstr, pattern, "", LD> {
bits<5> rd;
bits<5> rs;
bits<13> imm13;
}
// LD Instruction Class in V2/V3/V4.
// Definition of the instruction class NOT CHANGED.
class LDInstPost<dag outs, dag ins, string asmstr, list<dag> pattern,
string cstr>
: InstHexagon<outs, ins, asmstr, pattern, cstr, LD> {
bits<5> rd;
bits<5> rs;
bits<5> rt;
bits<13> imm13;
}
// ST Instruction Class in V2/V3 can take SLOT0 only.
// ST Instruction Class in V4 can take SLOT0 & SLOT1.
// Definition of the instruction class CHANGED from V2/V3 to V4.
class STInst<dag outs, dag ins, string asmstr, list<dag> pattern>
: InstHexagon<outs, ins, asmstr, pattern, "", ST> {
bits<5> rd;
bits<5> rs;
bits<13> imm13;
}
// ST Instruction Class in V2/V3 can take SLOT0 only.
// ST Instruction Class in V4 can take SLOT0 & SLOT1.
// Definition of the instruction class CHANGED from V2/V3 to V4.
class STInstPost<dag outs, dag ins, string asmstr, list<dag> pattern,
string cstr>
: InstHexagon<outs, ins, asmstr, pattern, cstr, ST> {
bits<5> rd;
bits<5> rs;
bits<5> rt;
bits<13> imm13;
}
// ALU32 Instruction Class in V2/V3/V4.
// Definition of the instruction class NOT CHANGED.
class ALU32Type<dag outs, dag ins, string asmstr, list<dag> pattern>
: InstHexagon<outs, ins, asmstr, pattern, "", ALU32> {
bits<5> rd;
bits<5> rs;
bits<5> rt;
bits<16> imm16;
bits<16> imm16_2;
}
// ALU64 Instruction Class in V2/V3.
// XTYPE Instruction Class in V4.
// Definition of the instruction class NOT CHANGED.
// Name of the Instruction Class changed from ALU64 to XTYPE from V2/V3 to V4.
class ALU64Type<dag outs, dag ins, string asmstr, list<dag> pattern>
: InstHexagon<outs, ins, asmstr, pattern, "", ALU64> {
bits<5> rd;
bits<5> rs;
bits<5> rt;
bits<16> imm16;
bits<16> imm16_2;
}
// M Instruction Class in V2/V3.
// XTYPE Instruction Class in V4.
// Definition of the instruction class NOT CHANGED.
// Name of the Instruction Class changed from M to XTYPE from V2/V3 to V4.
class MInst<dag outs, dag ins, string asmstr, list<dag> pattern>
: InstHexagon<outs, ins, asmstr, pattern, "", M> {
bits<5> rd;
bits<5> rs;
bits<5> rt;
}
// M Instruction Class in V2/V3.
// XTYPE Instruction Class in V4.
// Definition of the instruction class NOT CHANGED.
// Name of the Instruction Class changed from M to XTYPE from V2/V3 to V4.
class MInst_acc<dag outs, dag ins, string asmstr, list<dag> pattern,
string cstr>
: InstHexagon<outs, ins, asmstr, pattern, cstr, M> {
bits<5> rd;
bits<5> rs;
bits<5> rt;
}
// S Instruction Class in V2/V3.
// XTYPE Instruction Class in V4.
// Definition of the instruction class NOT CHANGED.
// Name of the Instruction Class changed from S to XTYPE from V2/V3 to V4.
class SInst<dag outs, dag ins, string asmstr, list<dag> pattern>
//: InstHexagon<outs, ins, asmstr, pattern, cstr, !if(V4T, XTYPE_V4, M)> {
: InstHexagon<outs, ins, asmstr, pattern, "", S> {
// : InstHexagon<outs, ins, asmstr, pattern, "", S> {
bits<5> rd;
bits<5> rs;
bits<5> rt;
}
// S Instruction Class in V2/V3.
// XTYPE Instruction Class in V4.
// Definition of the instruction class NOT CHANGED.
// Name of the Instruction Class changed from S to XTYPE from V2/V3 to V4.
class SInst_acc<dag outs, dag ins, string asmstr, list<dag> pattern,
string cstr>
: InstHexagon<outs, ins, asmstr, pattern, cstr, S> {
// : InstHexagon<outs, ins, asmstr, pattern, cstr, S> {
// : InstHexagon<outs, ins, asmstr, pattern, cstr, !if(V4T, XTYPE_V4, S)> {
bits<5> rd;
bits<5> rs;
bits<5> rt;
}
// J Instruction Class in V2/V3/V4.
// Definition of the instruction class NOT CHANGED.
class JType<dag outs, dag ins, string asmstr, list<dag> pattern>
: InstHexagon<outs, ins, asmstr, pattern, "", J> {
bits<16> imm16;
}
// JR Instruction Class in V2/V3/V4.
// Definition of the instruction class NOT CHANGED.
class JRType<dag outs, dag ins, string asmstr, list<dag> pattern>
: InstHexagon<outs, ins, asmstr, pattern, "", JR> {
bits<5> rs;
bits<5> pu; // Predicate register
}
// CR Instruction Class in V2/V3/V4.
// Definition of the instruction class NOT CHANGED.
class CRInst<dag outs, dag ins, string asmstr, list<dag> pattern>
: InstHexagon<outs, ins, asmstr, pattern, "", CR> {
bits<5> rs;
bits<10> imm10;
}
class Pseudo<dag outs, dag ins, string asmstr, list<dag> pattern>
: InstHexagon<outs, ins, asmstr, pattern, "", PSEUDO>;
//----------------------------------------------------------------------------//
// Intruction Classes Definitions -
//----------------------------------------------------------------------------//
//
// ALU32 patterns
//.
class ALU32_rr<dag outs, dag ins, string asmstr, list<dag> pattern>
: ALU32Type<outs, ins, asmstr, pattern> {
}
class ALU32_ir<dag outs, dag ins, string asmstr, list<dag> pattern>
: ALU32Type<outs, ins, asmstr, pattern> {
let rt{0-4} = 0;
}
class ALU32_ri<dag outs, dag ins, string asmstr, list<dag> pattern>
: ALU32Type<outs, ins, asmstr, pattern> {
let rt{0-4} = 0;
}
class ALU32_ii<dag outs, dag ins, string asmstr, list<dag> pattern>
: ALU32Type<outs, ins, asmstr, pattern> {
let rt{0-4} = 0;
}
//
// ALU64 patterns.
//
class ALU64_rr<dag outs, dag ins, string asmstr, list<dag> pattern>
: ALU64Type<outs, ins, asmstr, pattern> {
}
// J Type Instructions.
class JInst<dag outs, dag ins, string asmstr, list<dag> pattern>
: JType<outs, ins, asmstr, pattern> {
}
// JR type Instructions.
class JRInst<dag outs, dag ins, string asmstr, list<dag> pattern>
: JRType<outs, ins, asmstr, pattern> {
}
// Post increment ST Instruction.
class STInstPI<dag outs, dag ins, string asmstr, list<dag> pattern, string cstr>
: STInstPost<outs, ins, asmstr, pattern, cstr> {
let rt{0-4} = 0;
}
// Post increment LD Instruction.
class LDInstPI<dag outs, dag ins, string asmstr, list<dag> pattern, string cstr>
: LDInstPost<outs, ins, asmstr, pattern, cstr> {
let rt{0-4} = 0;
}
//===----------------------------------------------------------------------===//
// V4 Instruction Format Definitions +
//===----------------------------------------------------------------------===//
include "HexagonInstrFormatsV4.td"
//===----------------------------------------------------------------------===//
// V4 Instruction Format Definitions +
//===----------------------------------------------------------------------===//

View File

@ -0,0 +1,46 @@
//==- HexagonInstrFormats.td - Hexagon Instruction Formats --*- tablegen -*-==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file describes the Hexagon V4 instruction classes in TableGen format.
//
//===----------------------------------------------------------------------===//
//
// NV type instructions.
//
class NVInst_V4<dag outs, dag ins, string asmstr, list<dag> pattern>
: InstHexagon<outs, ins, asmstr, pattern, "", NV_V4> {
bits<5> rd;
bits<5> rs;
bits<13> imm13;
}
// Definition of Post increment new value store.
class NVInstPost_V4<dag outs, dag ins, string asmstr, list<dag> pattern,
string cstr>
: InstHexagon<outs, ins, asmstr, pattern, cstr, NV_V4> {
bits<5> rd;
bits<5> rs;
bits<5> rt;
bits<13> imm13;
}
// Post increment ST Instruction.
class NVInstPI_V4<dag outs, dag ins, string asmstr, list<dag> pattern,
string cstr>
: NVInstPost_V4<outs, ins, asmstr, pattern, cstr> {
let rt{0-4} = 0;
}
class MEMInst_V4<dag outs, dag ins, string asmstr, list<dag> pattern>
: InstHexagon<outs, ins, asmstr, pattern, "", MEM_V4> {
bits<5> rd;
bits<5> rs;
bits<6> imm6;
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,166 @@
//=- HexagonInstrInfo.h - Hexagon Instruction Information ---------*- 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 Hexagon implementation of the TargetInstrInfo class.
//
//===----------------------------------------------------------------------===//
#ifndef HexagonINSTRUCTIONINFO_H
#define HexagonINSTRUCTIONINFO_H
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetFrameLowering.h"
#include "HexagonRegisterInfo.h"
#define GET_INSTRINFO_HEADER
#include "HexagonGenInstrInfo.inc"
namespace llvm {
class HexagonInstrInfo : public HexagonGenInstrInfo {
const HexagonRegisterInfo RI;
const HexagonSubtarget& Subtarget;
public:
explicit HexagonInstrInfo(HexagonSubtarget &ST);
/// getRegisterInfo - TargetInstrInfo is a superset of MRegister info. As
/// such, whenever a client has an instance of instruction info, it should
/// always be able to get register info as well (through this method).
///
virtual const HexagonRegisterInfo &getRegisterInfo() const { return RI; }
/// isLoadFromStackSlot - If the specified machine instruction is a direct
/// load from a stack slot, return the virtual or physical register number of
/// the destination along with the FrameIndex of the loaded stack slot. If
/// not, return 0. This predicate must return 0 if the instruction has
/// any side effects other than loading from the stack slot.
virtual unsigned isLoadFromStackSlot(const MachineInstr *MI,
int &FrameIndex) const;
/// isStoreToStackSlot - If the specified machine instruction is a direct
/// store to a stack slot, return the virtual or physical register number of
/// the source reg along with the FrameIndex of the loaded stack slot. If
/// not, return 0. This predicate must return 0 if the instruction has
/// any side effects other than storing to the stack slot.
virtual unsigned isStoreToStackSlot(const MachineInstr *MI,
int &FrameIndex) const;
virtual bool AnalyzeBranch(MachineBasicBlock &MBB,MachineBasicBlock *&TBB,
MachineBasicBlock *&FBB,
SmallVectorImpl<MachineOperand> &Cond,
bool AllowModify) const;
virtual unsigned RemoveBranch(MachineBasicBlock &MBB) const;
virtual unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB,
MachineBasicBlock *FBB,
const SmallVectorImpl<MachineOperand> &Cond,
DebugLoc DL) const;
virtual void copyPhysReg(MachineBasicBlock &MBB,
MachineBasicBlock::iterator I, DebugLoc DL,
unsigned DestReg, unsigned SrcReg,
bool KillSrc) const;
virtual void storeRegToStackSlot(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
unsigned SrcReg, bool isKill, int FrameIndex,
const TargetRegisterClass *RC,
const TargetRegisterInfo *TRI) const;
virtual void storeRegToAddr(MachineFunction &MF, unsigned SrcReg, bool isKill,
SmallVectorImpl<MachineOperand> &Addr,
const TargetRegisterClass *RC,
SmallVectorImpl<MachineInstr*> &NewMIs) const;
virtual void loadRegFromStackSlot(MachineBasicBlock &MBB,
MachineBasicBlock::iterator MBBI,
unsigned DestReg, int FrameIndex,
const TargetRegisterClass *RC,
const TargetRegisterInfo *TRI) const;
virtual void loadRegFromAddr(MachineFunction &MF, unsigned DestReg,
SmallVectorImpl<MachineOperand> &Addr,
const TargetRegisterClass *RC,
SmallVectorImpl<MachineInstr*> &NewMIs) const;
virtual MachineInstr* foldMemoryOperandImpl(MachineFunction &MF,
MachineInstr* MI,
const SmallVectorImpl<unsigned> &Ops,
int FrameIndex) const;
virtual MachineInstr* foldMemoryOperandImpl(MachineFunction &MF,
MachineInstr* MI,
const SmallVectorImpl<unsigned> &Ops,
MachineInstr* LoadMI) const {
return 0;
}
unsigned createVR(MachineFunction* MF, MVT VT) const;
virtual bool isPredicable(MachineInstr *MI) const;
virtual bool
PredicateInstruction(MachineInstr *MI,
const SmallVectorImpl<MachineOperand> &Cond) const;
virtual bool isProfitableToIfCvt(MachineBasicBlock &MBB, unsigned NumCyles,
unsigned ExtraPredCycles,
const BranchProbability &Probability) const;
virtual bool isProfitableToIfCvt(MachineBasicBlock &TMBB,
unsigned NumTCycles, unsigned ExtraTCycles,
MachineBasicBlock &FMBB,
unsigned NumFCycles, unsigned ExtraFCycles,
const BranchProbability &Probability) const;
virtual bool isPredicated(const MachineInstr *MI) const;
virtual bool DefinesPredicate(MachineInstr *MI,
std::vector<MachineOperand> &Pred) const;
virtual bool
SubsumesPredicate(const SmallVectorImpl<MachineOperand> &Pred1,
const SmallVectorImpl<MachineOperand> &Pred2) const;
virtual bool
ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const;
virtual bool
isProfitableToDupForIfCvt(MachineBasicBlock &MBB,unsigned NumCycles,
const BranchProbability &Probability) const;
bool isValidOffset(const int Opcode, const int Offset) const;
bool isValidAutoIncImm(const EVT VT, const int Offset) const;
bool isMemOp(const MachineInstr *MI) const;
bool isSpillPredRegOp(const MachineInstr *MI) const;
bool isU6_3Immediate(const int value) const;
bool isU6_2Immediate(const int value) const;
bool isU6_1Immediate(const int value) const;
bool isU6_0Immediate(const int value) const;
bool isS4_3Immediate(const int value) const;
bool isS4_2Immediate(const int value) const;
bool isS4_1Immediate(const int value) const;
bool isS4_0Immediate(const int value) const;
bool isS12_Immediate(const int value) const;
bool isU6_Immediate(const int value) const;
bool isS8_Immediate(const int value) const;
bool isS6_Immediate(const int value) const;
bool isConditionalALU32 (const MachineInstr* MI) const;
bool isConditionalLoad (const MachineInstr* MI) const;
bool isDeallocRet(const MachineInstr *MI) const;
private:
int getMatchingCondBranchOpcode(int Opc, bool sense) const;
};
}
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,134 @@
//=- HexagonInstrInfoV3.td - Target Desc. for Hexagon Target -*- tablegen -*-=//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file describes the Hexagon V3 instructions in TableGen format.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// J +
//===----------------------------------------------------------------------===//
// Call subroutine.
let isCall = 1, neverHasSideEffects = 1,
Defs = [D0, D1, D2, D3, D4, D5, D6, D7, R28, R31,
P0, P1, P2, P3, LC0, LC1, SA0, SA1] in {
def CALLv3 : JInst<(outs), (ins calltarget:$dst, variable_ops),
"call $dst", []>, Requires<[HasV3T]>;
}
//===----------------------------------------------------------------------===//
// J -
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// JR +
//===----------------------------------------------------------------------===//
// Call subroutine from register.
let isCall = 1, neverHasSideEffects = 1,
Defs = [D0, D1, D2, D3, D4, D5, D6, D7, R28, R31,
P0, P1, P2, P3, LC0, LC1, SA0, SA1] in {
def CALLRv3 : JRInst<(outs), (ins IntRegs:$dst, variable_ops),
"callr $dst",
[]>, Requires<[HasV3TOnly]>;
}
// if(p?.new) jumpr:t r?
let isReturn = 1, isTerminator = 1, isBarrier = 1,
Defs = [PC], Uses = [R31] in {
def JMPR_cPnewt: JRInst<(outs), (ins PredRegs:$src1, IntRegs:$src2),
"if ($src1.new) jumpr:t $src2",
[]>, Requires<[HasV3T]>;
}
// if (!p?.new) jumpr:t r?
let isReturn = 1, isTerminator = 1, isBarrier = 1,
Defs = [PC], Uses = [R31] in {
def JMPR_cNotPnewt: JRInst<(outs), (ins PredRegs:$src1, IntRegs:$src2),
"if (!$src1.new) jumpr:t $src2",
[]>, Requires<[HasV3T]>;
}
// Not taken.
// if(p?.new) jumpr:nt r?
let isReturn = 1, isTerminator = 1, isBarrier = 1,
Defs = [PC], Uses = [R31] in {
def JMPR_cPnewNt: JRInst<(outs), (ins PredRegs:$src1, IntRegs:$src2),
"if ($src1.new) jumpr:nt $src2",
[]>, Requires<[HasV3T]>;
}
// if (!p?.new) jumpr:nt r?
let isReturn = 1, isTerminator = 1, isBarrier = 1,
Defs = [PC], Uses = [R31] in {
def JMPR_cNotPnewNt: JRInst<(outs), (ins PredRegs:$src1, IntRegs:$src2),
"if (!$src1.new) jumpr:nt $src2",
[]>, Requires<[HasV3T]>;
}
//===----------------------------------------------------------------------===//
// JR -
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// ALU64/ALU +
//===----------------------------------------------------------------------===//
let AddedComplexity = 200 in
def MAXw_dd : ALU64_rr<(outs DoubleRegs:$dst), (ins DoubleRegs:$src1,
DoubleRegs:$src2),
"$dst = max($src2, $src1)",
[(set DoubleRegs:$dst, (select (i1 (setlt DoubleRegs:$src2,
DoubleRegs:$src1)),
DoubleRegs:$src1,
DoubleRegs:$src2))]>,
Requires<[HasV3T]>;
let AddedComplexity = 200 in
def MINw_dd : ALU64_rr<(outs DoubleRegs:$dst), (ins DoubleRegs:$src1,
DoubleRegs:$src2),
"$dst = min($src2, $src1)",
[(set DoubleRegs:$dst, (select (i1 (setgt DoubleRegs:$src2,
DoubleRegs:$src1)),
DoubleRegs:$src1,
DoubleRegs:$src2))]>,
Requires<[HasV3T]>;
//===----------------------------------------------------------------------===//
// ALU64/ALU -
//===----------------------------------------------------------------------===//
//def : Pat <(brcond (i1 (seteq IntRegs:$src1, 0)), bb:$offset),
// (JMP_RegEzt IntRegs:$src1, bb:$offset)>, Requires<[HasV3T]>;
//def : Pat <(brcond (i1 (setne IntRegs:$src1, 0)), bb:$offset),
// (JMP_RegNzt IntRegs:$src1, bb:$offset)>, Requires<[HasV3T]>;
//def : Pat <(brcond (i1 (setle IntRegs:$src1, 0)), bb:$offset),
// (JMP_RegLezt IntRegs:$src1, bb:$offset)>, Requires<[HasV3T]>;
//def : Pat <(brcond (i1 (setge IntRegs:$src1, 0)), bb:$offset),
// (JMP_RegGezt IntRegs:$src1, bb:$offset)>, Requires<[HasV3T]>;
//def : Pat <(brcond (i1 (setgt IntRegs:$src1, -1)), bb:$offset),
// (JMP_RegGezt IntRegs:$src1, bb:$offset)>, Requires<[HasV3T]>;
// Map call instruction
def : Pat<(call IntRegs:$dst),
(CALLRv3 IntRegs:$dst)>, Requires<[HasV3T]>;
def : Pat<(call tglobaladdr:$dst),
(CALLv3 tglobaladdr:$dst)>, Requires<[HasV3T]>;
def : Pat<(call texternalsym:$dst),
(CALLv3 texternalsym:$dst)>, Requires<[HasV3T]>;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,29 @@
//===-- HexagonIntrinsicsDerived.td - Derived intrinsics ---*- tablegen -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Multiply 64-bit and use lower result
//
// Optimized with intrinisics accumulates
//
def : Pat <(mul DoubleRegs:$src1, DoubleRegs:$src2),
(COMBINE_rr
(Hexagon_M2_maci
(Hexagon_M2_maci (EXTRACT_SUBREG (MPYU64 (EXTRACT_SUBREG DoubleRegs:$src1, subreg_loreg),
(EXTRACT_SUBREG DoubleRegs:$src2, subreg_loreg)),
subreg_hireg),
(EXTRACT_SUBREG DoubleRegs:$src1, subreg_loreg),
(EXTRACT_SUBREG DoubleRegs:$src2, subreg_hireg)),
(EXTRACT_SUBREG DoubleRegs:$src2, subreg_loreg),
(EXTRACT_SUBREG DoubleRegs:$src1, subreg_hireg)),
(EXTRACT_SUBREG (MPYU64 (EXTRACT_SUBREG DoubleRegs:$src1, subreg_loreg),
(EXTRACT_SUBREG DoubleRegs:$src2, subreg_loreg)),
subreg_loreg))>;

View File

@ -0,0 +1,50 @@
//=- HexagonIntrinsicsV3.td - Target Description for Hexagon -*- tablegen -*-=//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file describes the Hexagon V3 Compiler Intrinsics in TableGen format.
//
//===----------------------------------------------------------------------===//
// MTYPE / COMPLEX / Vector reduce complex multiply real or imaginary.
def Hexagon_M2_vrcmpys_s1:
di_MInst_disi_s1_sat <"vrcmpys", int_hexagon_M2_vrcmpys_s1>;
def Hexagon_M2_vrcmpys_acc_s1:
di_MInst_didisi_acc_s1_sat <"vrcmpys", int_hexagon_M2_vrcmpys_acc_s1>;
def Hexagon_M2_vrcmpys_s1rp:
si_MInst_disi_s1_rnd_sat <"vrcmpys", int_hexagon_M2_vrcmpys_s1rp>;
/********************************************************************
* MTYPE/VB *
*********************************************************************/
// MTYPE / VB / Vector reduce add unsigned bytes.
def Hexagon_M2_vradduh:
si_MInst_didi <"vradduh", int_hexagon_M2_vradduh>;
/********************************************************************
* ALU64/ALU *
*********************************************************************/
// ALU64 / ALU / Add.
def Hexagon_A2_addsp:
di_ALU64_sidi <"add", int_hexagon_A2_addsp>;
def Hexagon_A2_addpsat:
di_ALU64_didi <"add", int_hexagon_A2_addpsat>;
def Hexagon_A2_maxp:
di_ALU64_didi <"max", int_hexagon_A2_maxp>;
def Hexagon_A2_maxup:
di_ALU64_didi <"maxu", int_hexagon_A2_maxup>;

View File

@ -0,0 +1,369 @@
//===- HexagonIntrinsicsV4.td - V4 Instruction intrinsics --*- tablegen -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// This is populated based on the following specs:
// Hexagon V4 Architecture Extensions
// Application-Level Specification
// 80-V9418-12 Rev. A
// June 15, 2010
//
// ALU 32 types.
//
class si_ALU32_sisi_not<string opc, Intrinsic IntID>
: ALU32_rr<(outs IntRegs:$dst), (ins IntRegs:$src1, IntRegs:$src2),
!strconcat("$dst = ", !strconcat(opc , "($src1, ~$src2)")),
[(set IntRegs:$dst, (IntID IntRegs:$src1, IntRegs:$src2))]>;
class di_ALU32_s8si<string opc, Intrinsic IntID>
: ALU32_rr<(outs DoubleRegs:$dst), (ins s8Imm:$src1, IntRegs:$src2),
!strconcat("$dst = ", !strconcat(opc , "(#$src1, $src2)")),
[(set DoubleRegs:$dst, (IntID imm:$src1, IntRegs:$src2))]>;
class di_ALU32_sis8<string opc, Intrinsic IntID>
: ALU32_rr<(outs DoubleRegs:$dst), (ins IntRegs:$src1, s8Imm:$src2),
!strconcat("$dst = ", !strconcat(opc , "($src1, #$src2)")),
[(set DoubleRegs:$dst, (IntID IntRegs:$src1, imm:$src2))]>;
class qi_neg_ALU32_sisi<string opc, Intrinsic IntID>
: ALU32_rr<(outs PredRegs:$dst), (ins IntRegs:$src1, IntRegs:$src2),
!strconcat("$dst = !", !strconcat(opc , "($src1, $src2)")),
[(set PredRegs:$dst, (IntID IntRegs:$src1, IntRegs:$src2))]>;
class qi_neg_ALU32_sis10<string opc, Intrinsic IntID>
: ALU32_rr<(outs PredRegs:$dst), (ins IntRegs:$src1, s10Imm:$src2),
!strconcat("$dst = !", !strconcat(opc , "($src1, #$src2)")),
[(set PredRegs:$dst, (IntID IntRegs:$src1, imm:$src2))]>;
class qi_neg_ALU32_siu9<string opc, Intrinsic IntID>
: ALU32_rr<(outs PredRegs:$dst), (ins IntRegs:$src1, u9Imm:$src2),
!strconcat("$dst = !", !strconcat(opc , "($src1, #$src2)")),
[(set PredRegs:$dst, (IntID IntRegs:$src1, imm:$src2))]>;
class si_neg_ALU32_sisi<string opc, Intrinsic IntID>
: ALU32_rr<(outs IntRegs:$dst), (ins IntRegs:$src1, IntRegs:$src2),
!strconcat("$dst = !", !strconcat(opc , "($src1, $src2)")),
[(set IntRegs:$dst, (IntID IntRegs:$src1, IntRegs:$src2))]>;
class si_neg_ALU32_sis8<string opc, Intrinsic IntID>
: ALU32_rr<(outs IntRegs:$dst), (ins IntRegs:$src1, s8Imm:$src2),
!strconcat("$dst = !", !strconcat(opc , "($src1, #$src2)")),
[(set IntRegs:$dst, (IntID IntRegs:$src1, imm:$src2))]>;
class si_ALU32_sis8<string opc, Intrinsic IntID>
: ALU32_rr<(outs IntRegs:$dst), (ins IntRegs:$src1, s8Imm:$src2),
!strconcat("$dst = ", !strconcat(opc , "($src1, #$src2)")),
[(set IntRegs:$dst, (IntID IntRegs:$src1, imm:$src2))]>;
//
// SInst Classes.
//
class qi_neg_SInst_qiqi<string opc, Intrinsic IntID>
: SInst<(outs PredRegs:$dst), (ins IntRegs:$src1, IntRegs:$src2),
!strconcat("$dst = !", !strconcat(opc , "($src1, $src2)")),
[(set PredRegs:$dst, (IntID IntRegs:$src1, IntRegs:$src2))]>;
class qi_SInst_qi_andqiqi_neg<string opc, Intrinsic IntID>
: SInst<(outs PredRegs:$dst), (ins IntRegs:$src1, IntRegs:$src2,
IntRegs:$src3),
!strconcat("$dst = ", !strconcat(opc ,
"($src1, and($src2, !$src3)")),
[(set PredRegs:$dst, (IntID IntRegs:$src1, IntRegs:$src2,
IntRegs:$src3))]>;
class qi_SInst_qi_andqiqi<string opc, Intrinsic IntID>
: SInst<(outs PredRegs:$dst), (ins IntRegs:$src1, IntRegs:$src2,
IntRegs:$src3),
!strconcat("$dst = ", !strconcat(opc ,
"($src1, and($src2, $src3)")),
[(set PredRegs:$dst, (IntID IntRegs:$src1, IntRegs:$src2,
IntRegs:$src3))]>;
class qi_SInst_qi_orqiqi_neg<string opc, Intrinsic IntID>
: SInst<(outs PredRegs:$dst), (ins IntRegs:$src1, IntRegs:$src2,
IntRegs:$src3),
!strconcat("$dst = ", !strconcat(opc ,
"($src1, or($src2, !$src3)")),
[(set PredRegs:$dst, (IntID IntRegs:$src1, IntRegs:$src2,
IntRegs:$src3))]>;
class qi_SInst_qi_orqiqi<string opc, Intrinsic IntID>
: SInst<(outs PredRegs:$dst), (ins IntRegs:$src1, IntRegs:$src2,
IntRegs:$src3),
!strconcat("$dst = ", !strconcat(opc ,
"($src1, or($src2, $src3)")),
[(set PredRegs:$dst, (IntID IntRegs:$src1, IntRegs:$src2,
IntRegs:$src3))]>;
class si_SInst_si_addsis6<string opc, Intrinsic IntID>
: SInst<(outs IntRegs:$dst), (ins IntRegs:$src1, IntRegs:$src2, s6Imm:$src3),
!strconcat("$dst = ", !strconcat(opc ,
"($src1, add($src2, #$src3)")),
[(set IntRegs:$dst, (IntID IntRegs:$src1, IntRegs:$src2,
imm:$src3))]>;
class si_SInst_si_subs6si<string opc, Intrinsic IntID>
: SInst<(outs IntRegs:$dst), (ins IntRegs:$src1, s6Imm:$src2, IntRegs:$src3),
!strconcat("$dst = ", !strconcat(opc ,
"($src1, sub(#$src2, $src3)")),
[(set IntRegs:$dst, (IntID IntRegs:$src1, imm:$src2,
IntRegs:$src3))]>;
class di_ALU64_didi_neg<string opc, Intrinsic IntID>
: ALU64_rr<(outs DoubleRegs:$dst), (ins DoubleRegs:$src1, DoubleRegs:$src2),
!strconcat("$dst = ", !strconcat(opc , "($src1, ~$src2)")),
[(set DoubleRegs:$dst, (IntID DoubleRegs:$src1, DoubleRegs:$src2))]>;
class di_MInst_dididi_xacc<string opc, Intrinsic IntID>
: MInst_acc<(outs DoubleRegs:$dst), (ins DoubleRegs:$dst2, DoubleRegs:$src1,
DoubleRegs:$src2),
!strconcat("$dst ^= ", !strconcat(opc , "($src1, $src2)")),
[(set DoubleRegs:$dst, (IntID DoubleRegs:$dst2, DoubleRegs:$src1,
DoubleRegs:$src2))],
"$dst2 = $dst">;
class si_MInst_sisisi_and<string opc, Intrinsic IntID>
: MInst<(outs IntRegs:$dst), (ins IntRegs:$dst1, IntRegs:$src2,
IntRegs:$src3),
!strconcat("$dst &= ", !strconcat(opc , "($src2, $src3)")),
[(set IntRegs:$dst, (IntID IntRegs:$dst1, IntRegs:$src2,
IntRegs:$src3))]>;
class si_MInst_sisisi_andn<string opc, Intrinsic IntID>
: MInst<(outs IntRegs:$dst), (ins IntRegs:$dst1, IntRegs:$src2,
IntRegs:$src3),
!strconcat("$dst &= ", !strconcat(opc , "($src2, ~$src3)")),
[(set IntRegs:$dst, (IntID IntRegs:$dst1, IntRegs:$src2,
IntRegs:$src3))]>;
class si_SInst_sisis10_andi<string opc, Intrinsic IntID>
: SInst<(outs IntRegs:$dst), (ins IntRegs:$src1, IntRegs:$src2, s10Imm:$src3),
!strconcat("$dst = ", !strconcat(opc ,
"($src1, and($src2, #$src3))")),
[(set IntRegs:$dst, (IntID IntRegs:$src1, IntRegs:$src2,
imm:$src3))]>;
class si_MInst_sisisi_xor<string opc, Intrinsic IntID>
: MInst<(outs IntRegs:$dst), (ins IntRegs:$dst1, IntRegs:$src2,
IntRegs:$src3),
!strconcat("$dst ^= ", !strconcat(opc , "($src2, $src3)")),
[(set IntRegs:$dst, (IntID IntRegs:$dst1, IntRegs:$src2,
IntRegs:$src3))]>;
class si_MInst_sisisi_xorn<string opc, Intrinsic IntID>
: MInst<(outs IntRegs:$dst), (ins IntRegs:$dst1, IntRegs:$src2,
IntRegs:$src3),
!strconcat("$dst ^= ", !strconcat(opc , "($src2, ~$src3)")),
[(set IntRegs:$dst, (IntID IntRegs:$dst1, IntRegs:$src2,
IntRegs:$src3))]>;
class si_SInst_sisis10_or<string opc, Intrinsic IntID>
: SInst<(outs IntRegs:$dst), (ins IntRegs:$dst1, IntRegs:$src2, s10Imm:$src3),
!strconcat("$dst |= ", !strconcat(opc , "($src2, #$src3)")),
[(set IntRegs:$dst, (IntID IntRegs:$dst1, IntRegs:$src2,
imm:$src3))]>;
class si_MInst_sisisi_or<string opc, Intrinsic IntID>
: MInst<(outs IntRegs:$dst), (ins IntRegs:$dst1, IntRegs:$src2,
IntRegs:$src3),
!strconcat("$dst |= ", !strconcat(opc , "($src2, $src3)")),
[(set IntRegs:$dst, (IntID IntRegs:$dst1, IntRegs:$src2,
IntRegs:$src3))]>;
class si_MInst_sisisi_orn<string opc, Intrinsic IntID>
: MInst<(outs IntRegs:$dst), (ins IntRegs:$dst1, IntRegs:$src2,
IntRegs:$src3),
!strconcat("$dst |= ", !strconcat(opc , "($src2, ~$src3)")),
[(set IntRegs:$dst, (IntID IntRegs:$dst1, IntRegs:$src2,
IntRegs:$src3))]>;
class si_SInst_siu5_sat<string opc, Intrinsic IntID>
: SInst<(outs IntRegs:$dst), (ins IntRegs:$src1, u5Imm:$src2),
!strconcat("$dst = ", !strconcat(opc , "($src1, #$src2):sat")),
[(set IntRegs:$dst, (IntID IntRegs:$src1, imm:$src2))]>;
/********************************************************************
* ALU32/ALU *
*********************************************************************/
// ALU32 / ALU / Logical Operations.
def Hexagon_A4_orn : si_ALU32_sisi_not <"or", int_hexagon_A4_orn>;
def Hexagon_A4_andn : si_ALU32_sisi_not <"and", int_hexagon_A4_andn>;
/********************************************************************
* ALU32/PERM *
*********************************************************************/
// ALU32 / PERM / Combine Words Into Doublewords.
def Hexagon_A4_combineir : di_ALU32_s8si <"combine", int_hexagon_A4_combineir>;
def Hexagon_A4_combineri : di_ALU32_sis8 <"combine", int_hexagon_A4_combineri>;
/********************************************************************
* ALU32/PRED *
*********************************************************************/
// ALU32 / PRED / Conditional Shift Halfword.
// ALU32 / PRED / Conditional Sign Extend.
// ALU32 / PRED / Conditional Zero Extend.
// ALU32 / PRED / Compare.
def Hexagon_C4_cmpneq : qi_neg_ALU32_sisi <"cmp.eq", int_hexagon_C4_cmpneq>;
def Hexagon_C4_cmpneqi : qi_neg_ALU32_sis10 <"cmp.eq", int_hexagon_C4_cmpneqi>;
def Hexagon_C4_cmplte : qi_neg_ALU32_sisi <"cmp.gt", int_hexagon_C4_cmplte>;
def Hexagon_C4_cmpltei : qi_neg_ALU32_sis10 <"cmp.gt", int_hexagon_C4_cmpltei>;
def Hexagon_C4_cmplteu : qi_neg_ALU32_sisi <"cmp.gtu",int_hexagon_C4_cmplteu>;
def Hexagon_C4_cmplteui: qi_neg_ALU32_siu9 <"cmp.gtu",int_hexagon_C4_cmplteui>;
// ALU32 / PRED / cmpare To General Register.
def Hexagon_A4_rcmpneq : si_neg_ALU32_sisi <"cmp.eq", int_hexagon_A4_rcmpneq>;
def Hexagon_A4_rcmpneqi: si_neg_ALU32_sis8 <"cmp.eq", int_hexagon_A4_rcmpneqi>;
def Hexagon_A4_rcmpeq : si_ALU32_sisi <"cmp.eq", int_hexagon_A4_rcmpeq>;
def Hexagon_A4_rcmpeqi : si_ALU32_sis8 <"cmp.eq", int_hexagon_A4_rcmpeqi>;
/********************************************************************
* CR *
*********************************************************************/
// CR / Corner Detection Acceleration.
def Hexagon_C4_fastcorner9:
qi_SInst_qiqi<"fastcorner9", int_hexagon_C4_fastcorner9>;
def Hexagon_C4_fastcorner9_not:
qi_neg_SInst_qiqi<"fastcorner9",int_hexagon_C4_fastcorner9_not>;
// CR / Logical Operations On Predicates.
def Hexagon_C4_and_andn:
qi_SInst_qi_andqiqi_neg <"and", int_hexagon_C4_and_andn>;
def Hexagon_C4_and_and:
qi_SInst_qi_andqiqi <"and", int_hexagon_C4_and_and>;
def Hexagon_C4_and_orn:
qi_SInst_qi_orqiqi_neg <"and", int_hexagon_C4_and_orn>;
def Hexagon_C4_and_or:
qi_SInst_qi_orqiqi <"and", int_hexagon_C4_and_or>;
def Hexagon_C4_or_andn:
qi_SInst_qi_andqiqi_neg <"or", int_hexagon_C4_or_andn>;
def Hexagon_C4_or_and:
qi_SInst_qi_andqiqi <"or", int_hexagon_C4_or_and>;
def Hexagon_C4_or_orn:
qi_SInst_qi_orqiqi_neg <"or", int_hexagon_C4_or_orn>;
def Hexagon_C4_or_or:
qi_SInst_qi_orqiqi <"or", int_hexagon_C4_or_or>;
/********************************************************************
* XTYPE/ALU *
*********************************************************************/
// XTYPE / ALU / Add And Accumulate.
def Hexagon_S4_addaddi:
si_SInst_si_addsis6 <"add", int_hexagon_S4_addaddi>;
def Hexagon_S4_subaddi:
si_SInst_si_subs6si <"add", int_hexagon_S4_subaddi>;
// XTYPE / ALU / Logical Doublewords.
def Hexagon_S4_andnp:
di_ALU64_didi_neg <"and", int_hexagon_A4_andnp>;
def Hexagon_S4_ornp:
di_ALU64_didi_neg <"or", int_hexagon_A4_ornp>;
// XTYPE / ALU / Logical-logical Doublewords.
def Hexagon_M4_xor_xacc:
di_MInst_dididi_xacc <"xor", int_hexagon_M4_xor_xacc>;
// XTYPE / ALU / Logical-logical Words.
def HEXAGON_M4_and_and:
si_MInst_sisisi_and <"and", int_hexagon_M4_and_and>;
def HEXAGON_M4_and_or:
si_MInst_sisisi_and <"or", int_hexagon_M4_and_or>;
def HEXAGON_M4_and_xor:
si_MInst_sisisi_and <"xor", int_hexagon_M4_and_xor>;
def HEXAGON_M4_and_andn:
si_MInst_sisisi_andn <"and", int_hexagon_M4_and_andn>;
def HEXAGON_M4_xor_and:
si_MInst_sisisi_xor <"and", int_hexagon_M4_xor_and>;
def HEXAGON_M4_xor_or:
si_MInst_sisisi_xor <"or", int_hexagon_M4_xor_or>;
def HEXAGON_M4_xor_andn:
si_MInst_sisisi_xorn <"and", int_hexagon_M4_xor_andn>;
def HEXAGON_M4_or_and:
si_MInst_sisisi_or <"and", int_hexagon_M4_or_and>;
def HEXAGON_M4_or_or:
si_MInst_sisisi_or <"or", int_hexagon_M4_or_or>;
def HEXAGON_M4_or_xor:
si_MInst_sisisi_or <"xor", int_hexagon_M4_or_xor>;
def HEXAGON_M4_or_andn:
si_MInst_sisisi_orn <"and", int_hexagon_M4_or_andn>;
def HEXAGON_S4_or_andix:
si_SInst_sisis10_andi <"or", int_hexagon_S4_or_andix>;
def HEXAGON_S4_or_andi:
si_SInst_sisis10_or <"and", int_hexagon_S4_or_andi>;
def HEXAGON_S4_or_ori:
si_SInst_sisis10_or <"or", int_hexagon_S4_or_ori>;
// XTYPE / ALU / Modulo wrap.
def HEXAGON_A4_modwrapu:
si_ALU64_sisi <"modwrap", int_hexagon_A4_modwrapu>;
// XTYPE / ALU / Round.
def HEXAGON_A4_cround_ri:
si_SInst_siu5 <"cround", int_hexagon_A4_cround_ri>;
def HEXAGON_A4_cround_rr:
si_SInst_sisi <"cround", int_hexagon_A4_cround_rr>;
def HEXAGON_A4_round_ri:
si_SInst_siu5 <"round", int_hexagon_A4_round_ri>;
def HEXAGON_A4_round_rr:
si_SInst_sisi <"round", int_hexagon_A4_round_rr>;
def HEXAGON_A4_round_ri_sat:
si_SInst_siu5_sat <"round", int_hexagon_A4_round_ri_sat>;
def HEXAGON_A4_round_rr_sat:
si_SInst_sisi_sat <"round", int_hexagon_A4_round_rr_sat>;
// XTYPE / ALU / Vector reduce add unsigned halfwords.
// XTYPE / ALU / Vector add bytes.
// XTYPE / ALU / Vector conditional negate.
// XTYPE / ALU / Vector maximum bytes.
// XTYPE / ALU / Vector reduce maximum halfwords.
// XTYPE / ALU / Vector reduce maximum words.
// XTYPE / ALU / Vector minimum bytes.
// XTYPE / ALU / Vector reduce minimum halfwords.
// XTYPE / ALU / Vector reduce minimum words.
// XTYPE / ALU / Vector subtract bytes.
/********************************************************************
* XTYPE/BIT *
*********************************************************************/
// XTYPE / BIT / Count leading.
// XTYPE / BIT / Count trailing.
// XTYPE / BIT / Extract bitfield.
// XTYPE / BIT / Masked parity.
// XTYPE / BIT / Bit reverse.
// XTYPE / BIT / Split bitfield.
/********************************************************************
* XTYPE/COMPLEX *
*********************************************************************/
// XTYPE / COMPLEX / Complex add/sub halfwords.
// XTYPE / COMPLEX / Complex add/sub words.
// XTYPE / COMPLEX / Complex multiply 32x16.
// XTYPE / COMPLEX / Vector reduce complex rotate.
/********************************************************************
* XTYPE/MPY *
*********************************************************************/
// XTYPE / COMPLEX / Complex add/sub halfwords.

View File

@ -0,0 +1,36 @@
//===-- HexagonMCAsmInfo.cpp - Hexagon asm properties -----------*- 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 declarations of the HexagonMCAsmInfo properties.
//
//===----------------------------------------------------------------------===//
#include "HexagonMCAsmInfo.h"
using namespace llvm;
HexagonMCAsmInfo::HexagonMCAsmInfo(const Target &T, StringRef TT) {
Data16bitsDirective = "\t.half\t";
Data32bitsDirective = "\t.word\t";
Data64bitsDirective = 0; // .xword is only supported by V9.
ZeroDirective = "\t.skip\t";
CommentString = "//";
HasLEB128 = true;
PrivateGlobalPrefix = ".L";
LCOMMDirectiveType = LCOMM::ByteAlignment;
InlineAsmStart = "# InlineAsm Start";
InlineAsmEnd = "# InlineAsm End";
ZeroDirective = "\t.space\t";
AscizDirective = "\t.string\t";
WeakRefDirective = "\t.weak\t";
UsesELFSectionDirectiveForBSS = true;
ExceptionsType = ExceptionHandling::DwarfCFI;
}

View File

@ -0,0 +1,30 @@
//===-- HexagonTargetAsmInfo.h - Hexagon asm properties ---------*- 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 declaration of the HexagonMCAsmInfo class.
//
//===----------------------------------------------------------------------===//
#ifndef HexagonMCASMINFO_H
#define HexagonMCASMINFO_H
#include "llvm/ADT/StringRef.h"
#include "llvm/MC/MCAsmInfo.h"
namespace llvm {
class Target;
class HexagonMCAsmInfo : public MCAsmInfo {
public:
explicit HexagonMCAsmInfo(const Target &T, StringRef TT);
};
} // namespace llvm
#endif

View File

@ -0,0 +1,75 @@
//=- HexagonMachineFuctionInfo.h - Hexagon machine function info --*- C++ -*-=//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef HexagonMACHINEFUNCTIONINFO_H
#define HexagonMACHINEFUNCTIONINFO_H
#include "llvm/CodeGen/MachineFunction.h"
namespace llvm {
namespace Hexagon {
const unsigned int StartPacket = 0x1;
const unsigned int EndPacket = 0x2;
}
/// Hexagon target-specific information for each MachineFunction.
class HexagonMachineFunctionInfo : public MachineFunctionInfo {
// SRetReturnReg - Some subtargets require that sret lowering includes
// returning the value of the returned struct in a register. This field
// holds the virtual register into which the sret argument is passed.
unsigned SRetReturnReg;
std::vector<MachineInstr*> AllocaAdjustInsts;
int VarArgsFrameIndex;
bool HasClobberLR;
std::map<const MachineInstr*, unsigned> PacketInfo;
public:
HexagonMachineFunctionInfo() : SRetReturnReg(0), HasClobberLR(0) {}
HexagonMachineFunctionInfo(MachineFunction &MF) : SRetReturnReg(0),
HasClobberLR(0) {}
unsigned getSRetReturnReg() const { return SRetReturnReg; }
void setSRetReturnReg(unsigned Reg) { SRetReturnReg = Reg; }
void addAllocaAdjustInst(MachineInstr* MI) {
AllocaAdjustInsts.push_back(MI);
}
const std::vector<MachineInstr*>& getAllocaAdjustInsts() {
return AllocaAdjustInsts;
}
void setVarArgsFrameIndex(int v) { VarArgsFrameIndex = v; }
int getVarArgsFrameIndex() { return VarArgsFrameIndex; }
void setStartPacket(MachineInstr* MI) {
PacketInfo[MI] |= Hexagon::StartPacket;
}
void setEndPacket(MachineInstr* MI) {
PacketInfo[MI] |= Hexagon::EndPacket;
}
bool isStartPacket(const MachineInstr* MI) const {
return (PacketInfo.count(MI) &&
(PacketInfo.find(MI)->second & Hexagon::StartPacket));
}
bool isEndPacket(const MachineInstr* MI) const {
return (PacketInfo.count(MI) &&
(PacketInfo.find(MI)->second & Hexagon::EndPacket));
}
void setHasClobberLR(bool v) { HasClobberLR = v; }
bool hasClobberLR() const { return HasClobberLR; }
};
} // End llvm namespace
#endif

View File

@ -0,0 +1,129 @@
//===-- HexagonOptimizeSZExtends.cpp - Identify and remove sign and -------===//
//===-- zero extends. -------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "llvm/Constants.h"
#include "llvm/PassSupport.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/Support/Debug.h"
#include "llvm/CodeGen/MachineFunctionAnalysis.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetInstrInfo.h"
#include <algorithm>
#include "Hexagon.h"
#include "HexagonTargetMachine.h"
using namespace llvm;
namespace {
struct HexagonOptimizeSZExtends : public MachineFunctionPass {
public:
static char ID;
HexagonOptimizeSZExtends() : MachineFunctionPass(ID) {}
bool runOnMachineFunction(MachineFunction &MF);
const char *getPassName() const {
return "Hexagon remove redundant zero and size extends";
}
void getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<MachineFunctionAnalysis>();
AU.addPreserved<MachineFunctionAnalysis>();
MachineFunctionPass::getAnalysisUsage(AU);
}
private:
};
}
char HexagonOptimizeSZExtends::ID = 0;
// This is a brain dead pass to get rid of redundant sign extends for the
// following case:
//
// Transform the following pattern
// %vreg170<def> = SXTW %vreg166
// ...
// %vreg176<def> = COPY %vreg170:subreg_loreg
//
// Into
// %vreg176<def> = COPY vreg166
bool HexagonOptimizeSZExtends::runOnMachineFunction(MachineFunction &MF) {
DenseMap<unsigned, unsigned> SExtMap;
// Loop over all of the basic blocks
for (MachineFunction::iterator MBBb = MF.begin(), MBBe = MF.end();
MBBb != MBBe; ++MBBb) {
MachineBasicBlock* MBB = MBBb;
SExtMap.clear();
// Traverse the basic block.
for (MachineBasicBlock::iterator MII = MBB->begin(); MII != MBB->end();
++MII) {
MachineInstr *MI = MII;
// Look for sign extends:
// %vreg170<def> = SXTW %vreg166
if (MI->getOpcode() == Hexagon::SXTW) {
assert (MI->getNumOperands() == 2);
MachineOperand &Dst = MI->getOperand(0);
MachineOperand &Src = MI->getOperand(1);
unsigned DstReg = Dst.getReg();
unsigned SrcReg = Src.getReg();
// Just handle virtual registers.
if (TargetRegisterInfo::isVirtualRegister(DstReg) &&
TargetRegisterInfo::isVirtualRegister(SrcReg)) {
// Map the following:
// %vreg170<def> = SXTW %vreg166
// SExtMap[170] = vreg166
SExtMap[DstReg] = SrcReg;
}
}
// Look for copy:
// %vreg176<def> = COPY %vreg170:subreg_loreg
if (MI->isCopy()) {
assert (MI->getNumOperands() == 2);
MachineOperand &Dst = MI->getOperand(0);
MachineOperand &Src = MI->getOperand(1);
// Make sure we are copying the lower 32 bits.
if (Src.getSubReg() != Hexagon::subreg_loreg)
continue;
unsigned DstReg = Dst.getReg();
unsigned SrcReg = Src.getReg();
if (TargetRegisterInfo::isVirtualRegister(DstReg) &&
TargetRegisterInfo::isVirtualRegister(SrcReg)) {
// Try to find in the map.
if (unsigned SextSrc = SExtMap.lookup(SrcReg)) {
// Change the 1st operand.
MI->RemoveOperand(1);
MI->addOperand(MachineOperand::CreateReg(SextSrc, false));
}
}
}
}
}
return true;
}
FunctionPass *llvm::createHexagonOptimizeSZExtends() {
return new HexagonOptimizeSZExtends();
}

View File

@ -0,0 +1,322 @@
//==- HexagonRegisterInfo.cpp - Hexagon Register Information -----*- 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 Hexagon implementation of the TargetRegisterInfo
// class.
//
//===----------------------------------------------------------------------===//
#include "Hexagon.h"
#include "HexagonRegisterInfo.h"
#include "HexagonSubtarget.h"
#include "HexagonTargetMachine.h"
#include "HexagonMachineFunctionInfo.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/RegisterScavenging.h"
#include "llvm/MC/MachineLocation.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Type.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include <iostream>
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/Function.h"
using namespace llvm;
HexagonRegisterInfo::HexagonRegisterInfo(HexagonSubtarget &st,
const HexagonInstrInfo &tii)
: HexagonGenRegisterInfo(Hexagon::R31),
Subtarget(st),
TII(tii) {
}
const unsigned* HexagonRegisterInfo::getCalleeSavedRegs(const MachineFunction
*MF)
const {
static const unsigned CalleeSavedRegsV2[] = {
Hexagon::R24, Hexagon::R25, Hexagon::R26, Hexagon::R27, 0
};
static const unsigned CalleeSavedRegsV3[] = {
Hexagon::R16, Hexagon::R17, Hexagon::R18, Hexagon::R19,
Hexagon::R20, Hexagon::R21, Hexagon::R22, Hexagon::R23,
Hexagon::R24, Hexagon::R25, Hexagon::R26, Hexagon::R27, 0
};
switch(Subtarget.getHexagonArchVersion()) {
case HexagonSubtarget::V2:
return CalleeSavedRegsV2;
break;
case HexagonSubtarget::V3:
case HexagonSubtarget::V4:
return CalleeSavedRegsV3;
break;
default:
const char *ErrorString =
"Callee saved registers requested for unknown archtecture version";
llvm_unreachable(ErrorString);
}
}
BitVector HexagonRegisterInfo::getReservedRegs(const MachineFunction &MF)
const {
BitVector Reserved(getNumRegs());
Reserved.set(HEXAGON_RESERVED_REG_1);
Reserved.set(HEXAGON_RESERVED_REG_2);
Reserved.set(Hexagon::R29);
Reserved.set(Hexagon::R30);
Reserved.set(Hexagon::R31);
Reserved.set(Hexagon::D14);
Reserved.set(Hexagon::D15);
Reserved.set(Hexagon::LC0);
Reserved.set(Hexagon::LC1);
Reserved.set(Hexagon::SA0);
Reserved.set(Hexagon::SA1);
return Reserved;
}
const TargetRegisterClass* const*
HexagonRegisterInfo::getCalleeSavedRegClasses(const MachineFunction *MF) const {
static const TargetRegisterClass * const CalleeSavedRegClassesV2[] = {
&Hexagon::IntRegsRegClass, &Hexagon::IntRegsRegClass,
&Hexagon::IntRegsRegClass, &Hexagon::IntRegsRegClass,
};
static const TargetRegisterClass * const CalleeSavedRegClassesV3[] = {
&Hexagon::IntRegsRegClass, &Hexagon::IntRegsRegClass,
&Hexagon::IntRegsRegClass, &Hexagon::IntRegsRegClass,
&Hexagon::IntRegsRegClass, &Hexagon::IntRegsRegClass,
&Hexagon::IntRegsRegClass, &Hexagon::IntRegsRegClass,
&Hexagon::IntRegsRegClass, &Hexagon::IntRegsRegClass,
&Hexagon::IntRegsRegClass, &Hexagon::IntRegsRegClass,
};
switch(Subtarget.getHexagonArchVersion()) {
case HexagonSubtarget::V2:
return CalleeSavedRegClassesV2;
break;
case HexagonSubtarget::V3:
case HexagonSubtarget::V4:
return CalleeSavedRegClassesV3;
break;
default:
const char *ErrorString =
"Callee saved register classes requested for unknown archtecture version";
llvm_unreachable(ErrorString);
}
}
void HexagonRegisterInfo::
eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const {
MachineInstr &MI = *I;
if (MI.getOpcode() == Hexagon::ADJCALLSTACKDOWN) {
// Hexagon_TODO: add code
} else if (MI.getOpcode() == Hexagon::ADJCALLSTACKUP) {
// Hexagon_TODO: add code
} else {
assert(0 && "Cannot handle this call frame pseudo instruction");
}
MBB.erase(I);
}
void HexagonRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
int SPAdj, RegScavenger *RS) const {
//
// Hexagon_TODO: Do we need to enforce this for Hexagon?
assert(SPAdj == 0 && "Unexpected");
unsigned i = 0;
MachineInstr &MI = *II;
while (!MI.getOperand(i).isFI()) {
++i;
assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!");
}
int FrameIndex = MI.getOperand(i).getIndex();
// Addressable stack objects are accessed using neg. offsets from %fp.
MachineFunction &MF = *MI.getParent()->getParent();
int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex);
MachineFrameInfo &MFI = *MF.getFrameInfo();
unsigned FrameReg = getFrameRegister(MF);
const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering();
if (!TFI->hasFP(MF)) {
// We will not reserve space on the stack for the lr and fp registers.
Offset -= 2 * Hexagon_WordSize;
}
const unsigned FrameSize = MFI.getStackSize();
if (!MFI.hasVarSizedObjects() &&
TII.isValidOffset(MI.getOpcode(), (FrameSize+Offset)) &&
!TII.isSpillPredRegOp(&MI)) {
// Replace frame index with a stack pointer reference.
MI.getOperand(i).ChangeToRegister(getStackRegister(), false, false, true);
MI.getOperand(i+1).ChangeToImmediate(FrameSize+Offset);
} else {
// Replace frame index with a frame pointer reference.
if (!TII.isValidOffset(MI.getOpcode(), Offset)) {
// If the offset overflows, then correct it.
//
// For loads, we do not need a reserved register
// r0 = memw(r30 + #10000) to:
//
// r0 = add(r30, #10000)
// r0 = memw(r0)
if ( (MI.getOpcode() == Hexagon::LDriw) ||
(MI.getOpcode() == Hexagon::LDrid) ||
(MI.getOpcode() == Hexagon::LDrih) ||
(MI.getOpcode() == Hexagon::LDriuh) ||
(MI.getOpcode() == Hexagon::LDrib) ||
(MI.getOpcode() == Hexagon::LDriub) ) {
unsigned dstReg = (MI.getOpcode() == Hexagon::LDrid) ?
*getSubRegisters(MI.getOperand(0).getReg()) :
MI.getOperand(0).getReg();
// Check if offset can fit in addi.
if (!TII.isValidOffset(Hexagon::ADD_ri, Offset)) {
BuildMI(*MI.getParent(), II, MI.getDebugLoc(),
TII.get(Hexagon::CONST32_Int_Real), dstReg).addImm(Offset);
BuildMI(*MI.getParent(), II, MI.getDebugLoc(),
TII.get(Hexagon::ADD_rr),
dstReg).addReg(FrameReg).addReg(dstReg);
} else {
BuildMI(*MI.getParent(), II, MI.getDebugLoc(),
TII.get(Hexagon::ADD_ri),
dstReg).addReg(FrameReg).addImm(Offset);
}
MI.getOperand(i).ChangeToRegister(dstReg, false, false, true);
MI.getOperand(i+1).ChangeToImmediate(0);
} else if ((MI.getOpcode() == Hexagon::STriw) ||
(MI.getOpcode() == Hexagon::STrid) ||
(MI.getOpcode() == Hexagon::STrih) ||
(MI.getOpcode() == Hexagon::STrib) ||
(MI.getOpcode() == Hexagon::STriwt)) {
// For stores, we need a reserved register. Change
// memw(r30 + #10000) = r0 to:
//
// rs = add(r30, #10000);
// memw(rs) = r0
unsigned resReg = HEXAGON_RESERVED_REG_1;
// Check if offset can fit in addi.
if (!TII.isValidOffset(Hexagon::ADD_ri, Offset)) {
BuildMI(*MI.getParent(), II, MI.getDebugLoc(),
TII.get(Hexagon::CONST32_Int_Real), resReg).addImm(Offset);
BuildMI(*MI.getParent(), II, MI.getDebugLoc(),
TII.get(Hexagon::ADD_rr),
resReg).addReg(FrameReg).addReg(resReg);
} else {
BuildMI(*MI.getParent(), II, MI.getDebugLoc(),
TII.get(Hexagon::ADD_ri),
resReg).addReg(FrameReg).addImm(Offset);
}
MI.getOperand(i).ChangeToRegister(resReg, false, false, true);
MI.getOperand(i+1).ChangeToImmediate(0);
} else if (TII.isMemOp(&MI)) {
unsigned resReg = HEXAGON_RESERVED_REG_1;
if (!MFI.hasVarSizedObjects() &&
TII.isValidOffset(MI.getOpcode(), (FrameSize+Offset))) {
MI.getOperand(i).ChangeToRegister(getStackRegister(), false, false,
true);
MI.getOperand(i+1).ChangeToImmediate(FrameSize+Offset);
} else if (!TII.isValidOffset(Hexagon::ADD_ri, Offset)) {
BuildMI(*MI.getParent(), II, MI.getDebugLoc(),
TII.get(Hexagon::CONST32_Int_Real), resReg).addImm(Offset);
BuildMI(*MI.getParent(), II, MI.getDebugLoc(),
TII.get(Hexagon::ADD_rr),
resReg).addReg(FrameReg).addReg(resReg);
MI.getOperand(i).ChangeToRegister(resReg, false, false, true);
MI.getOperand(i+1).ChangeToImmediate(0);
} else {
BuildMI(*MI.getParent(), II, MI.getDebugLoc(),
TII.get(Hexagon::ADD_ri),
resReg).addReg(FrameReg).addImm(Offset);
MI.getOperand(i).ChangeToRegister(resReg, false, false, true);
MI.getOperand(i+1).ChangeToImmediate(0);
}
} else {
unsigned dstReg = MI.getOperand(0).getReg();
BuildMI(*MI.getParent(), II, MI.getDebugLoc(),
TII.get(Hexagon::CONST32_Int_Real), dstReg).addImm(Offset);
BuildMI(*MI.getParent(), II, MI.getDebugLoc(),
TII.get(Hexagon::ADD_rr),
dstReg).addReg(FrameReg).addReg(dstReg);
// Can we delete MI??? r2 = add (r2, #0).
MI.getOperand(i).ChangeToRegister(dstReg, false, false, true);
MI.getOperand(i+1).ChangeToImmediate(0);
}
} else {
// If the offset is small enough to fit in the immediate field, directly
// encode it.
MI.getOperand(i).ChangeToRegister(FrameReg, false);
MI.getOperand(i+1).ChangeToImmediate(Offset);
}
}
}
unsigned HexagonRegisterInfo::getRARegister() const {
return Hexagon::R31;
}
unsigned HexagonRegisterInfo::getFrameRegister(const MachineFunction
&MF) const {
const TargetFrameLowering *TFI = MF.getTarget().getFrameLowering();
if (TFI->hasFP(MF)) {
return Hexagon::R30;
}
return Hexagon::R29;
}
unsigned HexagonRegisterInfo::getFrameRegister() const {
return Hexagon::R30;
}
unsigned HexagonRegisterInfo::getStackRegister() const {
return Hexagon::R29;
}
void HexagonRegisterInfo::getInitialFrameState(std::vector<MachineMove>
&Moves) const
{
// VirtualFP = (R30 + #0).
unsigned FPReg = getFrameRegister();
MachineLocation Dst(MachineLocation::VirtualFP);
MachineLocation Src(FPReg, 0);
Moves.push_back(MachineMove(0, Dst, Src));
}
unsigned HexagonRegisterInfo::getEHExceptionRegister() const {
assert(0 && "What is the exception register");
return 0;
}
unsigned HexagonRegisterInfo::getEHHandlerRegister() const {
assert(0 && "What is the exception handler register");
return 0;
}
#include "HexagonGenRegisterInfo.inc"

View File

@ -0,0 +1,89 @@
//==- HexagonRegisterInfo.h - Hexagon Register Information Impl --*- 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 Hexagon implementation of the TargetRegisterInfo
// class.
//
//===----------------------------------------------------------------------===//
#ifndef HexagonREGISTERINFO_H
#define HexagonREGISTERINFO_H
#include "llvm/Target/TargetRegisterInfo.h"
#define GET_REGINFO_HEADER
#include "HexagonGenRegisterInfo.inc"
#include "llvm/MC/MachineLocation.h"
//
// We try not to hard code the reserved registers in our code,
// so the following two macros were defined. However, there
// are still a few places that R11 and R10 are hard wired.
// See below. If, in the future, we decided to change the reserved
// register. Don't forget changing the following places.
//
// 1. the "Defs" set of STriw_pred in HexagonInstrInfo.td
// 2. the "Defs" set of LDri_pred in HexagonInstrInfo.td
// 3. the definition of "IntRegs" in HexagonRegisterInfo.td
// 4. the definition of "DoubleRegs" in HexagonRegisterInfo.td
//
#define HEXAGON_RESERVED_REG_1 Hexagon::R10
#define HEXAGON_RESERVED_REG_2 Hexagon::R11
namespace llvm {
class HexagonSubtarget;
class HexagonInstrInfo;
class Type;
struct HexagonRegisterInfo : public HexagonGenRegisterInfo {
HexagonSubtarget &Subtarget;
const HexagonInstrInfo &TII;
HexagonRegisterInfo(HexagonSubtarget &st, const HexagonInstrInfo &tii);
/// Code Generation virtual methods...
const unsigned *getCalleeSavedRegs(const MachineFunction *MF = 0) const;
const TargetRegisterClass* const* getCalleeSavedRegClasses(
const MachineFunction *MF = 0) const;
BitVector getReservedRegs(const MachineFunction &MF) const;
void eliminateCallFramePseudoInstr(MachineFunction &MF,
MachineBasicBlock &MBB,
MachineBasicBlock::iterator I) const;
void eliminateFrameIndex(MachineBasicBlock::iterator II,
int SPAdj, RegScavenger *RS = NULL) const;
/// determineFrameLayout - Determine the size of the frame and maximum call
/// frame size.
void determineFrameLayout(MachineFunction &MF) const;
/// requiresRegisterScavenging - returns true since we may need scavenging for
/// a temporary register when generating hardware loop instructions.
bool requiresRegisterScavenging(const MachineFunction &MF) const {
return true;
}
// Debug information queries.
unsigned getRARegister() const;
unsigned getFrameRegister(const MachineFunction &MF) const;
unsigned getFrameRegister() const;
void getInitialFrameState(std::vector<MachineMove> &Moves) const;
unsigned getStackRegister() const;
// Exception handling queries.
unsigned getEHExceptionRegister() const;
unsigned getEHHandlerRegister() const;
};
} // end namespace llvm
#endif

View File

@ -0,0 +1,169 @@
//===- HexagonRegisterInfo.td - Hexagon Register defs ------*- tablegen -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// Declarations that describe the Hexagon register file.
//===----------------------------------------------------------------------===//
class HexagonReg<string n> : Register<n> {
field bits<5> Num;
let Namespace = "Hexagon";
}
class HexagonDoubleReg<string n, list<Register> subregs> :
RegisterWithSubRegs<n, subregs> {
field bits<5> Num;
let Namespace = "Hexagon";
}
// Registers are identified with 5-bit ID numbers.
// Ri - 32-bit integer registers.
class Ri<bits<5> num, string n> : HexagonReg<n> {
let Num = num;
}
// Rf - 32-bit floating-point registers.
class Rf<bits<5> num, string n> : HexagonReg<n> {
let Num = num;
}
// Rd - 64 bit registers.
class Rd<bits<5> num, string n, list<Register> subregs> :
HexagonDoubleReg<n, subregs> {
let Num = num;
let SubRegs = subregs;
}
class Rp<bits<5> num, string n> : HexagonReg<n> {
let Num = num;
}
class Rc<bits<5> num, string n> : HexagonReg<n> {
let Num = num;
}
let Namespace = "Hexagon" in {
def subreg_loreg : SubRegIndex;
def subreg_hireg : SubRegIndex;
// Integer registers.
def R0 : Ri< 0, "r0">, DwarfRegNum<[0]>;
def R1 : Ri< 1, "r1">, DwarfRegNum<[1]>;
def R2 : Ri< 2, "r2">, DwarfRegNum<[2]>;
def R3 : Ri< 3, "r3">, DwarfRegNum<[3]>;
def R4 : Ri< 4, "r4">, DwarfRegNum<[4]>;
def R5 : Ri< 5, "r5">, DwarfRegNum<[5]>;
def R6 : Ri< 6, "r6">, DwarfRegNum<[6]>;
def R7 : Ri< 7, "r7">, DwarfRegNum<[7]>;
def R8 : Ri< 8, "r8">, DwarfRegNum<[8]>;
def R9 : Ri< 9, "r9">, DwarfRegNum<[9]>;
def R10 : Ri<10, "r10">, DwarfRegNum<[10]>;
def R11 : Ri<11, "r11">, DwarfRegNum<[11]>;
def R12 : Ri<12, "r12">, DwarfRegNum<[12]>;
def R13 : Ri<13, "r13">, DwarfRegNum<[13]>;
def R14 : Ri<14, "r14">, DwarfRegNum<[14]>;
def R15 : Ri<15, "r15">, DwarfRegNum<[15]>;
def R16 : Ri<16, "r16">, DwarfRegNum<[16]>;
def R17 : Ri<17, "r17">, DwarfRegNum<[17]>;
def R18 : Ri<18, "r18">, DwarfRegNum<[18]>;
def R19 : Ri<19, "r19">, DwarfRegNum<[19]>;
def R20 : Ri<20, "r20">, DwarfRegNum<[20]>;
def R21 : Ri<21, "r21">, DwarfRegNum<[21]>;
def R22 : Ri<22, "r22">, DwarfRegNum<[22]>;
def R23 : Ri<23, "r23">, DwarfRegNum<[23]>;
def R24 : Ri<24, "r24">, DwarfRegNum<[24]>;
def R25 : Ri<25, "r25">, DwarfRegNum<[25]>;
def R26 : Ri<26, "r26">, DwarfRegNum<[26]>;
def R27 : Ri<27, "r27">, DwarfRegNum<[27]>;
def R28 : Ri<28, "r28">, DwarfRegNum<[28]>;
def R29 : Ri<29, "r29">, DwarfRegNum<[29]>;
def R30 : Ri<30, "r30">, DwarfRegNum<[30]>;
def R31 : Ri<31, "r31">, DwarfRegNum<[31]>;
def PC : Ri<31, "r31">, DwarfRegNum<[32]>;
def GP : Ri<31, "r31">, DwarfRegNum<[33]>;
// Aliases of the R* registers used to hold 64-bit int values (doubles).
let SubRegIndices = [subreg_loreg, subreg_hireg] in {
def D0 : Rd< 0, "r1:0", [R0, R1]>, DwarfRegNum<[32]>;
def D1 : Rd< 2, "r3:2", [R2, R3]>, DwarfRegNum<[34]>;
def D2 : Rd< 4, "r5:4", [R4, R5]>, DwarfRegNum<[36]>;
def D3 : Rd< 6, "r7:6", [R6, R7]>, DwarfRegNum<[38]>;
def D4 : Rd< 8, "r9:8", [R8, R9]>, DwarfRegNum<[40]>;
def D5 : Rd<10, "r11:10", [R10, R11]>, DwarfRegNum<[42]>;
def D6 : Rd<12, "r13:12", [R12, R13]>, DwarfRegNum<[44]>;
def D7 : Rd<14, "r15:14", [R14, R15]>, DwarfRegNum<[46]>;
def D8 : Rd<16, "r17:16", [R16, R17]>, DwarfRegNum<[48]>;
def D9 : Rd<18, "r19:18", [R18, R19]>, DwarfRegNum<[50]>;
def D10 : Rd<20, "r21:20", [R20, R21]>, DwarfRegNum<[52]>;
def D11 : Rd<22, "r23:22", [R22, R23]>, DwarfRegNum<[54]>;
def D12 : Rd<24, "r25:24", [R24, R25]>, DwarfRegNum<[56]>;
def D13 : Rd<26, "r27:26", [R26, R27]>, DwarfRegNum<[58]>;
def D14 : Rd<28, "r29:28", [R28, R29]>, DwarfRegNum<[60]>;
def D15 : Rd<30, "r31:30", [R30, R31]>, DwarfRegNum<[62]>;
}
// Predicate registers.
def P0 : Rp< 0, "p0">, DwarfRegNum<[63]>;
def P1 : Rp< 0, "p1">, DwarfRegNum<[64]>;
def P2 : Rp< 0, "p2">, DwarfRegNum<[65]>;
def P3 : Rp< 0, "p3">, DwarfRegNum<[66]>;
// Control registers.
def SA0 : Rc<0, "sa0">, DwarfRegNum<[67]>;
def LC0 : Rc<0, "lc0">, DwarfRegNum<[68]>;
def SA1 : Rc<0, "sa1">, DwarfRegNum<[69]>;
def LC1 : Rc<0, "lc1">, DwarfRegNum<[70]>;
}
// Register classes.
//
// FIXME: the register order should be defined in terms of the preferred
// allocation order...
//
def IntRegs : RegisterClass<"Hexagon", [i32], 32, (add (sequence "R%u", 0, 9),
(sequence "R%u", 12, 28),
R10, R11, R29, R30,
R31)> {
}
def DoubleRegs : RegisterClass<"Hexagon", [i64], 64, (add (sequence "D%u", 0,
4),
(sequence "D%u", 6, 13),
D5, D14, D15)> {
let SubRegClasses = [(IntRegs subreg_loreg, subreg_hireg)];
}
def PredRegs : RegisterClass<"Hexagon", [i1], 32, (add (sequence "P%u", 0, 3))>
{
let Size = 32;
}
def CRRegs : RegisterClass<"Hexagon", [i32], 32, (add (sequence "LC%u", 0, 1),
(sequence "SA%u", 0, 1),
PC)> {
let Size = 32;
}

View File

@ -0,0 +1,85 @@
//=- HexagonRemoveExtendArgs.cpp - Remove unecessary argument sign extends --=//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Pass that removes sign extends for function parameters. These parameters
// are already sign extended by the caller per Hexagon's ABI
//
//===----------------------------------------------------------------------===//
#include "llvm/Pass.h"
#include "llvm/Function.h"
#include "llvm/Instructions.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/CodeGen/MachineFunctionAnalysis.h"
#include "HexagonTargetMachine.h"
#include <iostream>
using namespace llvm;
namespace {
struct HexagonRemoveExtendArgs : public FunctionPass {
public:
static char ID;
HexagonRemoveExtendArgs() : FunctionPass(ID) {}
virtual bool runOnFunction(Function &F);
const char *getPassName() const {
return "Remove sign extends";
}
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.addRequired<MachineFunctionAnalysis>();
AU.addPreserved<MachineFunctionAnalysis>();
FunctionPass::getAnalysisUsage(AU);
}
};
}
char HexagonRemoveExtendArgs::ID = 0;
RegisterPass<HexagonRemoveExtendArgs> X("reargs",
"Remove Sign and Zero Extends for Args"
);
bool HexagonRemoveExtendArgs::runOnFunction(Function &F) {
unsigned Idx = 1;
for (Function::arg_iterator AI = F.arg_begin(), AE = F.arg_end(); AI != AE;
++AI, ++Idx) {
if (F.paramHasAttr(Idx, Attribute::SExt)) {
Argument* Arg = AI;
if (!isa<PointerType>(Arg->getType())) {
for (Instruction::use_iterator UI = Arg->use_begin();
UI != Arg->use_end();) {
if (isa<SExtInst>(*UI)) {
Instruction* Use = cast<Instruction>(*UI);
SExtInst* SI = new SExtInst(Arg, Use->getType());
assert (EVT::getEVT(SI->getType()) ==
(EVT::getEVT(Use->getType())));
++UI;
Use->replaceAllUsesWith(SI);
Instruction* First = F.getEntryBlock().begin();
SI->insertBefore(First);
Use->eraseFromParent();
} else {
++UI;
}
}
}
}
}
return true;
}
FunctionPass *llvm::createHexagonRemoveExtendOps(HexagonTargetMachine &TM) {
return new HexagonRemoveExtendArgs();
}

View File

@ -0,0 +1,53 @@
//===-HexagonSchedule.td - Hexagon Scheduling Definitions -------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// Functional Units
def LUNIT : FuncUnit;
def LSUNIT : FuncUnit;
def MUNIT : FuncUnit;
def SUNIT : FuncUnit;
// Itinerary classes
def ALU32 : InstrItinClass;
def ALU64 : InstrItinClass;
def CR : InstrItinClass;
def J : InstrItinClass;
def JR : InstrItinClass;
def LD : InstrItinClass;
def M : InstrItinClass;
def ST : InstrItinClass;
def S : InstrItinClass;
def PSEUDO : InstrItinClass;
def HexagonItineraries :
ProcessorItineraries<[LUNIT, LSUNIT, MUNIT, SUNIT], [], [
InstrItinData<ALU32 , [InstrStage<1, [LUNIT, LSUNIT, MUNIT, SUNIT]>]>,
InstrItinData<ALU64 , [InstrStage<1, [MUNIT, SUNIT]>]>,
InstrItinData<CR , [InstrStage<1, [SUNIT]>]>,
InstrItinData<J , [InstrStage<1, [SUNIT, MUNIT]>]>,
InstrItinData<JR , [InstrStage<1, [MUNIT]>]>,
InstrItinData<LD , [InstrStage<1, [LUNIT, LSUNIT]>]>,
InstrItinData<M , [InstrStage<1, [MUNIT, SUNIT]>]>,
InstrItinData<ST , [InstrStage<1, [LSUNIT]>]>,
InstrItinData<S , [InstrStage<1, [SUNIT, MUNIT]>]>,
InstrItinData<PSEUDO , [InstrStage<1, [LUNIT, LSUNIT, MUNIT, SUNIT]>]>
]>;
//===----------------------------------------------------------------------===//
// V4 Machine Info +
//===----------------------------------------------------------------------===//
include "HexagonScheduleV4.td"
//===----------------------------------------------------------------------===//
// V4 Machine Info -
//===----------------------------------------------------------------------===//

View File

@ -0,0 +1,56 @@
//=-HexagonScheduleV4.td - HexagonV4 Scheduling Definitions --*- tablegen -*-=//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
// There are four SLOTS (four parallel pipelines) in Hexagon V4 machine.
// This file describes that machine information.
//
// |===========|==================================================|
// | PIPELINE | Instruction Classes |
// |===========|==================================================|
// | SLOT0 | LD ST ALU32 MEMOP NV SYSTEM |
// |-----------|--------------------------------------------------|
// | SLOT1 | LD ST ALU32 |
// |-----------|--------------------------------------------------|
// | SLOT2 | XTYPE ALU32 J JR |
// |-----------|--------------------------------------------------|
// | SLOT3 | XTYPE ALU32 J CR |
// |===========|==================================================|
// Functional Units.
def SLOT0 : FuncUnit;
def SLOT1 : FuncUnit;
def SLOT2 : FuncUnit;
def SLOT3 : FuncUnit;
// Itinerary classes.
def NV_V4 : InstrItinClass;
def MEM_V4 : InstrItinClass;
// ALU64/M/S Instruction classes of V2 are collectively knownn as XTYPE in V4.
def HexagonItinerariesV4 : ProcessorItineraries<
[SLOT0, SLOT1, SLOT2, SLOT3], [], [
InstrItinData<LD , [InstrStage<1, [SLOT0, SLOT1]>]>,
InstrItinData<ST , [InstrStage<1, [SLOT0, SLOT1]>]>,
InstrItinData<ALU32 , [InstrStage<1, [SLOT0, SLOT1, SLOT2, SLOT3]>]>,
InstrItinData<NV_V4 , [InstrStage<1, [SLOT0]>]>,
InstrItinData<MEM_V4 , [InstrStage<1, [SLOT0]>]>,
InstrItinData<J , [InstrStage<1, [SLOT2, SLOT3]>]>,
InstrItinData<JR , [InstrStage<1, [SLOT2]>]>,
InstrItinData<CR , [InstrStage<1, [SLOT3]>]>,
InstrItinData<PSEUDO , [InstrStage<1, [SLOT0, SLOT1, SLOT2, SLOT3]>]>,
InstrItinData<ALU64 , [InstrStage<1, [SLOT2, SLOT3]>]>,
InstrItinData<M , [InstrStage<1, [SLOT2, SLOT3]>]>,
InstrItinData<S , [InstrStage<1, [SLOT2, SLOT3]>]>
]>;
//===----------------------------------------------------------------------===//
// Hexagon V4 Resource Definitions -
//===----------------------------------------------------------------------===//

View File

@ -0,0 +1,121 @@
//=-HexagoSelectCCInfo.td - Selectcc mappings ----------------*- tablegen -*-=//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// selectcc mappings.
//
def : Pat <(i32 (selectcc IntRegs:$lhs, IntRegs:$rhs, IntRegs:$tval,
IntRegs:$fval, SETEQ)),
(i32 (MUX_rr (i1 (CMPEQrr IntRegs:$lhs, IntRegs:$rhs)),
IntRegs:$tval, IntRegs:$fval))>;
def : Pat <(i32 (selectcc IntRegs:$lhs, IntRegs:$rhs, IntRegs:$tval,
IntRegs:$fval, SETNE)),
(i32 (MUX_rr (i1 (NOT_Ps (CMPEQrr IntRegs:$lhs, IntRegs:$rhs))),
IntRegs:$tval, IntRegs:$fval))>;
def : Pat <(i32 (selectcc IntRegs:$lhs, IntRegs:$rhs, IntRegs:$tval,
IntRegs:$fval, SETGT)),
(i32 (MUX_rr (i1 (CMPGTrr IntRegs:$lhs, IntRegs:$rhs)),
IntRegs:$tval, IntRegs:$fval))>;
def : Pat <(i32 (selectcc IntRegs:$lhs, IntRegs:$rhs, IntRegs:$tval,
IntRegs:$fval, SETUGT)),
(i32 (MUX_rr (i1 (CMPGTUrr IntRegs:$lhs, IntRegs:$rhs)),
IntRegs:$tval, IntRegs:$fval))>;
def : Pat <(i32 (selectcc IntRegs:$lhs, IntRegs:$rhs, IntRegs:$tval,
IntRegs:$fval, SETULT)),
(i32 (MUX_rr (i1 (NOT_Ps (CMPGTUrr IntRegs:$lhs,
(ADD_ri IntRegs:$rhs, -1)))),
IntRegs:$tval, IntRegs:$fval))>;
def : Pat <(i32 (selectcc IntRegs:$lhs, IntRegs:$rhs, IntRegs:$tval,
IntRegs:$fval, SETLT)),
(i32 (MUX_rr (i1 (NOT_Ps (CMPGTrr IntRegs:$lhs,
(ADD_ri IntRegs:$rhs, -1)))),
IntRegs:$tval, IntRegs:$fval))>;
def : Pat <(i32 (selectcc IntRegs:$lhs, IntRegs:$rhs, IntRegs:$tval,
IntRegs:$fval, SETLE)),
(i32 (MUX_rr (i1 (NOT_Ps (CMPGTrr IntRegs:$lhs, IntRegs:$rhs))),
IntRegs:$tval, IntRegs:$fval))>;
def : Pat <(i32 (selectcc IntRegs:$lhs, IntRegs:$rhs, IntRegs:$tval,
IntRegs:$fval, SETULE)),
(i32 (MUX_rr (i1 (NOT_Ps (CMPGTUrr IntRegs:$lhs, IntRegs:$rhs))),
IntRegs:$tval, IntRegs:$fval))>;
//
// selectcc mappings for greater-equal-to Rs => greater-than Rs-1.
//
def : Pat <(i32 (selectcc IntRegs:$lhs, IntRegs:$rhs, IntRegs:$tval,
IntRegs:$fval, SETGE)),
(i32 (MUX_rr (i1 (CMPGTrr IntRegs:$lhs, (ADD_ri IntRegs:$rhs, -1))),
IntRegs:$tval, IntRegs:$fval))>;
def : Pat <(i32 (selectcc IntRegs:$lhs, IntRegs:$rhs, IntRegs:$tval,
IntRegs:$fval, SETUGE)),
(i32 (MUX_rr (i1 (CMPGTUrr IntRegs:$lhs, (ADD_ri IntRegs:$rhs, -1))),
IntRegs:$tval, IntRegs:$fval))>;
//
// selectcc mappings for predicate comparisons.
//
// Convert Rd = selectcc(p0, p1, true_val, false_val, SETEQ) into:
// pt = not(p1 xor p2)
// Rd = mux(pt, true_val, false_val)
// and similarly for SETNE
//
def : Pat <(i32 (selectcc PredRegs:$lhs, PredRegs:$rhs, IntRegs:$tval,
IntRegs:$fval, SETNE)),
(i32 (MUX_rr (i1 (XOR_pp PredRegs:$lhs, PredRegs:$rhs)), IntRegs:$tval,
IntRegs:$fval))>;
def : Pat <(i32 (selectcc PredRegs:$lhs, PredRegs:$rhs, IntRegs:$tval,
IntRegs:$fval, SETEQ)),
(i32 (MUX_rr (i1 (NOT_pp (XOR_pp PredRegs:$lhs, PredRegs:$rhs))),
IntRegs:$tval, IntRegs:$fval))>;
//
// selectcc mappings for 64-bit operands are messy. Hexagon does not have a
// MUX64 o, use this:
// selectcc(Rss, Rdd, tval, fval, cond) ->
// combine(mux(cmp_cond(Rss, Rdd), tval.hi, fval.hi),
// mux(cmp_cond(Rss, Rdd), tval.lo, fval.lo))
// setgt-64.
def : Pat<(i64 (selectcc DoubleRegs:$lhs, DoubleRegs:$rhs, DoubleRegs:$tval,
DoubleRegs:$fval, SETGT)),
(COMBINE_rr (MUX_rr (CMPGT64rr DoubleRegs:$lhs, DoubleRegs:$rhs),
(EXTRACT_SUBREG DoubleRegs:$tval, subreg_hireg),
(EXTRACT_SUBREG DoubleRegs:$fval, subreg_hireg)),
(MUX_rr (CMPGT64rr DoubleRegs:$lhs, DoubleRegs:$rhs),
(EXTRACT_SUBREG DoubleRegs:$tval, subreg_loreg),
(EXTRACT_SUBREG DoubleRegs:$fval, subreg_loreg)))>;
// setlt-64 -> setgt-64.
def : Pat<(i64 (selectcc DoubleRegs:$lhs, DoubleRegs:$rhs, DoubleRegs:$tval,
DoubleRegs:$fval, SETLT)),
(COMBINE_rr (MUX_rr (CMPGT64rr DoubleRegs:$lhs,
(ADD64_rr DoubleRegs:$rhs, (TFRI64 -1))),
(EXTRACT_SUBREG DoubleRegs:$tval, subreg_hireg),
(EXTRACT_SUBREG DoubleRegs:$fval, subreg_hireg)),
(MUX_rr (CMPGT64rr DoubleRegs:$lhs,
(ADD64_rr DoubleRegs:$rhs, (TFRI64 -1))),
(EXTRACT_SUBREG DoubleRegs:$tval, subreg_loreg),
(EXTRACT_SUBREG DoubleRegs:$fval, subreg_loreg)))>;

View File

@ -0,0 +1,46 @@
//===-- HexagonSelectionDAGInfo.cpp - Hexagon SelectionDAG Info -----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the HexagonSelectionDAGInfo class.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "hexagon-selectiondag-info"
#include "HexagonTargetMachine.h"
using namespace llvm;
bool llvm::flag_aligned_memcpy;
HexagonSelectionDAGInfo::HexagonSelectionDAGInfo(const HexagonTargetMachine
&TM)
: TargetSelectionDAGInfo(TM) {
}
HexagonSelectionDAGInfo::~HexagonSelectionDAGInfo() {
}
SDValue
HexagonSelectionDAGInfo::
EmitTargetCodeForMemcpy(SelectionDAG &DAG, DebugLoc dl, SDValue Chain,
SDValue Dst, SDValue Src, SDValue Size, unsigned Align,
bool isVolatile, bool AlwaysInline,
MachinePointerInfo DstPtrInfo,
MachinePointerInfo SrcPtrInfo) const {
flag_aligned_memcpy = false;
if ((Align & 0x3) == 0) {
ConstantSDNode *ConstantSize = dyn_cast<ConstantSDNode>(Size);
if (ConstantSize) {
uint64_t SizeVal = ConstantSize->getZExtValue();
if ((SizeVal > 32) && ((SizeVal % 8) == 0))
flag_aligned_memcpy = true;
}
}
return SDValue();
}

View File

@ -0,0 +1,40 @@
//=-- HexagonSelectionDAGInfo.h - Hexagon SelectionDAG Info ------*- C++ -*-=//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the Hexagon subclass for TargetSelectionDAGInfo.
//
//===----------------------------------------------------------------------===//
#ifndef HexagonSELECTIONDAGINFO_H
#define HexagonSELECTIONDAGINFO_H
#include "llvm/Target/TargetSelectionDAGInfo.h"
namespace llvm {
class HexagonTargetMachine;
class HexagonSelectionDAGInfo : public TargetSelectionDAGInfo {
public:
explicit HexagonSelectionDAGInfo(const HexagonTargetMachine &TM);
~HexagonSelectionDAGInfo();
virtual
SDValue EmitTargetCodeForMemcpy(SelectionDAG &DAG, DebugLoc dl,
SDValue Chain,
SDValue Dst, SDValue Src,
SDValue Size, unsigned Align,
bool isVolatile, bool AlwaysInline,
MachinePointerInfo DstPtrInfo,
MachinePointerInfo SrcPtrInfo) const;
};
}
#endif

View File

@ -0,0 +1,136 @@
//===---- HexagonSplitTFRCondSets.cpp - split TFR condsets into xfers -----===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//
//===----------------------------------------------------------------------===////
// This pass tries to provide opportunities for better optimization of muxes.
// The default code generated for something like: flag = (a == b) ? 1 : 3;
// would be:
//
// {p0 = cmp.eq(r0,r1)}
// {r3 = mux(p0,#1,#3)}
//
// This requires two packets. If we use .new predicated immediate transfers,
// then we can do this in a single packet, e.g.:
//
// {p0 = cmp.eq(r0,r1)
// if (p0.new) r3 = #1
// if (!p0.new) r3 = #3}
//
// Note that the conditional assignments are not generated in .new form here.
// We assume opptimisically that they will be formed later.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "xfer"
#include "llvm/CodeGen/Passes.h"
#include "llvm/CodeGen/LatencyPriorityQueue.h"
#include "llvm/CodeGen/SchedulerRegistry.h"
#include "llvm/CodeGen/MachineDominators.h"
#include "llvm/CodeGen/MachineFunctionPass.h"
#include "llvm/CodeGen/MachineLoopInfo.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/ScheduleHazardRecognizer.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetInstrInfo.h"
#include "llvm/Target/TargetRegisterInfo.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "HexagonTargetMachine.h"
#include "HexagonSubtarget.h"
#include "HexagonMachineFunctionInfo.h"
#include <map>
#include <iostream>
#include "llvm/Support/CommandLine.h"
#define DEBUG_TYPE "xfer"
using namespace llvm;
namespace {
class HexagonSplitTFRCondSets : public MachineFunctionPass {
HexagonTargetMachine& QTM;
const HexagonSubtarget &QST;
public:
static char ID;
HexagonSplitTFRCondSets(HexagonTargetMachine& TM) :
MachineFunctionPass(ID), QTM(TM), QST(*TM.getSubtargetImpl()) {}
const char *getPassName() const {
return "Hexagon Split TFRCondSets";
}
bool runOnMachineFunction(MachineFunction &Fn);
};
char HexagonSplitTFRCondSets::ID = 0;
bool HexagonSplitTFRCondSets::runOnMachineFunction(MachineFunction &Fn) {
const TargetInstrInfo *TII = QTM.getInstrInfo();
// 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.
for (MachineBasicBlock::iterator MII = MBB->begin(); MII != MBB->end();
++MII) {
MachineInstr *MI = MII;
int Opc = MI->getOpcode();
if (Opc == Hexagon::TFR_condset_rr) {
int DestReg = MI->getOperand(0).getReg();
int SrcReg1 = MI->getOperand(2).getReg();
int SrcReg2 = MI->getOperand(3).getReg();
// Minor optimization: do not emit the predicated copy if the source and
// the destination is the same register
if (DestReg != SrcReg1) {
BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::TFR_cPt),
DestReg).addReg(MI->getOperand(1).getReg()).addReg(SrcReg1);
}
if (DestReg != SrcReg2) {
BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::TFR_cNotPt),
DestReg).addReg(MI->getOperand(1).getReg()).addReg(SrcReg2);
}
MII = MBB->erase(MI);
--MII;
} else if (Opc == Hexagon::TFR_condset_ii) {
int DestReg = MI->getOperand(0).getReg();
int SrcReg1 = MI->getOperand(1).getReg();
int Immed1 = MI->getOperand(2).getImm();
int Immed2 = MI->getOperand(3).getImm();
BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::TFRI_cPt),
DestReg).addReg(SrcReg1).addImm(Immed1);
BuildMI(*MBB, MII, MI->getDebugLoc(), TII->get(Hexagon::TFRI_cNotPt),
DestReg).addReg(SrcReg1).addImm(Immed2);
MII = MBB->erase(MI);
--MII;
}
}
}
return true;
}
}
//===----------------------------------------------------------------------===//
// Public Constructor Functions
//===----------------------------------------------------------------------===//
FunctionPass *llvm::createHexagonSplitTFRCondSets(HexagonTargetMachine &TM) {
return new HexagonSplitTFRCondSets(TM);
}

View File

@ -0,0 +1,60 @@
//===- HexagonSubtarget.cpp - Hexagon Subtarget Information ---------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Hexagon specific subclass of TargetSubtarget.
//
//===----------------------------------------------------------------------===//
#include "HexagonSubtarget.h"
#include "Hexagon.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/ErrorHandling.h"
using namespace llvm;
#define GET_SUBTARGETINFO_MC_DESC
#define GET_SUBTARGETINFO_CTOR
#define GET_SUBTARGETINFO_TARGET_DESC
#include "HexagonGenSubtargetInfo.inc"
static cl::opt<bool>
EnableV3("enable-hexagon-v3", cl::Hidden,
cl::desc("Enable Hexagon V3 instructions."));
static cl::opt<bool>
EnableMemOps(
"enable-hexagon-memops",
cl::Hidden, cl::ZeroOrMore, cl::ValueDisallowed,
cl::desc("Generate V4 MEMOP in code generation for Hexagon target"));
HexagonSubtarget::HexagonSubtarget(StringRef TT, StringRef CPU, StringRef FS):
HexagonGenSubtargetInfo(TT, CPU, FS),
HexagonArchVersion(V1),
CPUString(CPU.str()) {
ParseSubtargetFeatures(CPU, FS);
switch(HexagonArchVersion) {
case HexagonSubtarget::V2:
break;
case HexagonSubtarget::V3:
EnableV3 = true;
break;
case HexagonSubtarget::V4:
break;
default:
llvm_unreachable("Unknown Architecture Version.");
}
// Initialize scheduling itinerary for the specified CPU.
InstrItins = getInstrItineraryForCPU(CPUString);
if (EnableMemOps)
UseMemOps = true;
else
UseMemOps = false;
}

View File

@ -0,0 +1,74 @@
//==-- HexagonSubtarget.h - Define Subtarget for the Hexagon ----*- C++ -*-==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file declares the Hexagon specific subclass of TargetSubtarget.
//
//===----------------------------------------------------------------------===//
#ifndef Hexagon_SUBTARGET_H
#define Hexagon_SUBTARGET_H
#include "llvm/Target/TargetSubtargetInfo.h"
#include "llvm/Target/TargetMachine.h"
#include <string>
#define GET_SUBTARGETINFO_HEADER
#include "HexagonGenSubtargetInfo.inc"
#define Hexagon_SMALL_DATA_THRESHOLD 8
namespace llvm {
class HexagonSubtarget : public HexagonGenSubtargetInfo {
bool UseMemOps;
public:
enum HexagonArchEnum {
V1, V2, V3, V4
};
HexagonArchEnum HexagonArchVersion;
std::string CPUString;
InstrItineraryData InstrItins;
public:
HexagonSubtarget(StringRef TT, StringRef CPU, StringRef FS);
/// getInstrItins - Return the instruction itineraies based on subtarget
/// selection.
const InstrItineraryData &getInstrItineraryData() const { return InstrItins; }
/// ParseSubtargetFeatures - Parses features string setting specified
/// subtarget options. Definition of function is auto generated by tblgen.
void ParseSubtargetFeatures(StringRef CPU, StringRef FS);
bool hasV2TOps () const { return HexagonArchVersion >= V2; }
bool hasV2TOpsOnly () const { return HexagonArchVersion == V2; }
bool hasV3TOps () const { return HexagonArchVersion >= V3; }
bool hasV3TOpsOnly () const { return HexagonArchVersion == V3; }
bool hasV4TOps () const { return HexagonArchVersion >= V4; }
bool useMemOps () const { return HexagonArchVersion >= V4 && UseMemOps; }
bool isSubtargetV2() const { return HexagonArchVersion == V2;}
const std::string &getCPUString () const { return CPUString; }
// Threshold for small data section
unsigned getSmallDataThreshold() const {
return Hexagon_SMALL_DATA_THRESHOLD;
}
const HexagonArchEnum &getHexagonArchVersion() const {
return HexagonArchVersion;
}
};
} // end namespace llvm
#endif

View File

@ -0,0 +1,128 @@
//===-- HexagonTargetMachine.cpp - Define TargetMachine for Hexagon -------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//
//===----------------------------------------------------------------------===//
#include "HexagonMCAsmInfo.h"
#include "HexagonTargetMachine.h"
#include "Hexagon.h"
#include "HexagonISelLowering.h"
#include "llvm/Module.h"
#include "llvm/CodeGen/Passes.h"
#include "llvm/PassManager.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Transforms/IPO/PassManagerBuilder.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Support/TargetRegistry.h"
#include <iostream>
#define GET_REGINFO_MC_DESC
#define GET_REGINFO_TARGET_DESC
#include "HexagonGenRegisterInfo.inc"
extern "C" void LLVMInitializeHexagonTargetMC() {}
using namespace llvm;
static cl::
opt<bool> DisableHardwareLoops(
"disable-hexagon-hwloops", cl::Hidden,
cl::desc("Disable Hardware Loops for Hexagon target"));
/// HexagonTargetMachineModule - Note that this is used on hosts that
/// cannot link in a library unless there are references into the
/// library. In particular, it seems that it is not possible to get
/// things to work on Win32 without this. Though it is unused, do not
/// remove it.
extern "C" int HexagonTargetMachineModule;
int HexagonTargetMachineModule = 0;
extern "C" void LLVMInitializeHexagonTarget() {
// Register the target.
RegisterTargetMachine<HexagonTargetMachine> X(TheHexagonTarget);
// Register the target asm info.
RegisterMCAsmInfo<HexagonMCAsmInfo> A(TheHexagonTarget);
}
/// HexagonTargetMachine ctor - Create an ILP32 architecture model.
///
/// Hexagon_TODO: Do I need an aggregate alignment?
///
HexagonTargetMachine::HexagonTargetMachine(const Target &T, StringRef TT,
StringRef CPU, StringRef FS,
TargetOptions Options,
Reloc::Model RM,
CodeModel::Model CM,
CodeGenOpt::Level OL)
: LLVMTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL),
DataLayout("e-p:32:32:32-i64:64:64-i32:32:32-i16:16:16-i1:32:32-a0:0") ,
Subtarget(TT, CPU, FS), TLInfo(*this), InstrInfo(Subtarget),
TSInfo(*this),
FrameLowering(Subtarget),
InstrItins(&Subtarget.getInstrItineraryData()) {
setMCUseCFI(false);
}
// addPassesForOptimizations - Allow the backend (target) to add Target
// Independent Optimization passes to the Pass Manager.
bool HexagonTargetMachine::addPassesForOptimizations(PassManagerBase &PM) {
PM.add(createConstantPropagationPass());
PM.add(createLoopSimplifyPass());
PM.add(createDeadCodeEliminationPass());
PM.add(createConstantPropagationPass());
PM.add(createLoopUnrollPass());
PM.add(createLoopStrengthReducePass(getTargetLowering()));
return true;
}
bool HexagonTargetMachine::addInstSelector(PassManagerBase &PM) {
PM.add(createHexagonRemoveExtendOps(*this));
PM.add(createHexagonISelDag(*this));
return false;
}
bool HexagonTargetMachine::addPreRegAlloc(PassManagerBase &PM) {
if (!DisableHardwareLoops) {
PM.add(createHexagonHardwareLoops());
}
return false;
}
bool HexagonTargetMachine::addPostRegAlloc(PassManagerBase &PM) {
PM.add(createHexagonCFGOptimizer(*this));
return true;
}
bool HexagonTargetMachine::addPreSched2(PassManagerBase &PM) {
PM.add(createIfConverterPass());
return true;
}
bool HexagonTargetMachine::addPreEmitPass(PassManagerBase &PM) {
if (!DisableHardwareLoops) {
PM.add(createHexagonFixupHwLoops());
}
// Expand Spill code for predicate registers.
PM.add(createHexagonExpandPredSpillCode(*this));
// Split up TFRcondsets into conditional transfers.
PM.add(createHexagonSplitTFRCondSets(*this));
return false;
}

View File

@ -0,0 +1,86 @@
//=-- HexagonTargetMachine.h - Define TargetMachine for Hexagon ---*- C++ -*-=//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file declares the Hexagon specific subclass of TargetMachine.
//
//===----------------------------------------------------------------------===//
#ifndef HexagonTARGETMACHINE_H
#define HexagonTARGETMACHINE_H
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetData.h"
#include "HexagonInstrInfo.h"
#include "HexagonSubtarget.h"
#include "HexagonISelLowering.h"
#include "HexagonSelectionDAGInfo.h"
#include "HexagonFrameLowering.h"
namespace llvm {
class Module;
class HexagonTargetMachine : public LLVMTargetMachine {
const TargetData DataLayout; // Calculates type size & alignment.
HexagonSubtarget Subtarget;
HexagonTargetLowering TLInfo;
HexagonInstrInfo InstrInfo;
HexagonSelectionDAGInfo TSInfo;
HexagonFrameLowering FrameLowering;
const InstrItineraryData* InstrItins;
public:
HexagonTargetMachine(const Target &T, StringRef TT,StringRef CPU,
StringRef FS, TargetOptions Options, Reloc::Model RM,
CodeModel::Model CM, CodeGenOpt::Level OL);
virtual const HexagonInstrInfo *getInstrInfo() const {
return &InstrInfo;
}
virtual const HexagonSubtarget *getSubtargetImpl() const {
return &Subtarget;
}
virtual const HexagonRegisterInfo *getRegisterInfo() const {
return &InstrInfo.getRegisterInfo();
}
virtual const InstrItineraryData* getInstrItineraryData() const {
return InstrItins;
}
virtual const HexagonTargetLowering* getTargetLowering() const {
return &TLInfo;
}
virtual const HexagonFrameLowering* getFrameLowering() const {
return &FrameLowering;
}
virtual const HexagonSelectionDAGInfo* getSelectionDAGInfo() const {
return &TSInfo;
}
virtual const TargetData *getTargetData() const { return &DataLayout; }
static unsigned getModuleMatchQuality(const Module &M);
// Pass Pipeline Configuration.
virtual bool addPassesForOptimizations(PassManagerBase &PM);
virtual bool addInstSelector(PassManagerBase &PM);
virtual bool addPreEmitPass(PassManagerBase &PM);
virtual bool addPreRegAlloc(llvm::PassManagerBase &PM);
virtual bool addPostRegAlloc(PassManagerBase &PM);
virtual bool addPreSched2(PassManagerBase &PM);
};
extern bool flag_aligned_memcpy;
} // end namespace llvm
#endif

View File

@ -0,0 +1,94 @@
//===-- HexagonTargetObjectFile.cpp - Hexagon asm properties ----*- 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 declarations of the HexagonTargetAsmInfo properties.
//
//===----------------------------------------------------------------------===//
#include "llvm/Function.h"
#include "llvm/GlobalVariable.h"
#include "llvm/Target/TargetData.h"
#include "llvm/DerivedTypes.h"
#include "llvm/MC/MCContext.h"
#include "llvm/Support/ELF.h"
#include "llvm/Support/CommandLine.h"
#include "HexagonSubtarget.h"
#include "HexagonTargetObjectFile.h"
#include "HexagonTargetMachine.h"
using namespace llvm;
static cl::opt<int> SmallDataThreshold("hexagon-small-data-threshold",
cl::init(8), cl::Hidden);
void HexagonTargetObjectFile::Initialize(MCContext &Ctx,
const TargetMachine &TM) {
TargetLoweringObjectFileELF::Initialize(Ctx, TM);
SmallDataSection =
getContext().getELFSection(".sdata", ELF::SHT_PROGBITS,
ELF::SHF_WRITE | ELF::SHF_ALLOC,
SectionKind::getDataRel());
SmallBSSSection =
getContext().getELFSection(".sbss", ELF::SHT_NOBITS,
ELF::SHF_WRITE | ELF::SHF_ALLOC,
SectionKind::getBSS());
}
// sdata/sbss support taken largely from the MIPS Backend.
static bool IsInSmallSection(uint64_t Size) {
return Size > 0 && Size <= (uint64_t)SmallDataThreshold;
}
/// IsGlobalInSmallSection - Return true if this global value should be
/// placed into small data/bss section.
bool HexagonTargetObjectFile::IsGlobalInSmallSection(const GlobalValue *GV,
const TargetMachine &TM) const {
// If the primary definition of this global value is outside the current
// translation unit or the global value is available for inspection but not
// emission, then do nothing.
if (GV->isDeclaration() || GV->hasAvailableExternallyLinkage())
return false;
// Otherwise, Check if GV should be in sdata/sbss, when normally it would end
// up in getKindForGlobal(GV, TM).
return IsGlobalInSmallSection(GV, TM, getKindForGlobal(GV, TM));
}
/// IsGlobalInSmallSection - Return true if this global value should be
/// placed into small data/bss section.
bool HexagonTargetObjectFile::
IsGlobalInSmallSection(const GlobalValue *GV, const TargetMachine &TM,
SectionKind Kind) const {
// Only global variables, not functions.
const GlobalVariable *GVA = dyn_cast<GlobalVariable>(GV);
if (!GVA)
return false;
if (Kind.isBSS() || Kind.isDataNoRel() || Kind.isCommon()) {
Type *Ty = GV->getType()->getElementType();
return IsInSmallSection(TM.getTargetData()->getTypeAllocSize(Ty));
}
return false;
}
const MCSection *HexagonTargetObjectFile::
SelectSectionForGlobal(const GlobalValue *GV, SectionKind Kind,
Mangler *Mang, const TargetMachine &TM) const {
// Handle Small Section classification here.
if (Kind.isBSS() && IsGlobalInSmallSection(GV, TM, Kind))
return SmallBSSSection;
if (Kind.isDataNoRel() && IsGlobalInSmallSection(GV, TM, Kind))
return SmallDataSection;
// Otherwise, we work the same as ELF.
return TargetLoweringObjectFileELF::SelectSectionForGlobal(GV, Kind, Mang,TM);
}

View File

@ -0,0 +1,40 @@
//===-- HexagonTargetAsmInfo.h - Hexagon asm properties ---------*- C++ -*--==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef HexagonTARGETOBJECTFILE_H
#define HexagonTARGETOBJECTFILE_H
#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
#include "llvm/MC/MCSectionELF.h"
namespace llvm {
class HexagonTargetObjectFile : public TargetLoweringObjectFileELF {
const MCSectionELF *SmallDataSection;
const MCSectionELF *SmallBSSSection;
public:
virtual void Initialize(MCContext &Ctx, const TargetMachine &TM);
/// IsGlobalInSmallSection - Return true if this global address should be
/// placed into small data/bss section.
bool IsGlobalInSmallSection(const GlobalValue *GV,
const TargetMachine &TM,
SectionKind Kind) const;
bool IsGlobalInSmallSection(const GlobalValue *GV,
const TargetMachine &TM) const;
const MCSection* SelectSectionForGlobal(const GlobalValue *GV,
SectionKind Kind,
Mangler *Mang,
const TargetMachine &TM) const;
};
} // namespace llvm
#endif

View File

@ -0,0 +1,141 @@
//==-- HexagonVarargsCallingConvention.h - Calling Conventions ---*- C++ -*-==//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file declares the functions that assign locations to outgoing function
// arguments. Adapted from the target independent version but this handles
// calls to varargs functions
//
//===----------------------------------------------------------------------===//
//
static bool RetCC_Hexagon32_VarArgs(unsigned ValNo, EVT ValVT,
EVT LocVT, CCValAssign::LocInfo LocInfo,
ISD::ArgFlagsTy ArgFlags,
Hexagon_CCState &State,
int NonVarArgsParams,
int CurrentParam,
bool ForceMem);
static bool CC_Hexagon32_VarArgs(unsigned ValNo, EVT ValVT,
EVT LocVT, CCValAssign::LocInfo LocInfo,
ISD::ArgFlagsTy ArgFlags,
Hexagon_CCState &State,
int NonVarArgsParams,
int CurrentParam,
bool ForceMem) {
unsigned ByValSize = 0;
if (ArgFlags.isByVal() &&
((ByValSize = ArgFlags.getByValSize()) >
(MVT(MVT::i64).getSizeInBits() / 8))) {
ForceMem = true;
}
// Only assign registers for named (non varargs) arguments
if ( !ForceMem && ((NonVarArgsParams == -1) || (CurrentParam <=
NonVarArgsParams))) {
if (LocVT == MVT::i32 ||
LocVT == MVT::i16 ||
LocVT == MVT::i8 ||
LocVT == MVT::f32) {
static const unsigned RegList1[] = {
Hexagon::R0, Hexagon::R1, Hexagon::R2, Hexagon::R3, Hexagon::R4,
Hexagon::R5
};
if (unsigned Reg = State.AllocateReg(RegList1, 6)) {
State.addLoc(CCValAssign::getReg(ValNo, ValVT.getSimpleVT(), Reg,
LocVT.getSimpleVT(), LocInfo));
return false;
}
}
if (LocVT == MVT::i64 ||
LocVT == MVT::f64) {
static const unsigned RegList2[] = {
Hexagon::D0, Hexagon::D1, Hexagon::D2
};
if (unsigned Reg = State.AllocateReg(RegList2, 3)) {
State.addLoc(CCValAssign::getReg(ValNo, ValVT.getSimpleVT(), Reg,
LocVT.getSimpleVT(), LocInfo));
return false;
}
}
}
const Type* ArgTy = LocVT.getTypeForEVT(State.getContext());
unsigned Alignment =
State.getTarget().getTargetData()->getABITypeAlignment(ArgTy);
unsigned Size =
State.getTarget().getTargetData()->getTypeSizeInBits(ArgTy) / 8;
// If it's passed by value, then we need the size of the aggregate not of
// the pointer.
if (ArgFlags.isByVal()) {
Size = ByValSize;
// Hexagon_TODO: Get the alignment of the contained type here.
Alignment = 8;
}
unsigned Offset3 = State.AllocateStack(Size, Alignment);
State.addLoc(CCValAssign::getMem(ValNo, ValVT.getSimpleVT(), Offset3,
LocVT.getSimpleVT(), LocInfo));
return false;
}
static bool RetCC_Hexagon32_VarArgs(unsigned ValNo, EVT ValVT,
EVT LocVT, CCValAssign::LocInfo LocInfo,
ISD::ArgFlagsTy ArgFlags,
Hexagon_CCState &State,
int NonVarArgsParams,
int CurrentParam,
bool ForceMem) {
if (LocVT == MVT::i32 ||
LocVT == MVT::f32) {
static const unsigned RegList1[] = {
Hexagon::R0, Hexagon::R1, Hexagon::R2, Hexagon::R3, Hexagon::R4,
Hexagon::R5
};
if (unsigned Reg = State.AllocateReg(RegList1, 6)) {
State.addLoc(CCValAssign::getReg(ValNo, ValVT.getSimpleVT(), Reg,
LocVT.getSimpleVT(), LocInfo));
return false;
}
}
if (LocVT == MVT::i64 ||
LocVT == MVT::f64) {
static const unsigned RegList2[] = {
Hexagon::D0, Hexagon::D1, Hexagon::D2
};
if (unsigned Reg = State.AllocateReg(RegList2, 3)) {
State.addLoc(CCValAssign::getReg(ValNo, ValVT.getSimpleVT(), Reg,
LocVT.getSimpleVT(), LocInfo));
return false;
}
}
const Type* ArgTy = LocVT.getTypeForEVT(State.getContext());
unsigned Alignment =
State.getTarget().getTargetData()->getABITypeAlignment(ArgTy);
unsigned Size =
State.getTarget().getTargetData()->getTypeSizeInBits(ArgTy) / 8;
unsigned Offset3 = State.AllocateStack(Size, Alignment);
State.addLoc(CCValAssign::getMem(ValNo, ValVT.getSimpleVT(), Offset3,
LocVT.getSimpleVT(), LocInfo));
return false;
}

View File

@ -0,0 +1,30 @@
;===- ./lib/Target/Hexagon/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 = TargetGroup
name = Hexagon
parent = Target
has_asmprinter = 1
[component_1]
type = Library
name = HexagonCodeGen
parent = Hexagon
required_libraries = AsmPrinter CodeGen Core HexagonInfo SelectionDAG Support Target MC
add_to_library_groups = Hexagon

View File

@ -0,0 +1,23 @@
##===- lib/Target/Hexagon/Makefile -------------------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
LEVEL = ../../..
LIBRARYNAME = LLVMHexagonCodeGen
TARGET = Hexagon
# Make sure that tblgen is run, first thing.
BUILT_SOURCES = HexagonGenRegisterInfo.inc \
HexagonGenInstrInfo.inc \
HexagonGenAsmWriter.inc \
HexagonGenDAGISel.inc HexagonGenSubtargetInfo.inc \
HexagonGenCallingConv.inc \
HexagonAsmPrinter.cpp
DIRS = TargetInfo
include $(LEVEL)/Makefile.common

View File

@ -0,0 +1,14 @@
include_directories( ${CMAKE_CURRENT_BINARY_DIR}/..
${CMAKE_CURRENT_SOURCE_DIR}/.. )
add_llvm_library(LLVMHexagonInfo
HexagonTargetInfo.cpp
)
add_llvm_library_dependencies(LLVMHexagonInfo
LLVMMC
LLVMSupport
LLVMTarget
)
add_dependencies(LLVMHexagonInfo HexagonCommonTableGen)

View File

@ -0,0 +1,19 @@
//===-- HexagonTargetInfo.cpp - Hexagon Target Implementation ------------------===//
//
// 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/Module.h"
#include "llvm/Support/TargetRegistry.h"
using namespace llvm;
Target llvm::TheHexagonTarget;
extern "C" void LLVMInitializeHexagonTargetInfo() {
RegisterTarget<Triple::hexagon, /*HasJIT=*/false> X(TheHexagonTarget, "hexagon", "Hexagon");
}

View File

@ -0,0 +1,24 @@
;===- ./lib/Target/Hexagon/TargetInfo/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 = HexagonInfo
parent = Hexagon
required_libraries = MC Support
add_to_library_groups = Hexagon

View File

@ -0,0 +1,15 @@
##===- lib/Target/Hexagon/TargetInfo/Makefile ----------------*- Makefile -*-===##
#
# The LLVM Compiler Infrastructure
#
# This file is distributed under the University of Illinois Open Source
# License. See LICENSE.TXT for details.
#
##===----------------------------------------------------------------------===##
LEVEL = ../../../..
LIBRARYNAME = LLVMHexagonInfo
# Hack: we need to include 'main' target directory to grab private headers
CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/..
include $(LEVEL)/Makefile.common

View File

@ -300,6 +300,7 @@ AC_CACHE_CHECK([target architecture],[llvm_cv_target_arch],
mips-*) llvm_cv_target_arch="Mips" ;;
xcore-*) llvm_cv_target_arch="XCore" ;;
msp430-*) llvm_cv_target_arch="MSP430" ;;
hexagon-*) llvm_cv_target_arch="Hexagon" ;;
mblaze-*) llvm_cv_target_arch="MBlaze" ;;
ptx-*) llvm_cv_target_arch="PTX" ;;
*) llvm_cv_target_arch="Unknown" ;;
@ -434,6 +435,7 @@ else
Mips) AC_SUBST(TARGET_HAS_JIT,1) ;;
XCore) AC_SUBST(TARGET_HAS_JIT,0) ;;
MSP430) AC_SUBST(TARGET_HAS_JIT,0) ;;
Hexagon) AC_SUBST(TARGET_HAS_JIT,0) ;;
MBlaze) AC_SUBST(TARGET_HAS_JIT,0) ;;
PTX) AC_SUBST(TARGET_HAS_JIT,0) ;;
*) AC_SUBST(TARGET_HAS_JIT,0) ;;
@ -545,14 +547,14 @@ dnl Allow specific targets to be specified for building (or not)
TARGETS_TO_BUILD=""
AC_ARG_ENABLE([targets],AS_HELP_STRING([--enable-targets],
[Build specific host targets: all or target1,target2,... Valid targets are:
host, x86, x86_64, sparc, powerpc, arm, mips, spu,
host, x86, x86_64, sparc, powerpc, arm, mips, spu, hexagon,
xcore, msp430, ptx, cbe, and cpp (default=all)]),,
enableval=all)
if test "$enableval" = host-only ; then
enableval=host
fi
case "$enableval" in
all) TARGETS_TO_BUILD="X86 Sparc PowerPC ARM Mips CellSPU XCore MSP430 CBackend CppBackend MBlaze PTX" ;;
all) TARGETS_TO_BUILD="X86 Sparc PowerPC ARM Mips CellSPU XCore MSP430 Hexagon CBackend CppBackend MBlaze PTX" ;;
*)for a_target in `echo $enableval|sed -e 's/,/ /g' ` ; do
case "$a_target" in
x86) TARGETS_TO_BUILD="X86 $TARGETS_TO_BUILD" ;;
@ -564,6 +566,7 @@ case "$enableval" in
spu) TARGETS_TO_BUILD="CellSPU $TARGETS_TO_BUILD" ;;
xcore) TARGETS_TO_BUILD="XCore $TARGETS_TO_BUILD" ;;
msp430) TARGETS_TO_BUILD="MSP430 $TARGETS_TO_BUILD" ;;
hexagon) TARGETS_TO_BUILD="Hexagon $TARGETS_TO_BUILD" ;;
cbe) TARGETS_TO_BUILD="CBackend $TARGETS_TO_BUILD" ;;
cpp) TARGETS_TO_BUILD="CppBackend $TARGETS_TO_BUILD" ;;
mblaze) TARGETS_TO_BUILD="MBlaze $TARGETS_TO_BUILD" ;;
@ -579,6 +582,7 @@ case "$enableval" in
CellSPU|SPU) TARGETS_TO_BUILD="CellSPU $TARGETS_TO_BUILD" ;;
XCore) TARGETS_TO_BUILD="XCore $TARGETS_TO_BUILD" ;;
MSP430) TARGETS_TO_BUILD="MSP430 $TARGETS_TO_BUILD" ;;
Hexagon) TARGETS_TO_BUILD="Hexagon $TARGETS_TO_BUILD" ;;
PTX) TARGETS_TO_BUILD="PTX $TARGETS_TO_BUILD" ;;
*) AC_MSG_ERROR([Can not set target to build]) ;;
esac ;;

View File

@ -1401,9 +1401,8 @@ Optional Features:
(default is YES)
--enable-targets Build specific host targets: all or
target1,target2,... Valid targets are: host, x86,
x86_64, sparc, powerpc, arm, mips, spu,
xcore, msp430, ptx, cbe, and cpp
(default=all)
x86_64, sparc, powerpc, arm, mips, spu, hexagon,
xcore, msp430, ptx, cbe, and cpp (default=all)
--enable-cbe-printf-a Enable C Backend output with hex floating point via
%a (default is YES)
--enable-bindings Build specific language bindings:
@ -3844,6 +3843,7 @@ else
mips-*) llvm_cv_target_arch="Mips" ;;
xcore-*) llvm_cv_target_arch="XCore" ;;
msp430-*) llvm_cv_target_arch="MSP430" ;;
hexagon-*) llvm_cv_target_arch="Hexagon" ;;
mblaze-*) llvm_cv_target_arch="MBlaze" ;;
ptx-*) llvm_cv_target_arch="PTX" ;;
*) llvm_cv_target_arch="Unknown" ;;
@ -5044,6 +5044,8 @@ else
XCore) TARGET_HAS_JIT=0
;;
MSP430) TARGET_HAS_JIT=0
;;
Hexagon) TARGET_HAS_JIT=0
;;
MBlaze) TARGET_HAS_JIT=0
;;
@ -5233,7 +5235,7 @@ if test "$enableval" = host-only ; then
enableval=host
fi
case "$enableval" in
all) TARGETS_TO_BUILD="X86 Sparc PowerPC ARM Mips CellSPU XCore MSP430 CBackend CppBackend MBlaze PTX" ;;
all) TARGETS_TO_BUILD="X86 Sparc PowerPC ARM Mips CellSPU XCore MSP430 Hexagon CBackend CppBackend MBlaze PTX" ;;
*)for a_target in `echo $enableval|sed -e 's/,/ /g' ` ; do
case "$a_target" in
x86) TARGETS_TO_BUILD="X86 $TARGETS_TO_BUILD" ;;
@ -5245,6 +5247,7 @@ case "$enableval" in
spu) TARGETS_TO_BUILD="CellSPU $TARGETS_TO_BUILD" ;;
xcore) TARGETS_TO_BUILD="XCore $TARGETS_TO_BUILD" ;;
msp430) TARGETS_TO_BUILD="MSP430 $TARGETS_TO_BUILD" ;;
hexagon) TARGETS_TO_BUILD="Hexagon $TARGETS_TO_BUILD" ;;
cbe) TARGETS_TO_BUILD="CBackend $TARGETS_TO_BUILD" ;;
cpp) TARGETS_TO_BUILD="CppBackend $TARGETS_TO_BUILD" ;;
mblaze) TARGETS_TO_BUILD="MBlaze $TARGETS_TO_BUILD" ;;
@ -5260,6 +5263,7 @@ case "$enableval" in
CellSPU|SPU) TARGETS_TO_BUILD="CellSPU $TARGETS_TO_BUILD" ;;
XCore) TARGETS_TO_BUILD="XCore $TARGETS_TO_BUILD" ;;
MSP430) TARGETS_TO_BUILD="MSP430 $TARGETS_TO_BUILD" ;;
Hexagon) TARGETS_TO_BUILD="Hexagon $TARGETS_TO_BUILD" ;;
PTX) TARGETS_TO_BUILD="PTX $TARGETS_TO_BUILD" ;;
*) { { echo "$as_me:$LINENO: error: Can not set target to build" >&5
echo "$as_me: error: Can not set target to build" >&2;}

View File

@ -0,0 +1,18 @@
; RUN: llc -march=hexagon -mcpu=hexagonv4 < %s | FileCheck %s
; CHECK: r[[T0:[0-9]+]] = #7
; CHECK: memw(r29 + #0) = r[[T0]]
; CHECK: r0 = #1
; CHECK: r1 = #2
; CHECK: r2 = #3
; CHECK: r3 = #4
; CHECK: r4 = #5
; CHECK: r5 = #6
define void @foo() nounwind {
entry:
call void @bar(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7)
ret void
}
declare void @bar(i32, i32, i32, i32, i32, i32, i32)

View File

@ -0,0 +1,17 @@
; RUN: llc -march=hexagon -mcpu=hexagonv4 < %s | FileCheck %s
; CHECK: combine(r{{[0-9]+}}, r{{[0-9]+}})
@j = external global i32
@k = external global i64
define void @foo() nounwind {
entry:
%0 = load i32* @j, align 4
%1 = load i64* @k, align 8
%conv = trunc i64 %1 to i32
%2 = call i64 @llvm.hexagon.A2.combinew(i32 %0, i32 %conv)
store i64 %2, i64* @k, align 8
ret void
}
declare i64 @llvm.hexagon.A2.combinew(i32, i32) nounwind readnone

View File

@ -0,0 +1,5 @@
load_lib llvm.exp
if { [llvm_supports_target Hexagon] } {
RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{ll,c,cpp}]]
}

View File

@ -0,0 +1,22 @@
; RUN: llc -march=hexagon -mcpu=hexagonv4 < %s | FileCheck %s
; CHECK: __hexagon_adddf3
; CHECK: __hexagon_subdf3
define void @foo(double* %acc, double %num, double %num2) nounwind {
entry:
%acc.addr = alloca double*, align 4
%num.addr = alloca double, align 8
%num2.addr = alloca double, align 8
store double* %acc, double** %acc.addr, align 4
store double %num, double* %num.addr, align 8
store double %num2, double* %num2.addr, align 8
%0 = load double** %acc.addr, align 4
%1 = load double* %0
%2 = load double* %num.addr, align 8
%add = fadd double %1, %2
%3 = load double* %num2.addr, align 8
%sub = fsub double %add, %3
%4 = load double** %acc.addr, align 4
store double %sub, double* %4
ret void
}

View File

@ -0,0 +1,22 @@
; RUN: llc -march=hexagon -mcpu=hexagonv4 < %s | FileCheck %s
; CHECK: __hexagon_addsf3
; CHECK: __hexagon_subsf3
define void @foo(float* %acc, float %num, float %num2) nounwind {
entry:
%acc.addr = alloca float*, align 4
%num.addr = alloca float, align 4
%num2.addr = alloca float, align 4
store float* %acc, float** %acc.addr, align 4
store float %num, float* %num.addr, align 4
store float %num2, float* %num2.addr, align 4
%0 = load float** %acc.addr, align 4
%1 = load float* %0
%2 = load float* %num.addr, align 4
%add = fadd float %1, %2
%3 = load float* %num2.addr, align 4
%sub = fsub float %add, %3
%4 = load float** %acc.addr, align 4
store float %sub, float* %4
ret void
}

View File

@ -0,0 +1,23 @@
; RUN: llc -march=hexagon -mcpu=hexagonv4 < %s | FileCheck %s
@num = external global i32
@acc = external global i32
@num2 = external global i32
; CHECK: allocframe
; CHECK: dealloc_return
define i32 @foo() nounwind {
entry:
%i = alloca i32, align 4
%0 = load i32* @num, align 4
store i32 %0, i32* %i, align 4
%1 = load i32* %i, align 4
%2 = load i32* @acc, align 4
%mul = mul nsw i32 %1, %2
%3 = load i32* @num2, align 4
%add = add nsw i32 %mul, %3
store i32 %add, i32* %i, align 4
%4 = load i32* %i, align 4
ret i32 %4
}

View File

@ -0,0 +1,19 @@
; RUN: llc -march=hexagon -mcpu=hexagonv4 < %s | FileCheck %s
; CHECK: += mpyi
define void @foo(i32 %acc, i32 %num, i32 %num2) nounwind {
entry:
%acc.addr = alloca i32, align 4
%num.addr = alloca i32, align 4
%num2.addr = alloca i32, align 4
store i32 %acc, i32* %acc.addr, align 4
store i32 %num, i32* %num.addr, align 4
store i32 %num2, i32* %num2.addr, align 4
%0 = load i32* %num.addr, align 4
%1 = load i32* %acc.addr, align 4
%mul = mul nsw i32 %0, %1
%2 = load i32* %num2.addr, align 4
%add = add nsw i32 %mul, %2
store i32 %add, i32* %num.addr, align 4
ret void
}

View File

@ -0,0 +1,20 @@
; RUN: llc -march=hexagon -mcpu=hexagonv4 < %s | FileCheck %s
@num = external global i32
@acc = external global i32
@val = external global i32
; CHECK: CONST32(#acc)
; CHECK: CONST32(#val)
; CHECK: CONST32(#num)
define void @foo() nounwind {
entry:
%0 = load i32* @num, align 4
%1 = load i32* @acc, align 4
%mul = mul nsw i32 %0, %1
%2 = load i32* @val, align 4
%add = add nsw i32 %mul, %2
store i32 %add, i32* @num, align 4
ret void
}

View File

@ -0,0 +1,15 @@
; RUN: llc -march=hexagon -mcpu=hexagonv4 < %s | FileCheck %s
; CHECK: r1:0 = or(r{{[0-9]}}:{{[0-9]}}, r{{[0-9]}}:{{[0-9]}})
%struct.small = type { i32, i32 }
@s1 = common global %struct.small zeroinitializer, align 4
define void @foo() nounwind {
entry:
%0 = load i64* bitcast (%struct.small* @s1 to i64*), align 1
call void @bar(i64 %0)
ret void
}
declare void @bar(i64)

View File

@ -0,0 +1,16 @@
; RUN: llc -march=hexagon -mcpu=hexagonv4 < %s | FileCheck %s
; CHECK: r[[T0:[0-9]+]] = CONST32(#s2)
; CHECK: r[[T1:[0-9]+]] = memw(r[[T0]] + #0)
; CHECK: memw(r29 + #0) = r[[T1]]
%struct.large = type { i64, i64 }
@s2 = common global %struct.large zeroinitializer, align 8
define void @foo() nounwind {
entry:
call void @bar(%struct.large* byval @s2)
ret void
}
declare void @bar(%struct.large* byval)

View File

@ -0,0 +1,16 @@
; RUN: llc -march=hexagon -mcpu=hexagonv4 < %s | FileCheck %s
; CHECK: vaddh(r{{[0-9]+}}, r{{[0-9]+}})
@j = external global i32
@k = external global i32
define void @foo() nounwind {
entry:
%0 = load i32* @j, align 4
%1 = load i32* @k, align 4
%2 = call i32 @llvm.hexagon.A2.svaddh(i32 %0, i32 %1)
store i32 %2, i32* @k, align 4
ret void
}
declare i32 @llvm.hexagon.A2.svaddh(i32, i32) nounwind readnone