2011-12-13 05:14:40 +08:00
|
|
|
//===-- HexagonISelLowering.cpp - Hexagon DAG Lowering Implementation -----===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2011-12-13 05:14:40 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// This file implements the interfaces that Hexagon uses to lower LLVM code
|
|
|
|
// into a selection DAG.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "HexagonISelLowering.h"
|
2017-06-06 19:49:48 +08:00
|
|
|
#include "Hexagon.h"
|
2011-12-13 05:14:40 +08:00
|
|
|
#include "HexagonMachineFunctionInfo.h"
|
2016-12-17 09:09:05 +08:00
|
|
|
#include "HexagonRegisterInfo.h"
|
2011-12-13 05:14:40 +08:00
|
|
|
#include "HexagonSubtarget.h"
|
2012-12-04 00:50:05 +08:00
|
|
|
#include "HexagonTargetMachine.h"
|
|
|
|
#include "HexagonTargetObjectFile.h"
|
2016-12-17 09:09:05 +08:00
|
|
|
#include "llvm/ADT/APInt.h"
|
|
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
|
|
#include "llvm/ADT/SmallVector.h"
|
2018-09-07 21:36:21 +08:00
|
|
|
#include "llvm/ADT/StringSwitch.h"
|
2011-12-13 05:14:40 +08:00
|
|
|
#include "llvm/CodeGen/CallingConvLower.h"
|
|
|
|
#include "llvm/CodeGen/MachineFrameInfo.h"
|
|
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
2016-12-17 09:09:05 +08:00
|
|
|
#include "llvm/CodeGen/MachineMemOperand.h"
|
2011-12-13 05:14:40 +08:00
|
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
2017-06-06 19:49:48 +08:00
|
|
|
#include "llvm/CodeGen/RuntimeLibcalls.h"
|
2016-12-17 09:09:05 +08:00
|
|
|
#include "llvm/CodeGen/SelectionDAG.h"
|
2017-11-17 09:07:10 +08:00
|
|
|
#include "llvm/CodeGen/TargetCallingConv.h"
|
2018-03-30 01:21:10 +08:00
|
|
|
#include "llvm/CodeGen/ValueTypes.h"
|
2016-12-17 09:09:05 +08:00
|
|
|
#include "llvm/IR/BasicBlock.h"
|
2013-01-02 19:36:10 +08:00
|
|
|
#include "llvm/IR/CallingConv.h"
|
2016-12-17 09:09:05 +08:00
|
|
|
#include "llvm/IR/DataLayout.h"
|
2013-01-02 19:36:10 +08:00
|
|
|
#include "llvm/IR/DerivedTypes.h"
|
2021-06-25 22:30:59 +08:00
|
|
|
#include "llvm/IR/DiagnosticInfo.h"
|
|
|
|
#include "llvm/IR/DiagnosticPrinter.h"
|
2013-01-02 19:36:10 +08:00
|
|
|
#include "llvm/IR/Function.h"
|
2016-12-17 09:09:05 +08:00
|
|
|
#include "llvm/IR/GlobalValue.h"
|
2013-01-02 19:36:10 +08:00
|
|
|
#include "llvm/IR/InlineAsm.h"
|
2016-12-17 09:09:05 +08:00
|
|
|
#include "llvm/IR/Instructions.h"
|
2018-03-29 21:52:46 +08:00
|
|
|
#include "llvm/IR/IntrinsicInst.h"
|
2019-12-11 23:55:26 +08:00
|
|
|
#include "llvm/IR/Intrinsics.h"
|
|
|
|
#include "llvm/IR/IntrinsicsHexagon.h"
|
2021-06-06 21:47:30 +08:00
|
|
|
#include "llvm/IR/IRBuilder.h"
|
2016-12-17 09:09:05 +08:00
|
|
|
#include "llvm/IR/Module.h"
|
|
|
|
#include "llvm/IR/Type.h"
|
|
|
|
#include "llvm/IR/Value.h"
|
|
|
|
#include "llvm/MC/MCRegisterInfo.h"
|
|
|
|
#include "llvm/Support/Casting.h"
|
|
|
|
#include "llvm/Support/CodeGen.h"
|
2012-04-21 23:31:36 +08:00
|
|
|
#include "llvm/Support/CommandLine.h"
|
2011-12-13 05:14:40 +08:00
|
|
|
#include "llvm/Support/Debug.h"
|
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
2016-12-17 09:09:05 +08:00
|
|
|
#include "llvm/Support/MathExtras.h"
|
2012-04-21 23:31:45 +08:00
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2016-12-17 09:09:05 +08:00
|
|
|
#include "llvm/Target/TargetMachine.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include <cassert>
|
|
|
|
#include <cstddef>
|
|
|
|
#include <cstdint>
|
|
|
|
#include <limits>
|
|
|
|
#include <utility>
|
2012-04-21 23:31:36 +08:00
|
|
|
|
2012-03-18 02:46:09 +08:00
|
|
|
using namespace llvm;
|
2011-12-13 05:14:40 +08:00
|
|
|
|
2014-04-22 06:55:11 +08:00
|
|
|
#define DEBUG_TYPE "hexagon-lowering"
|
|
|
|
|
2015-12-19 04:19:30 +08:00
|
|
|
static cl::opt<bool> EmitJumpTables("hexagon-emit-jump-tables",
|
|
|
|
cl::init(true), cl::Hidden,
|
2015-04-23 05:17:00 +08:00
|
|
|
cl::desc("Control jump table emission on Hexagon target"));
|
|
|
|
|
|
|
|
static cl::opt<bool> EnableHexSDNodeSched("enable-hexagon-sdnode-sched",
|
|
|
|
cl::Hidden, cl::ZeroOrMore, cl::init(false),
|
|
|
|
cl::desc("Enable Hexagon SDNode scheduling"));
|
|
|
|
|
|
|
|
static cl::opt<bool> EnableFastMath("ffast-math",
|
|
|
|
cl::Hidden, cl::ZeroOrMore, cl::init(false),
|
|
|
|
cl::desc("Enable Fast Math processing"));
|
|
|
|
|
|
|
|
static cl::opt<int> MinimumJumpTables("minimum-jump-tables",
|
|
|
|
cl::Hidden, cl::ZeroOrMore, cl::init(5),
|
|
|
|
cl::desc("Set minimum jump tables"));
|
|
|
|
|
|
|
|
static cl::opt<int> MaxStoresPerMemcpyCL("max-store-memcpy",
|
|
|
|
cl::Hidden, cl::ZeroOrMore, cl::init(6),
|
|
|
|
cl::desc("Max #stores to inline memcpy"));
|
|
|
|
|
|
|
|
static cl::opt<int> MaxStoresPerMemcpyOptSizeCL("max-store-memcpy-Os",
|
|
|
|
cl::Hidden, cl::ZeroOrMore, cl::init(4),
|
|
|
|
cl::desc("Max #stores to inline memcpy"));
|
|
|
|
|
|
|
|
static cl::opt<int> MaxStoresPerMemmoveCL("max-store-memmove",
|
|
|
|
cl::Hidden, cl::ZeroOrMore, cl::init(6),
|
|
|
|
cl::desc("Max #stores to inline memmove"));
|
|
|
|
|
|
|
|
static cl::opt<int> MaxStoresPerMemmoveOptSizeCL("max-store-memmove-Os",
|
|
|
|
cl::Hidden, cl::ZeroOrMore, cl::init(4),
|
|
|
|
cl::desc("Max #stores to inline memmove"));
|
|
|
|
|
|
|
|
static cl::opt<int> MaxStoresPerMemsetCL("max-store-memset",
|
|
|
|
cl::Hidden, cl::ZeroOrMore, cl::init(8),
|
|
|
|
cl::desc("Max #stores to inline memset"));
|
|
|
|
|
|
|
|
static cl::opt<int> MaxStoresPerMemsetOptSizeCL("max-store-memset-Os",
|
|
|
|
cl::Hidden, cl::ZeroOrMore, cl::init(4),
|
|
|
|
cl::desc("Max #stores to inline memset"));
|
|
|
|
|
2018-03-08 01:27:18 +08:00
|
|
|
static cl::opt<bool> AlignLoads("hexagon-align-loads",
|
|
|
|
cl::Hidden, cl::init(false),
|
|
|
|
cl::desc("Rewrite unaligned loads as a pair of aligned loads"));
|
|
|
|
|
2020-06-23 05:03:22 +08:00
|
|
|
static cl::opt<bool>
|
|
|
|
DisableArgsMinAlignment("hexagon-disable-args-min-alignment", cl::Hidden,
|
|
|
|
cl::init(false),
|
|
|
|
cl::desc("Disable minimum alignment of 1 for "
|
|
|
|
"arguments passed by value on stack"));
|
2011-12-13 05:14:40 +08:00
|
|
|
|
2013-10-27 19:16:09 +08:00
|
|
|
namespace {
|
2016-12-17 09:09:05 +08:00
|
|
|
|
2016-07-30 00:44:27 +08:00
|
|
|
class HexagonCCState : public CCState {
|
2018-02-15 23:47:53 +08:00
|
|
|
unsigned NumNamedVarArgParams = 0;
|
2016-07-30 00:44:27 +08:00
|
|
|
|
|
|
|
public:
|
2018-02-09 23:30:02 +08:00
|
|
|
HexagonCCState(CallingConv::ID CC, bool IsVarArg, MachineFunction &MF,
|
2016-07-30 00:44:27 +08:00
|
|
|
SmallVectorImpl<CCValAssign> &locs, LLVMContext &C,
|
2018-02-16 01:20:07 +08:00
|
|
|
unsigned NumNamedArgs)
|
|
|
|
: CCState(CC, IsVarArg, MF, locs, C),
|
|
|
|
NumNamedVarArgParams(NumNamedArgs) {}
|
2016-07-30 00:44:27 +08:00
|
|
|
unsigned getNumNamedVarArgParams() const { return NumNamedVarArgParams; }
|
|
|
|
};
|
|
|
|
|
2016-12-17 09:09:05 +08:00
|
|
|
} // end anonymous namespace
|
2011-12-13 05:14:40 +08:00
|
|
|
|
|
|
|
|
2018-02-09 23:30:02 +08:00
|
|
|
// Implement calling convention for Hexagon.
|
2011-12-13 05:14:40 +08:00
|
|
|
|
2018-02-09 23:30:02 +08:00
|
|
|
static bool CC_SkipOdd(unsigned &ValNo, MVT &ValVT, MVT &LocVT,
|
|
|
|
CCValAssign::LocInfo &LocInfo,
|
|
|
|
ISD::ArgFlagsTy &ArgFlags, CCState &State) {
|
|
|
|
static const MCPhysReg ArgRegs[] = {
|
|
|
|
Hexagon::R0, Hexagon::R1, Hexagon::R2,
|
|
|
|
Hexagon::R3, Hexagon::R4, Hexagon::R5
|
2011-12-13 05:14:40 +08:00
|
|
|
};
|
2018-02-09 23:30:02 +08:00
|
|
|
const unsigned NumArgRegs = array_lengthof(ArgRegs);
|
|
|
|
unsigned RegNum = State.getFirstUnallocated(ArgRegs);
|
2011-12-13 05:14:40 +08:00
|
|
|
|
2018-02-09 23:30:02 +08:00
|
|
|
// RegNum is an index into ArgRegs: skip a register if RegNum is odd.
|
|
|
|
if (RegNum != NumArgRegs && RegNum % 2 == 1)
|
|
|
|
State.AllocateReg(ArgRegs[RegNum]);
|
2011-12-13 05:14:40 +08:00
|
|
|
|
2018-02-09 23:30:02 +08:00
|
|
|
// Always return false here, as this function only makes sure that the first
|
|
|
|
// unallocated register has an even register number and does not actually
|
|
|
|
// allocate a register for the current argument.
|
2011-12-13 05:14:40 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-02-09 23:30:02 +08:00
|
|
|
#include "HexagonGenCallingConv.inc"
|
2011-12-13 05:14:40 +08:00
|
|
|
|
2015-11-27 02:38:27 +08:00
|
|
|
|
2011-12-13 05:14:40 +08:00
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG)
|
2016-08-02 04:31:50 +08:00
|
|
|
const {
|
2011-12-13 05:14:40 +08:00
|
|
|
return SDValue();
|
|
|
|
}
|
|
|
|
|
|
|
|
/// CreateCopyOfByValArgument - Make a copy of an aggregate at address specified
|
|
|
|
/// by "Src" to address "Dst" of size "Size". Alignment information is
|
|
|
|
/// specified by the specific parameter attribute. The copy will be passed as
|
|
|
|
/// a byval function parameter. Sometimes what we are copying is the end of a
|
|
|
|
/// larger object, the part that does not fit in registers.
|
2016-06-12 23:39:02 +08:00
|
|
|
static SDValue CreateCopyOfByValArgument(SDValue Src, SDValue Dst,
|
|
|
|
SDValue Chain, ISD::ArgFlagsTy Flags,
|
|
|
|
SelectionDAG &DAG, const SDLoc &dl) {
|
2015-04-28 22:05:47 +08:00
|
|
|
SDValue SizeNode = DAG.getConstant(Flags.getByValSize(), dl, MVT::i32);
|
[Alignment][NFC] Use Align for getMemcpy/Memmove/Memset
Summary:
This is patch is part of a series to introduce an Alignment type.
See this thread for context: http://lists.llvm.org/pipermail/llvm-dev/2019-July/133851.html
See this patch for the introduction of the type: https://reviews.llvm.org/D64790
Reviewers: courbet
Subscribers: arsenm, dschuff, jyknight, sdardis, nemanjai, jvesely, nhaehnle, sbc100, jgravelle-google, hiraditya, aheejin, kbarton, fedor.sergeev, asb, rbar, johnrusso, simoncook, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, PkmX, jocewei, jsji, Jim, lenary, s.egerton, pzheng, sameer.abuasal, apazos, luismarques, kerbowa, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D73885
2020-02-03 21:49:01 +08:00
|
|
|
return DAG.getMemcpy(
|
|
|
|
Chain, dl, Dst, Src, SizeNode, Flags.getNonZeroByValAlign(),
|
|
|
|
/*isVolatile=*/false, /*AlwaysInline=*/false,
|
|
|
|
/*isTailCall=*/false, MachinePointerInfo(), MachinePointerInfo());
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
|
|
|
|
2017-04-13 23:05:51 +08:00
|
|
|
bool
|
|
|
|
HexagonTargetLowering::CanLowerReturn(
|
2018-02-09 23:30:02 +08:00
|
|
|
CallingConv::ID CallConv, MachineFunction &MF, bool IsVarArg,
|
2017-04-13 23:05:51 +08:00
|
|
|
const SmallVectorImpl<ISD::OutputArg> &Outs,
|
|
|
|
LLVMContext &Context) const {
|
|
|
|
SmallVector<CCValAssign, 16> RVLocs;
|
2018-02-09 23:30:02 +08:00
|
|
|
CCState CCInfo(CallConv, IsVarArg, MF, RVLocs, Context);
|
|
|
|
|
|
|
|
if (MF.getSubtarget<HexagonSubtarget>().useHVXOps())
|
|
|
|
return CCInfo.CheckReturn(Outs, RetCC_Hexagon_HVX);
|
2017-04-13 23:05:51 +08:00
|
|
|
return CCInfo.CheckReturn(Outs, RetCC_Hexagon);
|
|
|
|
}
|
|
|
|
|
2011-12-13 05:14:40 +08:00
|
|
|
// LowerReturn - Lower ISD::RET. If a struct is larger than 8 bytes and is
|
|
|
|
// passed by value, the function prototype is modified to return void and
|
|
|
|
// the value is stored in memory pointed by a pointer passed by caller.
|
|
|
|
SDValue
|
2016-06-12 23:39:02 +08:00
|
|
|
HexagonTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
|
2018-02-09 23:30:02 +08:00
|
|
|
bool IsVarArg,
|
2011-12-13 05:14:40 +08:00
|
|
|
const SmallVectorImpl<ISD::OutputArg> &Outs,
|
|
|
|
const SmallVectorImpl<SDValue> &OutVals,
|
2016-06-12 23:39:02 +08:00
|
|
|
const SDLoc &dl, SelectionDAG &DAG) const {
|
2011-12-13 05:14:40 +08:00
|
|
|
// CCValAssign - represent the assignment of the return value to locations.
|
|
|
|
SmallVector<CCValAssign, 16> RVLocs;
|
|
|
|
|
|
|
|
// CCState - Info about the registers and stack slot.
|
2018-02-09 23:30:02 +08:00
|
|
|
CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,
|
2014-08-07 02:45:26 +08:00
|
|
|
*DAG.getContext());
|
2011-12-13 05:14:40 +08:00
|
|
|
|
|
|
|
// Analyze return values of ISD::RET
|
2018-02-09 23:30:02 +08:00
|
|
|
if (Subtarget.useHVXOps())
|
|
|
|
CCInfo.AnalyzeReturn(Outs, RetCC_Hexagon_HVX);
|
|
|
|
else
|
|
|
|
CCInfo.AnalyzeReturn(Outs, RetCC_Hexagon);
|
2011-12-13 05:14:40 +08:00
|
|
|
|
|
|
|
SDValue Flag;
|
2013-02-06 02:08:43 +08:00
|
|
|
SmallVector<SDValue, 4> RetOps(1, Chain);
|
|
|
|
|
2011-12-13 05:14:40 +08:00
|
|
|
// Copy the result values into the output registers.
|
|
|
|
for (unsigned i = 0; i != RVLocs.size(); ++i) {
|
|
|
|
CCValAssign &VA = RVLocs[i];
|
2021-04-23 05:18:39 +08:00
|
|
|
SDValue Val = OutVals[i];
|
|
|
|
|
|
|
|
switch (VA.getLocInfo()) {
|
|
|
|
default:
|
|
|
|
// Loc info must be one of Full, BCvt, SExt, ZExt, or AExt.
|
|
|
|
llvm_unreachable("Unknown loc info!");
|
|
|
|
case CCValAssign::Full:
|
|
|
|
break;
|
|
|
|
case CCValAssign::BCvt:
|
|
|
|
Val = DAG.getBitcast(VA.getLocVT(), Val);
|
|
|
|
break;
|
|
|
|
case CCValAssign::SExt:
|
|
|
|
Val = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Val);
|
|
|
|
break;
|
|
|
|
case CCValAssign::ZExt:
|
|
|
|
Val = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), Val);
|
|
|
|
break;
|
|
|
|
case CCValAssign::AExt:
|
|
|
|
Val = DAG.getNode(ISD::ANY_EXTEND, dl, VA.getLocVT(), Val);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
Chain = DAG.getCopyToReg(Chain, dl, VA.getLocReg(), Val, Flag);
|
2011-12-13 05:14:40 +08:00
|
|
|
|
|
|
|
// Guarantee that all emitted copies are stuck together with flags.
|
|
|
|
Flag = Chain.getValue(1);
|
2013-02-06 02:08:43 +08:00
|
|
|
RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
|
|
|
|
2013-02-06 02:08:43 +08:00
|
|
|
RetOps[0] = Chain; // Update chain.
|
|
|
|
|
|
|
|
// Add the flag if we have it.
|
2011-12-13 05:14:40 +08:00
|
|
|
if (Flag.getNode())
|
2013-02-06 02:08:43 +08:00
|
|
|
RetOps.push_back(Flag);
|
2011-12-13 05:14:40 +08:00
|
|
|
|
2014-04-27 02:35:24 +08:00
|
|
|
return DAG.getNode(HexagonISD::RET_FLAG, dl, MVT::Other, RetOps);
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
|
|
|
|
2017-04-19 05:16:46 +08:00
|
|
|
bool HexagonTargetLowering::mayBeEmittedAsTailCall(const CallInst *CI) const {
|
2015-04-23 05:17:00 +08:00
|
|
|
// If either no tail call or told not to tail call at all, don't.
|
2019-12-03 08:42:33 +08:00
|
|
|
return CI->isTailCall();
|
2015-04-23 05:17:00 +08:00
|
|
|
}
|
2011-12-13 05:14:40 +08:00
|
|
|
|
2019-10-29 04:12:43 +08:00
|
|
|
Register HexagonTargetLowering::getRegisterByName(
|
2019-12-28 22:18:56 +08:00
|
|
|
const char* RegName, LLT VT, const MachineFunction &) const {
|
2018-09-07 21:36:21 +08:00
|
|
|
// Just support r19, the linux kernel uses it.
|
2019-10-01 09:44:39 +08:00
|
|
|
Register Reg = StringSwitch<Register>(RegName)
|
2019-10-29 04:12:43 +08:00
|
|
|
.Case("r0", Hexagon::R0)
|
|
|
|
.Case("r1", Hexagon::R1)
|
|
|
|
.Case("r2", Hexagon::R2)
|
|
|
|
.Case("r3", Hexagon::R3)
|
|
|
|
.Case("r4", Hexagon::R4)
|
|
|
|
.Case("r5", Hexagon::R5)
|
|
|
|
.Case("r6", Hexagon::R6)
|
|
|
|
.Case("r7", Hexagon::R7)
|
|
|
|
.Case("r8", Hexagon::R8)
|
|
|
|
.Case("r9", Hexagon::R9)
|
|
|
|
.Case("r10", Hexagon::R10)
|
|
|
|
.Case("r11", Hexagon::R11)
|
|
|
|
.Case("r12", Hexagon::R12)
|
|
|
|
.Case("r13", Hexagon::R13)
|
|
|
|
.Case("r14", Hexagon::R14)
|
|
|
|
.Case("r15", Hexagon::R15)
|
|
|
|
.Case("r16", Hexagon::R16)
|
|
|
|
.Case("r17", Hexagon::R17)
|
|
|
|
.Case("r18", Hexagon::R18)
|
2018-09-07 21:36:21 +08:00
|
|
|
.Case("r19", Hexagon::R19)
|
2019-10-29 04:12:43 +08:00
|
|
|
.Case("r20", Hexagon::R20)
|
|
|
|
.Case("r21", Hexagon::R21)
|
|
|
|
.Case("r22", Hexagon::R22)
|
|
|
|
.Case("r23", Hexagon::R23)
|
|
|
|
.Case("r24", Hexagon::R24)
|
|
|
|
.Case("r25", Hexagon::R25)
|
|
|
|
.Case("r26", Hexagon::R26)
|
|
|
|
.Case("r27", Hexagon::R27)
|
|
|
|
.Case("r28", Hexagon::R28)
|
|
|
|
.Case("r29", Hexagon::R29)
|
|
|
|
.Case("r30", Hexagon::R30)
|
|
|
|
.Case("r31", Hexagon::R31)
|
|
|
|
.Case("r1:0", Hexagon::D0)
|
|
|
|
.Case("r3:2", Hexagon::D1)
|
|
|
|
.Case("r5:4", Hexagon::D2)
|
|
|
|
.Case("r7:6", Hexagon::D3)
|
|
|
|
.Case("r9:8", Hexagon::D4)
|
|
|
|
.Case("r11:10", Hexagon::D5)
|
|
|
|
.Case("r13:12", Hexagon::D6)
|
|
|
|
.Case("r15:14", Hexagon::D7)
|
|
|
|
.Case("r17:16", Hexagon::D8)
|
|
|
|
.Case("r19:18", Hexagon::D9)
|
|
|
|
.Case("r21:20", Hexagon::D10)
|
|
|
|
.Case("r23:22", Hexagon::D11)
|
|
|
|
.Case("r25:24", Hexagon::D12)
|
|
|
|
.Case("r27:26", Hexagon::D13)
|
|
|
|
.Case("r29:28", Hexagon::D14)
|
|
|
|
.Case("r31:30", Hexagon::D15)
|
|
|
|
.Case("sp", Hexagon::R29)
|
|
|
|
.Case("fp", Hexagon::R30)
|
|
|
|
.Case("lr", Hexagon::R31)
|
|
|
|
.Case("p0", Hexagon::P0)
|
|
|
|
.Case("p1", Hexagon::P1)
|
|
|
|
.Case("p2", Hexagon::P2)
|
|
|
|
.Case("p3", Hexagon::P3)
|
|
|
|
.Case("sa0", Hexagon::SA0)
|
|
|
|
.Case("lc0", Hexagon::LC0)
|
|
|
|
.Case("sa1", Hexagon::SA1)
|
|
|
|
.Case("lc1", Hexagon::LC1)
|
|
|
|
.Case("m0", Hexagon::M0)
|
|
|
|
.Case("m1", Hexagon::M1)
|
|
|
|
.Case("usr", Hexagon::USR)
|
|
|
|
.Case("ugp", Hexagon::UGP)
|
2021-03-12 01:44:57 +08:00
|
|
|
.Case("cs0", Hexagon::CS0)
|
|
|
|
.Case("cs1", Hexagon::CS1)
|
2019-10-01 09:44:39 +08:00
|
|
|
.Default(Register());
|
2018-09-07 21:36:21 +08:00
|
|
|
if (Reg)
|
|
|
|
return Reg;
|
|
|
|
|
|
|
|
report_fatal_error("Invalid register name global variable");
|
|
|
|
}
|
|
|
|
|
2011-12-13 05:14:40 +08:00
|
|
|
/// LowerCallResult - Lower the result values of an ISD::CALL into the
|
|
|
|
/// appropriate copies out of appropriate physical registers. This assumes that
|
2017-02-18 06:14:51 +08:00
|
|
|
/// Chain/Glue are the input chain/glue to use, and that TheCall is the call
|
2011-12-13 05:14:40 +08:00
|
|
|
/// being lowered. Returns a SDNode with the same number of values as the
|
|
|
|
/// ISD::CALL.
|
2016-06-12 23:39:02 +08:00
|
|
|
SDValue HexagonTargetLowering::LowerCallResult(
|
2018-02-09 23:30:02 +08:00
|
|
|
SDValue Chain, SDValue Glue, CallingConv::ID CallConv, bool IsVarArg,
|
2016-06-12 23:39:02 +08:00
|
|
|
const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl,
|
|
|
|
SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals,
|
|
|
|
const SmallVectorImpl<SDValue> &OutVals, SDValue Callee) const {
|
2011-12-13 05:14:40 +08:00
|
|
|
// Assign locations to each value returned by this call.
|
|
|
|
SmallVector<CCValAssign, 16> RVLocs;
|
|
|
|
|
2018-02-09 23:30:02 +08:00
|
|
|
CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,
|
2014-08-07 02:45:26 +08:00
|
|
|
*DAG.getContext());
|
2011-12-13 05:14:40 +08:00
|
|
|
|
2018-02-09 23:30:02 +08:00
|
|
|
if (Subtarget.useHVXOps())
|
|
|
|
CCInfo.AnalyzeCallResult(Ins, RetCC_Hexagon_HVX);
|
|
|
|
else
|
|
|
|
CCInfo.AnalyzeCallResult(Ins, RetCC_Hexagon);
|
2011-12-13 05:14:40 +08:00
|
|
|
|
|
|
|
// Copy all of the result registers out of their specified physreg.
|
|
|
|
for (unsigned i = 0; i != RVLocs.size(); ++i) {
|
2016-03-05 01:38:05 +08:00
|
|
|
SDValue RetVal;
|
|
|
|
if (RVLocs[i].getValVT() == MVT::i1) {
|
|
|
|
// Return values of type MVT::i1 require special handling. The reason
|
|
|
|
// is that MVT::i1 is associated with the PredRegs register class, but
|
|
|
|
// values of that type are still returned in R0. Generate an explicit
|
|
|
|
// copy into a predicate register from R0, and treat the value of the
|
|
|
|
// predicate register as the call result.
|
|
|
|
auto &MRI = DAG.getMachineFunction().getRegInfo();
|
|
|
|
SDValue FR0 = DAG.getCopyFromReg(Chain, dl, RVLocs[i].getLocReg(),
|
2017-02-18 06:14:51 +08:00
|
|
|
MVT::i32, Glue);
|
2016-03-05 01:38:05 +08:00
|
|
|
// FR0 = (Value, Chain, Glue)
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-16 03:22:08 +08:00
|
|
|
Register PredR = MRI.createVirtualRegister(&Hexagon::PredRegsRegClass);
|
2016-03-05 01:38:05 +08:00
|
|
|
SDValue TPR = DAG.getCopyToReg(FR0.getValue(1), dl, PredR,
|
|
|
|
FR0.getValue(0), FR0.getValue(2));
|
|
|
|
// TPR = (Chain, Glue)
|
2017-02-18 06:14:51 +08:00
|
|
|
// Don't glue this CopyFromReg, because it copies from a virtual
|
|
|
|
// register. If it is glued to the call, InstrEmitter will add it
|
|
|
|
// as an implicit def to the call (EmitMachineNode).
|
|
|
|
RetVal = DAG.getCopyFromReg(TPR.getValue(0), dl, PredR, MVT::i1);
|
|
|
|
Glue = TPR.getValue(1);
|
2017-10-24 03:35:25 +08:00
|
|
|
Chain = TPR.getValue(0);
|
2016-03-05 01:38:05 +08:00
|
|
|
} else {
|
|
|
|
RetVal = DAG.getCopyFromReg(Chain, dl, RVLocs[i].getLocReg(),
|
2017-02-18 06:14:51 +08:00
|
|
|
RVLocs[i].getValVT(), Glue);
|
|
|
|
Glue = RetVal.getValue(2);
|
2017-10-24 03:35:25 +08:00
|
|
|
Chain = RetVal.getValue(1);
|
2016-03-05 01:38:05 +08:00
|
|
|
}
|
|
|
|
InVals.push_back(RetVal.getValue(0));
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return Chain;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// LowerCall - Functions arguments are copied from virtual regs to
|
|
|
|
/// (physical regs)/(stack frame), CALLSEQ_START and CALLSEQ_END are emitted.
|
|
|
|
SDValue
|
2012-05-26 00:35:28 +08:00
|
|
|
HexagonTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
|
2011-12-13 05:14:40 +08:00
|
|
|
SmallVectorImpl<SDValue> &InVals) const {
|
2012-05-26 00:35:28 +08:00
|
|
|
SelectionDAG &DAG = CLI.DAG;
|
2013-07-14 12:42:23 +08:00
|
|
|
SDLoc &dl = CLI.DL;
|
|
|
|
SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
|
|
|
|
SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
|
|
|
|
SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
|
2012-05-26 00:35:28 +08:00
|
|
|
SDValue Chain = CLI.Chain;
|
|
|
|
SDValue Callee = CLI.Callee;
|
|
|
|
CallingConv::ID CallConv = CLI.CallConv;
|
2016-08-02 04:31:50 +08:00
|
|
|
bool IsVarArg = CLI.IsVarArg;
|
|
|
|
bool DoesNotReturn = CLI.DoesNotReturn;
|
2011-12-13 05:14:40 +08:00
|
|
|
|
2018-02-16 01:20:07 +08:00
|
|
|
bool IsStructRet = Outs.empty() ? false : Outs[0].Flags.isSRet();
|
2015-04-23 00:43:53 +08:00
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
2017-07-12 01:11:54 +08:00
|
|
|
MachineFrameInfo &MFI = MF.getFrameInfo();
|
2015-07-09 10:09:04 +08:00
|
|
|
auto PtrVT = getPointerTy(MF.getDataLayout());
|
2011-12-13 05:14:40 +08:00
|
|
|
|
2020-04-14 01:44:59 +08:00
|
|
|
unsigned NumParams = CLI.CB ? CLI.CB->getFunctionType()->getNumParams() : 0;
|
2018-02-16 01:20:07 +08:00
|
|
|
if (GlobalAddressSDNode *GAN = dyn_cast<GlobalAddressSDNode>(Callee))
|
|
|
|
Callee = DAG.getTargetGlobalAddress(GAN->getGlobal(), dl, MVT::i32);
|
2011-12-13 05:14:40 +08:00
|
|
|
|
Add support for Linux/Musl ABI
Differential revision: https://reviews.llvm.org/D72701
The patch adds a new option ABI for Hexagon. It primary deals with
the way variable arguments are passed and is use in the Hexagon Linux Musl
environment.
If a callee function has a variable argument list, it must perform the
following operations to set up its function prologue:
1. Determine the number of registers which could have been used for passing
unnamed arguments. This can be calculated by counting the number of
registers used for passing named arguments. For example, if the callee
function is as follows:
int foo(int a, ...){ ... }
... then register R0 is used to access the argument ' a '. The registers
available for passing unnamed arguments are R1, R2, R3, R4, and R5.
2. Determine the number and size of the named arguments on the stack.
3. If the callee has named arguments on the stack, it should copy all of these
arguments to a location below the current position on the stack, and the
difference should be the size of the register-saved area plus padding
(if any is necessary).
The register-saved area constitutes all the registers that could have
been used to pass unnamed arguments. If the number of registers forming
the register-saved area is odd, it requires 4 bytes of padding; if the
number is even, no padding is required. This is done to ensure an 8-byte
alignment on the stack. For example, if the callee is as follows:
int foo(int a, ...){ ... }
... then the named arguments should be copied to the following location:
current_position - 5 (for R1-R5) * 4 (bytes) - 4 (bytes of padding)
If the callee is as follows:
int foo(int a, int b, ...){ ... }
... then the named arguments should be copied to the following location:
current_position - 4 (for R2-R5) * 4 (bytes) - 0 (bytes of padding)
4. After any named arguments have been copied, copy all the registers that
could have been used to pass unnamed arguments on the stack. If the number
of registers is odd, leave 4 bytes of padding and then start copying them
on the stack; if the number is even, no padding is required. This
constitutes the register-saved area. If padding is required, ensure
that the start location of padding is 8-byte aligned. If no padding is
required, ensure that the start location of the on-stack copy of the
first register which might have a variable argument is 8-byte aligned.
5. Decrement the stack pointer by the size of register saved area plus the
padding. For example, if the callee is as follows:
int foo(int a, ...){ ... } ;
... then the decrement value should be the following:
5 (for R1-R5) * 4 (bytes) + 4 (bytes of padding) = 24 bytes
The decrement should be performed before the allocframe instruction.
Increment the stack-pointer back by the same amount before returning
from the function.
2019-12-28 03:03:01 +08:00
|
|
|
// Linux ABI treats var-arg calls the same way as regular ones.
|
|
|
|
bool TreatAsVarArg = !Subtarget.isEnvironmentMusl() && IsVarArg;
|
|
|
|
|
2013-10-27 19:16:09 +08:00
|
|
|
// Analyze operands of the call, assigning locations to each operand.
|
|
|
|
SmallVector<CCValAssign, 16> ArgLocs;
|
Add support for Linux/Musl ABI
Differential revision: https://reviews.llvm.org/D72701
The patch adds a new option ABI for Hexagon. It primary deals with
the way variable arguments are passed and is use in the Hexagon Linux Musl
environment.
If a callee function has a variable argument list, it must perform the
following operations to set up its function prologue:
1. Determine the number of registers which could have been used for passing
unnamed arguments. This can be calculated by counting the number of
registers used for passing named arguments. For example, if the callee
function is as follows:
int foo(int a, ...){ ... }
... then register R0 is used to access the argument ' a '. The registers
available for passing unnamed arguments are R1, R2, R3, R4, and R5.
2. Determine the number and size of the named arguments on the stack.
3. If the callee has named arguments on the stack, it should copy all of these
arguments to a location below the current position on the stack, and the
difference should be the size of the register-saved area plus padding
(if any is necessary).
The register-saved area constitutes all the registers that could have
been used to pass unnamed arguments. If the number of registers forming
the register-saved area is odd, it requires 4 bytes of padding; if the
number is even, no padding is required. This is done to ensure an 8-byte
alignment on the stack. For example, if the callee is as follows:
int foo(int a, ...){ ... }
... then the named arguments should be copied to the following location:
current_position - 5 (for R1-R5) * 4 (bytes) - 4 (bytes of padding)
If the callee is as follows:
int foo(int a, int b, ...){ ... }
... then the named arguments should be copied to the following location:
current_position - 4 (for R2-R5) * 4 (bytes) - 0 (bytes of padding)
4. After any named arguments have been copied, copy all the registers that
could have been used to pass unnamed arguments on the stack. If the number
of registers is odd, leave 4 bytes of padding and then start copying them
on the stack; if the number is even, no padding is required. This
constitutes the register-saved area. If padding is required, ensure
that the start location of padding is 8-byte aligned. If no padding is
required, ensure that the start location of the on-stack copy of the
first register which might have a variable argument is 8-byte aligned.
5. Decrement the stack pointer by the size of register saved area plus the
padding. For example, if the callee is as follows:
int foo(int a, ...){ ... } ;
... then the decrement value should be the following:
5 (for R1-R5) * 4 (bytes) + 4 (bytes of padding) = 24 bytes
The decrement should be performed before the allocframe instruction.
Increment the stack-pointer back by the same amount before returning
from the function.
2019-12-28 03:03:01 +08:00
|
|
|
HexagonCCState CCInfo(CallConv, TreatAsVarArg, MF, ArgLocs, *DAG.getContext(),
|
2018-02-16 01:20:07 +08:00
|
|
|
NumParams);
|
2013-10-27 19:16:09 +08:00
|
|
|
|
2018-02-09 23:30:02 +08:00
|
|
|
if (Subtarget.useHVXOps())
|
|
|
|
CCInfo.AnalyzeCallOperands(Outs, CC_Hexagon_HVX);
|
2020-06-23 05:03:22 +08:00
|
|
|
else if (DisableArgsMinAlignment)
|
|
|
|
CCInfo.AnalyzeCallOperands(Outs, CC_Hexagon_Legacy);
|
2011-12-13 05:14:40 +08:00
|
|
|
else
|
|
|
|
CCInfo.AnalyzeCallOperands(Outs, CC_Hexagon);
|
|
|
|
|
2018-02-09 23:30:02 +08:00
|
|
|
if (CLI.IsTailCall) {
|
2017-12-16 06:22:58 +08:00
|
|
|
bool StructAttrFlag = MF.getFunction().hasStructRetAttr();
|
2018-02-09 23:30:02 +08:00
|
|
|
CLI.IsTailCall = IsEligibleForTailCallOptimization(Callee, CallConv,
|
|
|
|
IsVarArg, IsStructRet, StructAttrFlag, Outs,
|
|
|
|
OutVals, Ins, DAG);
|
2015-04-23 00:43:53 +08:00
|
|
|
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
|
2011-12-13 05:14:40 +08:00
|
|
|
CCValAssign &VA = ArgLocs[i];
|
|
|
|
if (VA.isMemLoc()) {
|
2018-02-09 23:30:02 +08:00
|
|
|
CLI.IsTailCall = false;
|
2011-12-13 05:14:40 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-05-14 20:53:11 +08:00
|
|
|
LLVM_DEBUG(dbgs() << (CLI.IsTailCall ? "Eligible for Tail Call\n"
|
|
|
|
: "Argument must be passed on stack. "
|
|
|
|
"Not eligible for Tail Call\n"));
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
|
|
|
// Get a count of how many bytes are to be pushed on the stack.
|
|
|
|
unsigned NumBytes = CCInfo.getNextStackOffset();
|
|
|
|
SmallVector<std::pair<unsigned, SDValue>, 16> RegsToPass;
|
|
|
|
SmallVector<SDValue, 8> MemOpChains;
|
|
|
|
|
2018-02-09 23:30:02 +08:00
|
|
|
const HexagonRegisterInfo &HRI = *Subtarget.getRegisterInfo();
|
2015-07-09 10:09:04 +08:00
|
|
|
SDValue StackPtr =
|
|
|
|
DAG.getCopyFromReg(Chain, dl, HRI.getStackRegister(), PtrVT);
|
2011-12-13 05:14:40 +08:00
|
|
|
|
2015-11-27 02:38:27 +08:00
|
|
|
bool NeedsArgAlign = false;
|
2020-03-19 00:04:10 +08:00
|
|
|
Align LargestAlignSeen;
|
2011-12-13 05:14:40 +08:00
|
|
|
// Walk the register/memloc assignments, inserting copies/loads.
|
|
|
|
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
|
|
|
|
CCValAssign &VA = ArgLocs[i];
|
|
|
|
SDValue Arg = OutVals[i];
|
|
|
|
ISD::ArgFlagsTy Flags = Outs[i].Flags;
|
2015-11-27 02:38:27 +08:00
|
|
|
// Record if we need > 8 byte alignment on an argument.
|
2017-11-28 02:12:16 +08:00
|
|
|
bool ArgAlign = Subtarget.isHVXVectorType(VA.getValVT());
|
2015-11-27 02:38:27 +08:00
|
|
|
NeedsArgAlign |= ArgAlign;
|
2011-12-13 05:14:40 +08:00
|
|
|
|
|
|
|
// Promote the value if needed.
|
|
|
|
switch (VA.getLocInfo()) {
|
|
|
|
default:
|
2017-12-20 22:44:05 +08:00
|
|
|
// Loc info must be one of Full, BCvt, SExt, ZExt, or AExt.
|
2012-02-07 10:50:20 +08:00
|
|
|
llvm_unreachable("Unknown loc info!");
|
2011-12-13 05:14:40 +08:00
|
|
|
case CCValAssign::Full:
|
|
|
|
break;
|
2017-12-20 22:44:05 +08:00
|
|
|
case CCValAssign::BCvt:
|
|
|
|
Arg = DAG.getBitcast(VA.getLocVT(), Arg);
|
|
|
|
break;
|
2011-12-13 05:14:40 +08:00
|
|
|
case CCValAssign::SExt:
|
|
|
|
Arg = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Arg);
|
|
|
|
break;
|
|
|
|
case CCValAssign::ZExt:
|
|
|
|
Arg = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), Arg);
|
|
|
|
break;
|
|
|
|
case CCValAssign::AExt:
|
|
|
|
Arg = DAG.getNode(ISD::ANY_EXTEND, dl, VA.getLocVT(), Arg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (VA.isMemLoc()) {
|
|
|
|
unsigned LocMemOffset = VA.getLocMemOffset();
|
2015-04-28 22:05:47 +08:00
|
|
|
SDValue MemAddr = DAG.getConstant(LocMemOffset, dl,
|
|
|
|
StackPtr.getValueType());
|
2015-04-23 00:43:53 +08:00
|
|
|
MemAddr = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, MemAddr);
|
2015-11-27 02:38:27 +08:00
|
|
|
if (ArgAlign)
|
2020-03-19 00:04:10 +08:00
|
|
|
LargestAlignSeen = std::max(
|
|
|
|
LargestAlignSeen, Align(VA.getLocVT().getStoreSizeInBits() / 8));
|
2011-12-13 05:14:40 +08:00
|
|
|
if (Flags.isByVal()) {
|
|
|
|
// The argument is a struct passed by value. According to LLVM, "Arg"
|
2018-03-31 06:22:31 +08:00
|
|
|
// is a pointer.
|
2015-04-23 00:43:53 +08:00
|
|
|
MemOpChains.push_back(CreateCopyOfByValArgument(Arg, MemAddr, Chain,
|
2011-12-13 05:14:40 +08:00
|
|
|
Flags, DAG, dl));
|
|
|
|
} else {
|
2015-08-12 07:09:45 +08:00
|
|
|
MachinePointerInfo LocPI = MachinePointerInfo::getStack(
|
|
|
|
DAG.getMachineFunction(), LocMemOffset);
|
[SelectionDAG] Get rid of bool parameters in SelectionDAG::getLoad, getStore, and friends.
Summary:
Instead, we take a single flags arg (a bitset).
Also add a default 0 alignment, and change the order of arguments so the
alignment comes before the flags.
This greatly simplifies many callsites, and fixes a bug in
AMDGPUISelLowering, wherein the order of the args to getLoad was
inverted. It also greatly simplifies the process of adding another flag
to getLoad.
Reviewers: chandlerc, tstellarAMD
Subscribers: jholewinski, arsenm, jyknight, dsanders, nemanjai, llvm-commits
Differential Revision: http://reviews.llvm.org/D22249
llvm-svn: 275592
2016-07-16 02:27:10 +08:00
|
|
|
SDValue S = DAG.getStore(Chain, dl, Arg, MemAddr, LocPI);
|
2015-04-23 00:43:53 +08:00
|
|
|
MemOpChains.push_back(S);
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Arguments that can be passed on register must be kept at RegsToPass
|
|
|
|
// vector.
|
2015-04-23 00:43:53 +08:00
|
|
|
if (VA.isRegLoc())
|
2011-12-13 05:14:40 +08:00
|
|
|
RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
|
|
|
|
}
|
|
|
|
|
2018-06-20 21:56:09 +08:00
|
|
|
if (NeedsArgAlign && Subtarget.hasV60Ops()) {
|
2018-05-14 20:53:11 +08:00
|
|
|
LLVM_DEBUG(dbgs() << "Function needs byte stack align due to call args\n");
|
2021-05-07 21:15:52 +08:00
|
|
|
Align VecAlign = HRI.getSpillAlign(Hexagon::HvxVRRegClass);
|
2018-02-09 23:30:02 +08:00
|
|
|
LargestAlignSeen = std::max(LargestAlignSeen, VecAlign);
|
2016-07-29 02:40:00 +08:00
|
|
|
MFI.ensureMaxAlignment(LargestAlignSeen);
|
2015-11-27 02:38:27 +08:00
|
|
|
}
|
2011-12-13 05:14:40 +08:00
|
|
|
// Transform all store nodes into one single node because all store
|
|
|
|
// nodes are independent of each other.
|
2015-04-23 00:43:53 +08:00
|
|
|
if (!MemOpChains.empty())
|
2014-04-27 02:35:24 +08:00
|
|
|
Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOpChains);
|
2011-12-13 05:14:40 +08:00
|
|
|
|
2017-02-18 06:14:51 +08:00
|
|
|
SDValue Glue;
|
2018-02-09 23:30:02 +08:00
|
|
|
if (!CLI.IsTailCall) {
|
2017-05-09 21:35:13 +08:00
|
|
|
Chain = DAG.getCALLSEQ_START(Chain, NumBytes, 0, dl);
|
2017-02-18 06:14:51 +08:00
|
|
|
Glue = Chain.getValue(1);
|
2015-04-23 00:43:53 +08:00
|
|
|
}
|
2011-12-13 05:14:40 +08:00
|
|
|
|
|
|
|
// Build a sequence of copy-to-reg nodes chained together with token
|
|
|
|
// chain and flag operands which copy the outgoing args into registers.
|
2016-08-02 04:31:50 +08:00
|
|
|
// The Glue is necessary since all emitted instructions must be
|
2011-12-13 05:14:40 +08:00
|
|
|
// stuck together.
|
2018-02-09 23:30:02 +08:00
|
|
|
if (!CLI.IsTailCall) {
|
2011-12-13 05:14:40 +08:00
|
|
|
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
|
|
|
|
Chain = DAG.getCopyToReg(Chain, dl, RegsToPass[i].first,
|
2016-08-02 04:31:50 +08:00
|
|
|
RegsToPass[i].second, Glue);
|
|
|
|
Glue = Chain.getValue(1);
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
2015-04-23 00:43:53 +08:00
|
|
|
} else {
|
|
|
|
// For tail calls lower the arguments to the 'real' stack slot.
|
|
|
|
//
|
2011-12-13 05:14:40 +08:00
|
|
|
// Force all the incoming stack arguments to be loaded from the stack
|
|
|
|
// before any new outgoing arguments are stored to the stack, because the
|
|
|
|
// outgoing stack slots may alias the incoming argument stack slots, and
|
|
|
|
// the alias isn't otherwise explicit. This is slightly more conservative
|
|
|
|
// than necessary, because it means that each store effectively depends
|
|
|
|
// on every argument instead of just those arguments it would clobber.
|
|
|
|
//
|
2012-06-02 18:20:22 +08:00
|
|
|
// Do not flag preceding copytoreg stuff together with the following stuff.
|
2016-08-02 04:31:50 +08:00
|
|
|
Glue = SDValue();
|
2011-12-13 05:14:40 +08:00
|
|
|
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
|
|
|
|
Chain = DAG.getCopyToReg(Chain, dl, RegsToPass[i].first,
|
2016-08-02 04:31:50 +08:00
|
|
|
RegsToPass[i].second, Glue);
|
|
|
|
Glue = Chain.getValue(1);
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
2016-08-02 04:31:50 +08:00
|
|
|
Glue = SDValue();
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
|
|
|
|
2016-07-25 22:42:11 +08:00
|
|
|
bool LongCalls = MF.getSubtarget<HexagonSubtarget>().useLongCalls();
|
|
|
|
unsigned Flags = LongCalls ? HexagonII::HMOTF_ConstExtended : 0;
|
|
|
|
|
2011-12-13 05:14:40 +08:00
|
|
|
// If the callee is a GlobalAddress/ExternalSymbol node (quite common, every
|
|
|
|
// direct call is) turn it into a TargetGlobalAddress/TargetExternalSymbol
|
|
|
|
// node so that legalize doesn't hack it.
|
2015-12-17 01:29:37 +08:00
|
|
|
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
|
2016-07-25 22:42:11 +08:00
|
|
|
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, PtrVT, 0, Flags);
|
2011-12-13 05:14:40 +08:00
|
|
|
} else if (ExternalSymbolSDNode *S =
|
|
|
|
dyn_cast<ExternalSymbolSDNode>(Callee)) {
|
2016-07-25 22:42:11 +08:00
|
|
|
Callee = DAG.getTargetExternalSymbol(S->getSymbol(), PtrVT, Flags);
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Returns a chain & a flag for retval copy to use.
|
|
|
|
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
|
|
|
|
SmallVector<SDValue, 8> Ops;
|
|
|
|
Ops.push_back(Chain);
|
|
|
|
Ops.push_back(Callee);
|
|
|
|
|
|
|
|
// Add argument registers to the end of the list so that they are
|
|
|
|
// known live into the call.
|
|
|
|
for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
|
|
|
|
Ops.push_back(DAG.getRegister(RegsToPass[i].first,
|
|
|
|
RegsToPass[i].second.getValueType()));
|
|
|
|
}
|
|
|
|
|
2017-02-18 06:14:51 +08:00
|
|
|
const uint32_t *Mask = HRI.getCallPreservedMask(MF, CallConv);
|
|
|
|
assert(Mask && "Missing call preserved mask for calling convention");
|
|
|
|
Ops.push_back(DAG.getRegisterMask(Mask));
|
|
|
|
|
2016-08-02 04:31:50 +08:00
|
|
|
if (Glue.getNode())
|
|
|
|
Ops.push_back(Glue);
|
2011-12-13 05:14:40 +08:00
|
|
|
|
2018-02-09 23:30:02 +08:00
|
|
|
if (CLI.IsTailCall) {
|
2017-07-12 01:11:54 +08:00
|
|
|
MFI.setHasTailCall();
|
2014-04-27 02:35:24 +08:00
|
|
|
return DAG.getNode(HexagonISD::TC_RETURN, dl, NodeTys, Ops);
|
2015-05-09 07:52:00 +08:00
|
|
|
}
|
2011-12-13 05:14:40 +08:00
|
|
|
|
2017-07-12 01:11:54 +08:00
|
|
|
// Set this here because we need to know this for "hasFP" in frame lowering.
|
|
|
|
// The target-independent code calls getFrameRegister before setting it, and
|
|
|
|
// getFrameRegister uses hasFP to determine whether the function has FP.
|
|
|
|
MFI.setHasCalls(true);
|
|
|
|
|
2016-08-12 19:12:02 +08:00
|
|
|
unsigned OpCode = DoesNotReturn ? HexagonISD::CALLnr : HexagonISD::CALL;
|
2015-01-17 01:05:27 +08:00
|
|
|
Chain = DAG.getNode(OpCode, dl, NodeTys, Ops);
|
2016-08-02 04:31:50 +08:00
|
|
|
Glue = Chain.getValue(1);
|
2011-12-13 05:14:40 +08:00
|
|
|
|
|
|
|
// Create the CALLSEQ_END node.
|
2015-04-28 22:05:47 +08:00
|
|
|
Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(NumBytes, dl, true),
|
2016-08-02 04:31:50 +08:00
|
|
|
DAG.getIntPtrConstant(0, dl, true), Glue, dl);
|
|
|
|
Glue = Chain.getValue(1);
|
2011-12-13 05:14:40 +08:00
|
|
|
|
|
|
|
// Handle result values, copying them out of physregs into vregs that we
|
|
|
|
// return.
|
2016-08-02 04:31:50 +08:00
|
|
|
return LowerCallResult(Chain, Glue, CallConv, IsVarArg, Ins, dl, DAG,
|
2011-12-13 05:14:40 +08:00
|
|
|
InVals, OutVals, Callee);
|
|
|
|
}
|
|
|
|
|
2018-02-13 23:35:07 +08:00
|
|
|
/// Returns true by value, base pointer and offset pointer and addressing
|
|
|
|
/// mode by reference if this node can be combined with a load / store to
|
|
|
|
/// form a post-indexed load / store.
|
2011-12-13 05:14:40 +08:00
|
|
|
bool HexagonTargetLowering::getPostIndexedAddressParts(SDNode *N, SDNode *Op,
|
2018-02-13 23:35:07 +08:00
|
|
|
SDValue &Base, SDValue &Offset, ISD::MemIndexedMode &AM,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
LSBaseSDNode *LSN = dyn_cast<LSBaseSDNode>(N);
|
|
|
|
if (!LSN)
|
|
|
|
return false;
|
|
|
|
EVT VT = LSN->getMemoryVT();
|
|
|
|
if (!VT.isSimple())
|
|
|
|
return false;
|
2018-03-08 01:27:18 +08:00
|
|
|
bool IsLegalType = VT == MVT::i8 || VT == MVT::i16 || VT == MVT::i32 ||
|
2018-05-19 02:14:44 +08:00
|
|
|
VT == MVT::i64 || VT == MVT::f32 || VT == MVT::f64 ||
|
|
|
|
VT == MVT::v2i16 || VT == MVT::v2i32 || VT == MVT::v4i8 ||
|
|
|
|
VT == MVT::v4i16 || VT == MVT::v8i8 ||
|
2018-02-13 23:35:07 +08:00
|
|
|
Subtarget.isHVXVectorType(VT.getSimpleVT());
|
|
|
|
if (!IsLegalType)
|
2011-12-13 05:14:40 +08:00
|
|
|
return false;
|
|
|
|
|
2018-02-13 23:35:07 +08:00
|
|
|
if (Op->getOpcode() != ISD::ADD)
|
|
|
|
return false;
|
|
|
|
Base = Op->getOperand(0);
|
|
|
|
Offset = Op->getOperand(1);
|
|
|
|
if (!isa<ConstantSDNode>(Offset.getNode()))
|
|
|
|
return false;
|
|
|
|
AM = ISD::POST_INC;
|
2011-12-13 05:14:40 +08:00
|
|
|
|
2018-02-13 23:35:07 +08:00
|
|
|
int32_t V = cast<ConstantSDNode>(Offset.getNode())->getSExtValue();
|
|
|
|
return Subtarget.getInstrInfo()->isValidAutoIncImm(VT, V);
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
|
|
|
|
2015-12-19 04:19:30 +08:00
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerINLINEASM(SDValue Op, SelectionDAG &DAG) const {
|
2011-12-13 05:14:40 +08:00
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
2017-07-01 05:21:40 +08:00
|
|
|
auto &HMFI = *MF.getInfo<HexagonMachineFunctionInfo>();
|
|
|
|
const HexagonRegisterInfo &HRI = *Subtarget.getRegisterInfo();
|
|
|
|
unsigned LR = HRI.getRARegister();
|
|
|
|
|
2019-02-09 04:48:56 +08:00
|
|
|
if ((Op.getOpcode() != ISD::INLINEASM &&
|
|
|
|
Op.getOpcode() != ISD::INLINEASM_BR) || HMFI.hasClobberLR())
|
2017-07-01 05:21:40 +08:00
|
|
|
return Op;
|
|
|
|
|
|
|
|
unsigned NumOps = Op.getNumOperands();
|
|
|
|
if (Op.getOperand(NumOps-1).getValueType() == MVT::Glue)
|
|
|
|
--NumOps; // Ignore the flag operand.
|
|
|
|
|
|
|
|
for (unsigned i = InlineAsm::Op_FirstOperand; i != NumOps;) {
|
|
|
|
unsigned Flags = cast<ConstantSDNode>(Op.getOperand(i))->getZExtValue();
|
|
|
|
unsigned NumVals = InlineAsm::getNumOperandRegisters(Flags);
|
|
|
|
++i; // Skip the ID value.
|
|
|
|
|
|
|
|
switch (InlineAsm::getKind(Flags)) {
|
|
|
|
default:
|
|
|
|
llvm_unreachable("Bad flags!");
|
|
|
|
case InlineAsm::Kind_RegUse:
|
|
|
|
case InlineAsm::Kind_Imm:
|
|
|
|
case InlineAsm::Kind_Mem:
|
|
|
|
i += NumVals;
|
|
|
|
break;
|
|
|
|
case InlineAsm::Kind_Clobber:
|
|
|
|
case InlineAsm::Kind_RegDef:
|
|
|
|
case InlineAsm::Kind_RegDefEarlyClobber: {
|
|
|
|
for (; NumVals; --NumVals, ++i) {
|
|
|
|
unsigned Reg = cast<RegisterSDNode>(Op.getOperand(i))->getReg();
|
|
|
|
if (Reg != LR)
|
|
|
|
continue;
|
|
|
|
HMFI.setHasClobberLR(true);
|
|
|
|
return Op;
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
2017-07-01 05:21:40 +08:00
|
|
|
break;
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
|
|
|
}
|
2017-07-01 05:21:40 +08:00
|
|
|
}
|
|
|
|
|
2011-12-13 05:14:40 +08:00
|
|
|
return Op;
|
|
|
|
}
|
|
|
|
|
2016-02-18 21:58:38 +08:00
|
|
|
// Need to transform ISD::PREFETCH into something that doesn't inherit
|
|
|
|
// all of the properties of ISD::PREFETCH, specifically SDNPMayLoad and
|
|
|
|
// SDNPMayStore.
|
|
|
|
SDValue HexagonTargetLowering::LowerPREFETCH(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
SDValue Chain = Op.getOperand(0);
|
|
|
|
SDValue Addr = Op.getOperand(1);
|
|
|
|
// Lower it to DCFETCH($reg, #0). A "pat" will try to merge the offset in,
|
|
|
|
// if the "reg" is fed by an "add".
|
|
|
|
SDLoc DL(Op);
|
|
|
|
SDValue Zero = DAG.getConstant(0, DL, MVT::i32);
|
|
|
|
return DAG.getNode(HexagonISD::DCFETCH, DL, MVT::Other, Chain, Addr, Zero);
|
|
|
|
}
|
|
|
|
|
2017-02-23 06:28:47 +08:00
|
|
|
// Custom-handle ISD::READCYCLECOUNTER because the target-independent SDNode
|
|
|
|
// is marked as having side-effects, while the register read on Hexagon does
|
|
|
|
// not have any. TableGen refuses to accept the direct pattern from that node
|
|
|
|
// to the A4_tfrcpp.
|
|
|
|
SDValue HexagonTargetLowering::LowerREADCYCLECOUNTER(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
SDValue Chain = Op.getOperand(0);
|
|
|
|
SDLoc dl(Op);
|
2021-03-20 01:47:32 +08:00
|
|
|
SDVTList VTs = DAG.getVTList(MVT::i64, MVT::Other);
|
2017-02-23 06:28:47 +08:00
|
|
|
return DAG.getNode(HexagonISD::READCYCLE, dl, VTs, Chain);
|
|
|
|
}
|
|
|
|
|
2016-02-18 21:58:38 +08:00
|
|
|
SDValue HexagonTargetLowering::LowerINTRINSIC_VOID(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
SDValue Chain = Op.getOperand(0);
|
|
|
|
unsigned IntNo = cast<ConstantSDNode>(Op.getOperand(1))->getZExtValue();
|
|
|
|
// Lower the hexagon_prefetch builtin to DCFETCH, as above.
|
|
|
|
if (IntNo == Intrinsic::hexagon_prefetch) {
|
|
|
|
SDValue Addr = Op.getOperand(2);
|
|
|
|
SDLoc DL(Op);
|
|
|
|
SDValue Zero = DAG.getConstant(0, DL, MVT::i32);
|
|
|
|
return DAG.getNode(HexagonISD::DCFETCH, DL, MVT::Other, Chain, Addr, Zero);
|
|
|
|
}
|
|
|
|
return SDValue();
|
|
|
|
}
|
|
|
|
|
2011-12-13 05:14:40 +08:00
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerDYNAMIC_STACKALLOC(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
SDValue Chain = Op.getOperand(0);
|
|
|
|
SDValue Size = Op.getOperand(1);
|
2015-04-23 00:43:53 +08:00
|
|
|
SDValue Align = Op.getOperand(2);
|
2013-05-25 10:42:55 +08:00
|
|
|
SDLoc dl(Op);
|
2011-12-13 05:14:40 +08:00
|
|
|
|
2015-04-23 00:43:53 +08:00
|
|
|
ConstantSDNode *AlignConst = dyn_cast<ConstantSDNode>(Align);
|
|
|
|
assert(AlignConst && "Non-constant Align in LowerDYNAMIC_STACKALLOC");
|
|
|
|
|
|
|
|
unsigned A = AlignConst->getSExtValue();
|
2015-04-23 05:17:00 +08:00
|
|
|
auto &HFI = *Subtarget.getFrameLowering();
|
2015-04-23 00:43:53 +08:00
|
|
|
// "Zero" means natural stack alignment.
|
|
|
|
if (A == 0)
|
[Alignment][NFC] Use llvmTargetFrameLowering::getStackAlign
Summary:
This is patch is part of a series to introduce an Alignment type.
See this thread for context: http://lists.llvm.org/pipermail/llvm-dev/2019-July/133851.html
See this patch for the introduction of the type: https://reviews.llvm.org/D64790
Reviewers: courbet
Reviewed By: courbet
Subscribers: wuzish, arsenm, jyknight, nemanjai, jvesely, nhaehnle, hiraditya, kbarton, fedor.sergeev, jrtc27, kerbowa, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D76613
2020-03-27 01:51:25 +08:00
|
|
|
A = HFI.getStackAlign().value();
|
2015-04-23 00:43:53 +08:00
|
|
|
|
2018-05-14 20:53:11 +08:00
|
|
|
LLVM_DEBUG({
|
2016-10-20 08:22:23 +08:00
|
|
|
dbgs () << __func__ << " Align: " << A << " Size: ";
|
2015-04-23 00:43:53 +08:00
|
|
|
Size.getNode()->dump(&DAG);
|
|
|
|
dbgs() << "\n";
|
|
|
|
});
|
|
|
|
|
2015-04-28 22:05:47 +08:00
|
|
|
SDValue AC = DAG.getConstant(A, dl, MVT::i32);
|
2015-04-23 00:43:53 +08:00
|
|
|
SDVTList VTs = DAG.getVTList(MVT::i32, MVT::Other);
|
2015-10-20 02:30:27 +08:00
|
|
|
SDValue AA = DAG.getNode(HexagonISD::ALLOCA, dl, VTs, Chain, Size, AC);
|
2016-06-24 01:52:57 +08:00
|
|
|
|
|
|
|
DAG.ReplaceAllUsesOfValueWith(Op, AA);
|
2015-10-20 02:30:27 +08:00
|
|
|
return AA;
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
|
|
|
|
2016-06-12 23:39:02 +08:00
|
|
|
SDValue HexagonTargetLowering::LowerFormalArguments(
|
2018-02-09 23:30:02 +08:00
|
|
|
SDValue Chain, CallingConv::ID CallConv, bool IsVarArg,
|
2016-06-12 23:39:02 +08:00
|
|
|
const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl,
|
|
|
|
SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const {
|
2011-12-13 05:14:40 +08:00
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
2016-07-29 02:40:00 +08:00
|
|
|
MachineFrameInfo &MFI = MF.getFrameInfo();
|
2018-02-09 23:30:02 +08:00
|
|
|
MachineRegisterInfo &MRI = MF.getRegInfo();
|
2011-12-13 05:14:40 +08:00
|
|
|
|
Add support for Linux/Musl ABI
Differential revision: https://reviews.llvm.org/D72701
The patch adds a new option ABI for Hexagon. It primary deals with
the way variable arguments are passed and is use in the Hexagon Linux Musl
environment.
If a callee function has a variable argument list, it must perform the
following operations to set up its function prologue:
1. Determine the number of registers which could have been used for passing
unnamed arguments. This can be calculated by counting the number of
registers used for passing named arguments. For example, if the callee
function is as follows:
int foo(int a, ...){ ... }
... then register R0 is used to access the argument ' a '. The registers
available for passing unnamed arguments are R1, R2, R3, R4, and R5.
2. Determine the number and size of the named arguments on the stack.
3. If the callee has named arguments on the stack, it should copy all of these
arguments to a location below the current position on the stack, and the
difference should be the size of the register-saved area plus padding
(if any is necessary).
The register-saved area constitutes all the registers that could have
been used to pass unnamed arguments. If the number of registers forming
the register-saved area is odd, it requires 4 bytes of padding; if the
number is even, no padding is required. This is done to ensure an 8-byte
alignment on the stack. For example, if the callee is as follows:
int foo(int a, ...){ ... }
... then the named arguments should be copied to the following location:
current_position - 5 (for R1-R5) * 4 (bytes) - 4 (bytes of padding)
If the callee is as follows:
int foo(int a, int b, ...){ ... }
... then the named arguments should be copied to the following location:
current_position - 4 (for R2-R5) * 4 (bytes) - 0 (bytes of padding)
4. After any named arguments have been copied, copy all the registers that
could have been used to pass unnamed arguments on the stack. If the number
of registers is odd, leave 4 bytes of padding and then start copying them
on the stack; if the number is even, no padding is required. This
constitutes the register-saved area. If padding is required, ensure
that the start location of padding is 8-byte aligned. If no padding is
required, ensure that the start location of the on-stack copy of the
first register which might have a variable argument is 8-byte aligned.
5. Decrement the stack pointer by the size of register saved area plus the
padding. For example, if the callee is as follows:
int foo(int a, ...){ ... } ;
... then the decrement value should be the following:
5 (for R1-R5) * 4 (bytes) + 4 (bytes of padding) = 24 bytes
The decrement should be performed before the allocframe instruction.
Increment the stack-pointer back by the same amount before returning
from the function.
2019-12-28 03:03:01 +08:00
|
|
|
// Linux ABI treats var-arg calls the same way as regular ones.
|
|
|
|
bool TreatAsVarArg = !Subtarget.isEnvironmentMusl() && IsVarArg;
|
|
|
|
|
2011-12-13 05:14:40 +08:00
|
|
|
// Assign locations to all of the incoming arguments.
|
|
|
|
SmallVector<CCValAssign, 16> ArgLocs;
|
Add support for Linux/Musl ABI
Differential revision: https://reviews.llvm.org/D72701
The patch adds a new option ABI for Hexagon. It primary deals with
the way variable arguments are passed and is use in the Hexagon Linux Musl
environment.
If a callee function has a variable argument list, it must perform the
following operations to set up its function prologue:
1. Determine the number of registers which could have been used for passing
unnamed arguments. This can be calculated by counting the number of
registers used for passing named arguments. For example, if the callee
function is as follows:
int foo(int a, ...){ ... }
... then register R0 is used to access the argument ' a '. The registers
available for passing unnamed arguments are R1, R2, R3, R4, and R5.
2. Determine the number and size of the named arguments on the stack.
3. If the callee has named arguments on the stack, it should copy all of these
arguments to a location below the current position on the stack, and the
difference should be the size of the register-saved area plus padding
(if any is necessary).
The register-saved area constitutes all the registers that could have
been used to pass unnamed arguments. If the number of registers forming
the register-saved area is odd, it requires 4 bytes of padding; if the
number is even, no padding is required. This is done to ensure an 8-byte
alignment on the stack. For example, if the callee is as follows:
int foo(int a, ...){ ... }
... then the named arguments should be copied to the following location:
current_position - 5 (for R1-R5) * 4 (bytes) - 4 (bytes of padding)
If the callee is as follows:
int foo(int a, int b, ...){ ... }
... then the named arguments should be copied to the following location:
current_position - 4 (for R2-R5) * 4 (bytes) - 0 (bytes of padding)
4. After any named arguments have been copied, copy all the registers that
could have been used to pass unnamed arguments on the stack. If the number
of registers is odd, leave 4 bytes of padding and then start copying them
on the stack; if the number is even, no padding is required. This
constitutes the register-saved area. If padding is required, ensure
that the start location of padding is 8-byte aligned. If no padding is
required, ensure that the start location of the on-stack copy of the
first register which might have a variable argument is 8-byte aligned.
5. Decrement the stack pointer by the size of register saved area plus the
padding. For example, if the callee is as follows:
int foo(int a, ...){ ... } ;
... then the decrement value should be the following:
5 (for R1-R5) * 4 (bytes) + 4 (bytes of padding) = 24 bytes
The decrement should be performed before the allocframe instruction.
Increment the stack-pointer back by the same amount before returning
from the function.
2019-12-28 03:03:01 +08:00
|
|
|
HexagonCCState CCInfo(CallConv, TreatAsVarArg, MF, ArgLocs,
|
|
|
|
*DAG.getContext(),
|
2018-02-16 01:20:07 +08:00
|
|
|
MF.getFunction().getFunctionType()->getNumParams());
|
2011-12-13 05:14:40 +08:00
|
|
|
|
2018-02-09 23:30:02 +08:00
|
|
|
if (Subtarget.useHVXOps())
|
|
|
|
CCInfo.AnalyzeFormalArguments(Ins, CC_Hexagon_HVX);
|
2020-06-23 05:03:22 +08:00
|
|
|
else if (DisableArgsMinAlignment)
|
|
|
|
CCInfo.AnalyzeFormalArguments(Ins, CC_Hexagon_Legacy);
|
2018-02-09 23:30:02 +08:00
|
|
|
else
|
|
|
|
CCInfo.AnalyzeFormalArguments(Ins, CC_Hexagon);
|
2011-12-13 05:14:40 +08:00
|
|
|
|
|
|
|
// For LLVM, in the case when returning a struct by value (>8byte),
|
|
|
|
// the first argument is a pointer that points to the location on caller's
|
|
|
|
// stack where the return value will be stored. For Hexagon, the location on
|
|
|
|
// caller's stack is passed only when the struct size is smaller than (and
|
|
|
|
// equal to) 8 bytes. If not, no address will be passed into callee and
|
|
|
|
// callee return the result direclty through R0/R1.
|
Add support for Linux/Musl ABI
Differential revision: https://reviews.llvm.org/D72701
The patch adds a new option ABI for Hexagon. It primary deals with
the way variable arguments are passed and is use in the Hexagon Linux Musl
environment.
If a callee function has a variable argument list, it must perform the
following operations to set up its function prologue:
1. Determine the number of registers which could have been used for passing
unnamed arguments. This can be calculated by counting the number of
registers used for passing named arguments. For example, if the callee
function is as follows:
int foo(int a, ...){ ... }
... then register R0 is used to access the argument ' a '. The registers
available for passing unnamed arguments are R1, R2, R3, R4, and R5.
2. Determine the number and size of the named arguments on the stack.
3. If the callee has named arguments on the stack, it should copy all of these
arguments to a location below the current position on the stack, and the
difference should be the size of the register-saved area plus padding
(if any is necessary).
The register-saved area constitutes all the registers that could have
been used to pass unnamed arguments. If the number of registers forming
the register-saved area is odd, it requires 4 bytes of padding; if the
number is even, no padding is required. This is done to ensure an 8-byte
alignment on the stack. For example, if the callee is as follows:
int foo(int a, ...){ ... }
... then the named arguments should be copied to the following location:
current_position - 5 (for R1-R5) * 4 (bytes) - 4 (bytes of padding)
If the callee is as follows:
int foo(int a, int b, ...){ ... }
... then the named arguments should be copied to the following location:
current_position - 4 (for R2-R5) * 4 (bytes) - 0 (bytes of padding)
4. After any named arguments have been copied, copy all the registers that
could have been used to pass unnamed arguments on the stack. If the number
of registers is odd, leave 4 bytes of padding and then start copying them
on the stack; if the number is even, no padding is required. This
constitutes the register-saved area. If padding is required, ensure
that the start location of padding is 8-byte aligned. If no padding is
required, ensure that the start location of the on-stack copy of the
first register which might have a variable argument is 8-byte aligned.
5. Decrement the stack pointer by the size of register saved area plus the
padding. For example, if the callee is as follows:
int foo(int a, ...){ ... } ;
... then the decrement value should be the following:
5 (for R1-R5) * 4 (bytes) + 4 (bytes of padding) = 24 bytes
The decrement should be performed before the allocframe instruction.
Increment the stack-pointer back by the same amount before returning
from the function.
2019-12-28 03:03:01 +08:00
|
|
|
auto NextSingleReg = [] (const TargetRegisterClass &RC, unsigned Reg) {
|
|
|
|
switch (RC.getID()) {
|
|
|
|
case Hexagon::IntRegsRegClassID:
|
|
|
|
return Reg - Hexagon::R0 + 1;
|
|
|
|
case Hexagon::DoubleRegsRegClassID:
|
|
|
|
return (Reg - Hexagon::D0 + 1) * 2;
|
|
|
|
case Hexagon::HvxVRRegClassID:
|
|
|
|
return Reg - Hexagon::V0 + 1;
|
|
|
|
case Hexagon::HvxWRRegClassID:
|
|
|
|
return (Reg - Hexagon::W0 + 1) * 2;
|
|
|
|
}
|
|
|
|
llvm_unreachable("Unexpected register class");
|
|
|
|
};
|
2011-12-13 05:14:40 +08:00
|
|
|
|
Add support for Linux/Musl ABI
Differential revision: https://reviews.llvm.org/D72701
The patch adds a new option ABI for Hexagon. It primary deals with
the way variable arguments are passed and is use in the Hexagon Linux Musl
environment.
If a callee function has a variable argument list, it must perform the
following operations to set up its function prologue:
1. Determine the number of registers which could have been used for passing
unnamed arguments. This can be calculated by counting the number of
registers used for passing named arguments. For example, if the callee
function is as follows:
int foo(int a, ...){ ... }
... then register R0 is used to access the argument ' a '. The registers
available for passing unnamed arguments are R1, R2, R3, R4, and R5.
2. Determine the number and size of the named arguments on the stack.
3. If the callee has named arguments on the stack, it should copy all of these
arguments to a location below the current position on the stack, and the
difference should be the size of the register-saved area plus padding
(if any is necessary).
The register-saved area constitutes all the registers that could have
been used to pass unnamed arguments. If the number of registers forming
the register-saved area is odd, it requires 4 bytes of padding; if the
number is even, no padding is required. This is done to ensure an 8-byte
alignment on the stack. For example, if the callee is as follows:
int foo(int a, ...){ ... }
... then the named arguments should be copied to the following location:
current_position - 5 (for R1-R5) * 4 (bytes) - 4 (bytes of padding)
If the callee is as follows:
int foo(int a, int b, ...){ ... }
... then the named arguments should be copied to the following location:
current_position - 4 (for R2-R5) * 4 (bytes) - 0 (bytes of padding)
4. After any named arguments have been copied, copy all the registers that
could have been used to pass unnamed arguments on the stack. If the number
of registers is odd, leave 4 bytes of padding and then start copying them
on the stack; if the number is even, no padding is required. This
constitutes the register-saved area. If padding is required, ensure
that the start location of padding is 8-byte aligned. If no padding is
required, ensure that the start location of the on-stack copy of the
first register which might have a variable argument is 8-byte aligned.
5. Decrement the stack pointer by the size of register saved area plus the
padding. For example, if the callee is as follows:
int foo(int a, ...){ ... } ;
... then the decrement value should be the following:
5 (for R1-R5) * 4 (bytes) + 4 (bytes of padding) = 24 bytes
The decrement should be performed before the allocframe instruction.
Increment the stack-pointer back by the same amount before returning
from the function.
2019-12-28 03:03:01 +08:00
|
|
|
auto &HFL = const_cast<HexagonFrameLowering&>(*Subtarget.getFrameLowering());
|
2018-02-09 23:30:02 +08:00
|
|
|
auto &HMFI = *MF.getInfo<HexagonMachineFunctionInfo>();
|
Add support for Linux/Musl ABI
Differential revision: https://reviews.llvm.org/D72701
The patch adds a new option ABI for Hexagon. It primary deals with
the way variable arguments are passed and is use in the Hexagon Linux Musl
environment.
If a callee function has a variable argument list, it must perform the
following operations to set up its function prologue:
1. Determine the number of registers which could have been used for passing
unnamed arguments. This can be calculated by counting the number of
registers used for passing named arguments. For example, if the callee
function is as follows:
int foo(int a, ...){ ... }
... then register R0 is used to access the argument ' a '. The registers
available for passing unnamed arguments are R1, R2, R3, R4, and R5.
2. Determine the number and size of the named arguments on the stack.
3. If the callee has named arguments on the stack, it should copy all of these
arguments to a location below the current position on the stack, and the
difference should be the size of the register-saved area plus padding
(if any is necessary).
The register-saved area constitutes all the registers that could have
been used to pass unnamed arguments. If the number of registers forming
the register-saved area is odd, it requires 4 bytes of padding; if the
number is even, no padding is required. This is done to ensure an 8-byte
alignment on the stack. For example, if the callee is as follows:
int foo(int a, ...){ ... }
... then the named arguments should be copied to the following location:
current_position - 5 (for R1-R5) * 4 (bytes) - 4 (bytes of padding)
If the callee is as follows:
int foo(int a, int b, ...){ ... }
... then the named arguments should be copied to the following location:
current_position - 4 (for R2-R5) * 4 (bytes) - 0 (bytes of padding)
4. After any named arguments have been copied, copy all the registers that
could have been used to pass unnamed arguments on the stack. If the number
of registers is odd, leave 4 bytes of padding and then start copying them
on the stack; if the number is even, no padding is required. This
constitutes the register-saved area. If padding is required, ensure
that the start location of padding is 8-byte aligned. If no padding is
required, ensure that the start location of the on-stack copy of the
first register which might have a variable argument is 8-byte aligned.
5. Decrement the stack pointer by the size of register saved area plus the
padding. For example, if the callee is as follows:
int foo(int a, ...){ ... } ;
... then the decrement value should be the following:
5 (for R1-R5) * 4 (bytes) + 4 (bytes of padding) = 24 bytes
The decrement should be performed before the allocframe instruction.
Increment the stack-pointer back by the same amount before returning
from the function.
2019-12-28 03:03:01 +08:00
|
|
|
HFL.FirstVarArgSavedReg = 0;
|
|
|
|
HMFI.setFirstNamedArgFrameIndex(-int(MFI.getNumFixedObjects()));
|
2011-12-13 05:14:40 +08:00
|
|
|
|
|
|
|
for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
|
|
|
|
CCValAssign &VA = ArgLocs[i];
|
|
|
|
ISD::ArgFlagsTy Flags = Ins[i].Flags;
|
2018-02-09 23:30:02 +08:00
|
|
|
bool ByVal = Flags.isByVal();
|
|
|
|
|
|
|
|
// Arguments passed in registers:
|
|
|
|
// 1. 32- and 64-bit values and HVX vectors are passed directly,
|
|
|
|
// 2. Large structs are passed via an address, and the address is
|
|
|
|
// passed in a register.
|
|
|
|
if (VA.isRegLoc() && ByVal && Flags.getByValSize() <= 8)
|
|
|
|
llvm_unreachable("ByValSize must be bigger than 8 bytes");
|
|
|
|
|
|
|
|
bool InReg = VA.isRegLoc() &&
|
|
|
|
(!ByVal || (ByVal && Flags.getByValSize() > 8));
|
|
|
|
|
|
|
|
if (InReg) {
|
|
|
|
MVT RegVT = VA.getLocVT();
|
|
|
|
if (VA.getLocInfo() == CCValAssign::BCvt)
|
|
|
|
RegVT = VA.getValVT();
|
|
|
|
|
|
|
|
const TargetRegisterClass *RC = getRegClassFor(RegVT);
|
Apply llvm-prefer-register-over-unsigned from clang-tidy to LLVM
Summary:
This clang-tidy check is looking for unsigned integer variables whose initializer
starts with an implicit cast from llvm::Register and changes the type of the
variable to llvm::Register (dropping the llvm:: where possible).
Partial reverts in:
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
X86FixupLEAs.cpp - Some functions return unsigned and arguably should be MCRegister
X86FrameLowering.cpp - Some functions return unsigned and arguably should be MCRegister
HexagonBitSimplify.cpp - Function takes BitTracker::RegisterRef which appears to be unsigned&
MachineVerifier.cpp - Ambiguous operator==() given MCRegister and const Register
PPCFastISel.cpp - No Register::operator-=()
PeepholeOptimizer.cpp - TargetInstrInfo::optimizeLoadInstr() takes an unsigned&
MachineTraceMetrics.cpp - MachineTraceMetrics lacks a suitable constructor
Manual fixups in:
ARMFastISel.cpp - ARMEmitLoad() now takes a Register& instead of unsigned&
HexagonSplitDouble.cpp - Ternary operator was ambiguous between unsigned/Register
HexagonConstExtenders.cpp - Has a local class named Register, used llvm::Register instead of Register.
PPCFastISel.cpp - PPCEmitLoad() now takes a Register& instead of unsigned&
Depends on D65919
Reviewers: arsenm, bogner, craig.topper, RKSimon
Reviewed By: arsenm
Subscribers: RKSimon, craig.topper, lenary, aemerson, wuzish, jholewinski, MatzeB, qcolombet, dschuff, jyknight, dylanmckay, sdardis, nemanjai, jvesely, wdng, nhaehnle, sbc100, jgravelle-google, kristof.beyls, hiraditya, aheejin, kbarton, fedor.sergeev, javed.absar, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, tpr, PkmX, jocewei, jsji, Petar.Avramovic, asbirlea, Jim, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65962
llvm-svn: 369041
2019-08-16 03:22:08 +08:00
|
|
|
Register VReg = MRI.createVirtualRegister(RC);
|
2018-02-09 23:30:02 +08:00
|
|
|
SDValue Copy = DAG.getCopyFromReg(Chain, dl, VReg, RegVT);
|
|
|
|
|
|
|
|
// Treat values of type MVT::i1 specially: they are passed in
|
|
|
|
// registers of type i32, but they need to remain as values of
|
|
|
|
// type i1 for consistency of the argument lowering.
|
|
|
|
if (VA.getValVT() == MVT::i1) {
|
|
|
|
assert(RegVT.getSizeInBits() <= 32);
|
|
|
|
SDValue T = DAG.getNode(ISD::AND, dl, RegVT,
|
|
|
|
Copy, DAG.getConstant(1, dl, RegVT));
|
|
|
|
Copy = DAG.getSetCC(dl, MVT::i1, T, DAG.getConstant(0, dl, RegVT),
|
|
|
|
ISD::SETNE);
|
2011-12-13 05:14:40 +08:00
|
|
|
} else {
|
2018-02-09 23:30:02 +08:00
|
|
|
#ifndef NDEBUG
|
|
|
|
unsigned RegSize = RegVT.getSizeInBits();
|
|
|
|
assert(RegSize == 32 || RegSize == 64 ||
|
|
|
|
Subtarget.isHVXVectorType(RegVT));
|
|
|
|
#endif
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
2018-02-09 23:30:02 +08:00
|
|
|
InVals.push_back(Copy);
|
|
|
|
MRI.addLiveIn(VA.getLocReg(), VReg);
|
Add support for Linux/Musl ABI
Differential revision: https://reviews.llvm.org/D72701
The patch adds a new option ABI for Hexagon. It primary deals with
the way variable arguments are passed and is use in the Hexagon Linux Musl
environment.
If a callee function has a variable argument list, it must perform the
following operations to set up its function prologue:
1. Determine the number of registers which could have been used for passing
unnamed arguments. This can be calculated by counting the number of
registers used for passing named arguments. For example, if the callee
function is as follows:
int foo(int a, ...){ ... }
... then register R0 is used to access the argument ' a '. The registers
available for passing unnamed arguments are R1, R2, R3, R4, and R5.
2. Determine the number and size of the named arguments on the stack.
3. If the callee has named arguments on the stack, it should copy all of these
arguments to a location below the current position on the stack, and the
difference should be the size of the register-saved area plus padding
(if any is necessary).
The register-saved area constitutes all the registers that could have
been used to pass unnamed arguments. If the number of registers forming
the register-saved area is odd, it requires 4 bytes of padding; if the
number is even, no padding is required. This is done to ensure an 8-byte
alignment on the stack. For example, if the callee is as follows:
int foo(int a, ...){ ... }
... then the named arguments should be copied to the following location:
current_position - 5 (for R1-R5) * 4 (bytes) - 4 (bytes of padding)
If the callee is as follows:
int foo(int a, int b, ...){ ... }
... then the named arguments should be copied to the following location:
current_position - 4 (for R2-R5) * 4 (bytes) - 0 (bytes of padding)
4. After any named arguments have been copied, copy all the registers that
could have been used to pass unnamed arguments on the stack. If the number
of registers is odd, leave 4 bytes of padding and then start copying them
on the stack; if the number is even, no padding is required. This
constitutes the register-saved area. If padding is required, ensure
that the start location of padding is 8-byte aligned. If no padding is
required, ensure that the start location of the on-stack copy of the
first register which might have a variable argument is 8-byte aligned.
5. Decrement the stack pointer by the size of register saved area plus the
padding. For example, if the callee is as follows:
int foo(int a, ...){ ... } ;
... then the decrement value should be the following:
5 (for R1-R5) * 4 (bytes) + 4 (bytes of padding) = 24 bytes
The decrement should be performed before the allocframe instruction.
Increment the stack-pointer back by the same amount before returning
from the function.
2019-12-28 03:03:01 +08:00
|
|
|
HFL.FirstVarArgSavedReg = NextSingleReg(*RC, VA.getLocReg());
|
2011-12-13 05:14:40 +08:00
|
|
|
} else {
|
2018-02-09 23:30:02 +08:00
|
|
|
assert(VA.isMemLoc() && "Argument should be passed in memory");
|
2011-12-13 05:14:40 +08:00
|
|
|
|
2018-02-09 23:30:02 +08:00
|
|
|
// If it's a byval parameter, then we need to compute the
|
|
|
|
// "real" size, not the size of the pointer.
|
|
|
|
unsigned ObjSize = Flags.isByVal()
|
|
|
|
? Flags.getByValSize()
|
|
|
|
: VA.getLocVT().getStoreSizeInBits() / 8;
|
2011-12-13 05:14:40 +08:00
|
|
|
|
2018-02-09 23:30:02 +08:00
|
|
|
// Create the frame index object for this incoming parameter.
|
|
|
|
int Offset = HEXAGON_LRFP_SIZE + VA.getLocMemOffset();
|
|
|
|
int FI = MFI.CreateFixedObject(ObjSize, Offset, true);
|
2011-12-13 05:14:40 +08:00
|
|
|
SDValue FIN = DAG.getFrameIndex(FI, MVT::i32);
|
|
|
|
|
|
|
|
if (Flags.isByVal()) {
|
|
|
|
// If it's a pass-by-value aggregate, then do not dereference the stack
|
|
|
|
// location. Instead, we should generate a reference to the stack
|
|
|
|
// location.
|
|
|
|
InVals.push_back(FIN);
|
|
|
|
} else {
|
2018-02-09 23:30:02 +08:00
|
|
|
SDValue L = DAG.getLoad(VA.getValVT(), dl, Chain, FIN,
|
|
|
|
MachinePointerInfo::getFixedStack(MF, FI, 0));
|
|
|
|
InVals.push_back(L);
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Add support for Linux/Musl ABI
Differential revision: https://reviews.llvm.org/D72701
The patch adds a new option ABI for Hexagon. It primary deals with
the way variable arguments are passed and is use in the Hexagon Linux Musl
environment.
If a callee function has a variable argument list, it must perform the
following operations to set up its function prologue:
1. Determine the number of registers which could have been used for passing
unnamed arguments. This can be calculated by counting the number of
registers used for passing named arguments. For example, if the callee
function is as follows:
int foo(int a, ...){ ... }
... then register R0 is used to access the argument ' a '. The registers
available for passing unnamed arguments are R1, R2, R3, R4, and R5.
2. Determine the number and size of the named arguments on the stack.
3. If the callee has named arguments on the stack, it should copy all of these
arguments to a location below the current position on the stack, and the
difference should be the size of the register-saved area plus padding
(if any is necessary).
The register-saved area constitutes all the registers that could have
been used to pass unnamed arguments. If the number of registers forming
the register-saved area is odd, it requires 4 bytes of padding; if the
number is even, no padding is required. This is done to ensure an 8-byte
alignment on the stack. For example, if the callee is as follows:
int foo(int a, ...){ ... }
... then the named arguments should be copied to the following location:
current_position - 5 (for R1-R5) * 4 (bytes) - 4 (bytes of padding)
If the callee is as follows:
int foo(int a, int b, ...){ ... }
... then the named arguments should be copied to the following location:
current_position - 4 (for R2-R5) * 4 (bytes) - 0 (bytes of padding)
4. After any named arguments have been copied, copy all the registers that
could have been used to pass unnamed arguments on the stack. If the number
of registers is odd, leave 4 bytes of padding and then start copying them
on the stack; if the number is even, no padding is required. This
constitutes the register-saved area. If padding is required, ensure
that the start location of padding is 8-byte aligned. If no padding is
required, ensure that the start location of the on-stack copy of the
first register which might have a variable argument is 8-byte aligned.
5. Decrement the stack pointer by the size of register saved area plus the
padding. For example, if the callee is as follows:
int foo(int a, ...){ ... } ;
... then the decrement value should be the following:
5 (for R1-R5) * 4 (bytes) + 4 (bytes of padding) = 24 bytes
The decrement should be performed before the allocframe instruction.
Increment the stack-pointer back by the same amount before returning
from the function.
2019-12-28 03:03:01 +08:00
|
|
|
if (IsVarArg && Subtarget.isEnvironmentMusl()) {
|
|
|
|
for (int i = HFL.FirstVarArgSavedReg; i < 6; i++)
|
|
|
|
MRI.addLiveIn(Hexagon::R0+i);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (IsVarArg && Subtarget.isEnvironmentMusl()) {
|
|
|
|
HMFI.setFirstNamedArgFrameIndex(HMFI.getFirstNamedArgFrameIndex() - 1);
|
|
|
|
HMFI.setLastNamedArgFrameIndex(-int(MFI.getNumFixedObjects()));
|
|
|
|
|
|
|
|
// Create Frame index for the start of register saved area.
|
|
|
|
int NumVarArgRegs = 6 - HFL.FirstVarArgSavedReg;
|
|
|
|
bool RequiresPadding = (NumVarArgRegs & 1);
|
|
|
|
int RegSaveAreaSizePlusPadding = RequiresPadding
|
|
|
|
? (NumVarArgRegs + 1) * 4
|
|
|
|
: NumVarArgRegs * 4;
|
|
|
|
|
|
|
|
if (RegSaveAreaSizePlusPadding > 0) {
|
|
|
|
// The offset to saved register area should be 8 byte aligned.
|
|
|
|
int RegAreaStart = HEXAGON_LRFP_SIZE + CCInfo.getNextStackOffset();
|
|
|
|
if (!(RegAreaStart % 8))
|
|
|
|
RegAreaStart = (RegAreaStart + 7) & -8;
|
2011-12-13 05:14:40 +08:00
|
|
|
|
Add support for Linux/Musl ABI
Differential revision: https://reviews.llvm.org/D72701
The patch adds a new option ABI for Hexagon. It primary deals with
the way variable arguments are passed and is use in the Hexagon Linux Musl
environment.
If a callee function has a variable argument list, it must perform the
following operations to set up its function prologue:
1. Determine the number of registers which could have been used for passing
unnamed arguments. This can be calculated by counting the number of
registers used for passing named arguments. For example, if the callee
function is as follows:
int foo(int a, ...){ ... }
... then register R0 is used to access the argument ' a '. The registers
available for passing unnamed arguments are R1, R2, R3, R4, and R5.
2. Determine the number and size of the named arguments on the stack.
3. If the callee has named arguments on the stack, it should copy all of these
arguments to a location below the current position on the stack, and the
difference should be the size of the register-saved area plus padding
(if any is necessary).
The register-saved area constitutes all the registers that could have
been used to pass unnamed arguments. If the number of registers forming
the register-saved area is odd, it requires 4 bytes of padding; if the
number is even, no padding is required. This is done to ensure an 8-byte
alignment on the stack. For example, if the callee is as follows:
int foo(int a, ...){ ... }
... then the named arguments should be copied to the following location:
current_position - 5 (for R1-R5) * 4 (bytes) - 4 (bytes of padding)
If the callee is as follows:
int foo(int a, int b, ...){ ... }
... then the named arguments should be copied to the following location:
current_position - 4 (for R2-R5) * 4 (bytes) - 0 (bytes of padding)
4. After any named arguments have been copied, copy all the registers that
could have been used to pass unnamed arguments on the stack. If the number
of registers is odd, leave 4 bytes of padding and then start copying them
on the stack; if the number is even, no padding is required. This
constitutes the register-saved area. If padding is required, ensure
that the start location of padding is 8-byte aligned. If no padding is
required, ensure that the start location of the on-stack copy of the
first register which might have a variable argument is 8-byte aligned.
5. Decrement the stack pointer by the size of register saved area plus the
padding. For example, if the callee is as follows:
int foo(int a, ...){ ... } ;
... then the decrement value should be the following:
5 (for R1-R5) * 4 (bytes) + 4 (bytes of padding) = 24 bytes
The decrement should be performed before the allocframe instruction.
Increment the stack-pointer back by the same amount before returning
from the function.
2019-12-28 03:03:01 +08:00
|
|
|
int RegSaveAreaFrameIndex =
|
|
|
|
MFI.CreateFixedObject(RegSaveAreaSizePlusPadding, RegAreaStart, true);
|
|
|
|
HMFI.setRegSavedAreaStartFrameIndex(RegSaveAreaFrameIndex);
|
|
|
|
|
|
|
|
// This will point to the next argument passed via stack.
|
|
|
|
int Offset = RegAreaStart + RegSaveAreaSizePlusPadding;
|
|
|
|
int FI = MFI.CreateFixedObject(Hexagon_PointerSize, Offset, true);
|
|
|
|
HMFI.setVarArgsFrameIndex(FI);
|
|
|
|
} else {
|
|
|
|
// This will point to the next argument passed via stack, when
|
|
|
|
// there is no saved register area.
|
|
|
|
int Offset = HEXAGON_LRFP_SIZE + CCInfo.getNextStackOffset();
|
|
|
|
int FI = MFI.CreateFixedObject(Hexagon_PointerSize, Offset, true);
|
|
|
|
HMFI.setRegSavedAreaStartFrameIndex(FI);
|
|
|
|
HMFI.setVarArgsFrameIndex(FI);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (IsVarArg && !Subtarget.isEnvironmentMusl()) {
|
2011-12-13 05:14:40 +08:00
|
|
|
// This will point to the next argument passed via stack.
|
2018-02-09 23:30:02 +08:00
|
|
|
int Offset = HEXAGON_LRFP_SIZE + CCInfo.getNextStackOffset();
|
|
|
|
int FI = MFI.CreateFixedObject(Hexagon_PointerSize, Offset, true);
|
|
|
|
HMFI.setVarArgsFrameIndex(FI);
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return Chain;
|
|
|
|
}
|
|
|
|
|
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerVASTART(SDValue Op, SelectionDAG &DAG) const {
|
|
|
|
// VASTART stores the address of the VarArgsFrameIndex slot into the
|
|
|
|
// memory location argument.
|
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
HexagonMachineFunctionInfo *QFI = MF.getInfo<HexagonMachineFunctionInfo>();
|
|
|
|
SDValue Addr = DAG.getFrameIndex(QFI->getVarArgsFrameIndex(), MVT::i32);
|
|
|
|
const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue();
|
Add support for Linux/Musl ABI
Differential revision: https://reviews.llvm.org/D72701
The patch adds a new option ABI for Hexagon. It primary deals with
the way variable arguments are passed and is use in the Hexagon Linux Musl
environment.
If a callee function has a variable argument list, it must perform the
following operations to set up its function prologue:
1. Determine the number of registers which could have been used for passing
unnamed arguments. This can be calculated by counting the number of
registers used for passing named arguments. For example, if the callee
function is as follows:
int foo(int a, ...){ ... }
... then register R0 is used to access the argument ' a '. The registers
available for passing unnamed arguments are R1, R2, R3, R4, and R5.
2. Determine the number and size of the named arguments on the stack.
3. If the callee has named arguments on the stack, it should copy all of these
arguments to a location below the current position on the stack, and the
difference should be the size of the register-saved area plus padding
(if any is necessary).
The register-saved area constitutes all the registers that could have
been used to pass unnamed arguments. If the number of registers forming
the register-saved area is odd, it requires 4 bytes of padding; if the
number is even, no padding is required. This is done to ensure an 8-byte
alignment on the stack. For example, if the callee is as follows:
int foo(int a, ...){ ... }
... then the named arguments should be copied to the following location:
current_position - 5 (for R1-R5) * 4 (bytes) - 4 (bytes of padding)
If the callee is as follows:
int foo(int a, int b, ...){ ... }
... then the named arguments should be copied to the following location:
current_position - 4 (for R2-R5) * 4 (bytes) - 0 (bytes of padding)
4. After any named arguments have been copied, copy all the registers that
could have been used to pass unnamed arguments on the stack. If the number
of registers is odd, leave 4 bytes of padding and then start copying them
on the stack; if the number is even, no padding is required. This
constitutes the register-saved area. If padding is required, ensure
that the start location of padding is 8-byte aligned. If no padding is
required, ensure that the start location of the on-stack copy of the
first register which might have a variable argument is 8-byte aligned.
5. Decrement the stack pointer by the size of register saved area plus the
padding. For example, if the callee is as follows:
int foo(int a, ...){ ... } ;
... then the decrement value should be the following:
5 (for R1-R5) * 4 (bytes) + 4 (bytes of padding) = 24 bytes
The decrement should be performed before the allocframe instruction.
Increment the stack-pointer back by the same amount before returning
from the function.
2019-12-28 03:03:01 +08:00
|
|
|
|
|
|
|
if (!Subtarget.isEnvironmentMusl()) {
|
|
|
|
return DAG.getStore(Op.getOperand(0), SDLoc(Op), Addr, Op.getOperand(1),
|
|
|
|
MachinePointerInfo(SV));
|
|
|
|
}
|
|
|
|
auto &FuncInfo = *MF.getInfo<HexagonMachineFunctionInfo>();
|
|
|
|
auto &HFL = *Subtarget.getFrameLowering();
|
|
|
|
SDLoc DL(Op);
|
|
|
|
SmallVector<SDValue, 8> MemOps;
|
|
|
|
|
|
|
|
// Get frame index of va_list.
|
|
|
|
SDValue FIN = Op.getOperand(1);
|
|
|
|
|
|
|
|
// If first Vararg register is odd, add 4 bytes to start of
|
|
|
|
// saved register area to point to the first register location.
|
|
|
|
// This is because the saved register area has to be 8 byte aligned.
|
|
|
|
// Incase of an odd start register, there will be 4 bytes of padding in
|
|
|
|
// the beginning of saved register area. If all registers area used up,
|
|
|
|
// the following condition will handle it correctly.
|
|
|
|
SDValue SavedRegAreaStartFrameIndex =
|
|
|
|
DAG.getFrameIndex(FuncInfo.getRegSavedAreaStartFrameIndex(), MVT::i32);
|
|
|
|
|
|
|
|
auto PtrVT = getPointerTy(DAG.getDataLayout());
|
|
|
|
|
|
|
|
if (HFL.FirstVarArgSavedReg & 1)
|
|
|
|
SavedRegAreaStartFrameIndex =
|
|
|
|
DAG.getNode(ISD::ADD, DL, PtrVT,
|
|
|
|
DAG.getFrameIndex(FuncInfo.getRegSavedAreaStartFrameIndex(),
|
|
|
|
MVT::i32),
|
|
|
|
DAG.getIntPtrConstant(4, DL));
|
|
|
|
|
|
|
|
// Store the saved register area start pointer.
|
|
|
|
SDValue Store =
|
|
|
|
DAG.getStore(Op.getOperand(0), DL,
|
|
|
|
SavedRegAreaStartFrameIndex,
|
|
|
|
FIN, MachinePointerInfo(SV));
|
|
|
|
MemOps.push_back(Store);
|
|
|
|
|
|
|
|
// Store saved register area end pointer.
|
|
|
|
FIN = DAG.getNode(ISD::ADD, DL, PtrVT,
|
|
|
|
FIN, DAG.getIntPtrConstant(4, DL));
|
|
|
|
Store = DAG.getStore(Op.getOperand(0), DL,
|
|
|
|
DAG.getFrameIndex(FuncInfo.getVarArgsFrameIndex(),
|
|
|
|
PtrVT),
|
|
|
|
FIN, MachinePointerInfo(SV, 4));
|
|
|
|
MemOps.push_back(Store);
|
|
|
|
|
|
|
|
// Store overflow area pointer.
|
|
|
|
FIN = DAG.getNode(ISD::ADD, DL, PtrVT,
|
|
|
|
FIN, DAG.getIntPtrConstant(4, DL));
|
|
|
|
Store = DAG.getStore(Op.getOperand(0), DL,
|
|
|
|
DAG.getFrameIndex(FuncInfo.getVarArgsFrameIndex(),
|
|
|
|
PtrVT),
|
|
|
|
FIN, MachinePointerInfo(SV, 8));
|
|
|
|
MemOps.push_back(Store);
|
|
|
|
|
|
|
|
return DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOps);
|
|
|
|
}
|
|
|
|
|
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerVACOPY(SDValue Op, SelectionDAG &DAG) const {
|
|
|
|
// Assert that the linux ABI is enabled for the current compilation.
|
|
|
|
assert(Subtarget.isEnvironmentMusl() && "Linux ABI should be enabled");
|
|
|
|
SDValue Chain = Op.getOperand(0);
|
|
|
|
SDValue DestPtr = Op.getOperand(1);
|
|
|
|
SDValue SrcPtr = Op.getOperand(2);
|
|
|
|
const Value *DestSV = cast<SrcValueSDNode>(Op.getOperand(3))->getValue();
|
|
|
|
const Value *SrcSV = cast<SrcValueSDNode>(Op.getOperand(4))->getValue();
|
|
|
|
SDLoc DL(Op);
|
|
|
|
// Size of the va_list is 12 bytes as it has 3 pointers. Therefore,
|
|
|
|
// we need to memcopy 12 bytes from va_list to another similar list.
|
|
|
|
return DAG.getMemcpy(Chain, DL, DestPtr, SrcPtr,
|
[Alignment][NFC] Use Align for getMemcpy/Memmove/Memset
Summary:
This is patch is part of a series to introduce an Alignment type.
See this thread for context: http://lists.llvm.org/pipermail/llvm-dev/2019-July/133851.html
See this patch for the introduction of the type: https://reviews.llvm.org/D64790
Reviewers: courbet
Subscribers: arsenm, dschuff, jyknight, sdardis, nemanjai, jvesely, nhaehnle, sbc100, jgravelle-google, hiraditya, aheejin, kbarton, fedor.sergeev, asb, rbar, johnrusso, simoncook, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, atanasyan, rogfer01, MartinMosbeck, brucehoult, the_o, PkmX, jocewei, jsji, Jim, lenary, s.egerton, pzheng, sameer.abuasal, apazos, luismarques, kerbowa, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D73885
2020-02-03 21:49:01 +08:00
|
|
|
DAG.getIntPtrConstant(12, DL), Align(4),
|
|
|
|
/*isVolatile*/ false, false, false,
|
Add support for Linux/Musl ABI
Differential revision: https://reviews.llvm.org/D72701
The patch adds a new option ABI for Hexagon. It primary deals with
the way variable arguments are passed and is use in the Hexagon Linux Musl
environment.
If a callee function has a variable argument list, it must perform the
following operations to set up its function prologue:
1. Determine the number of registers which could have been used for passing
unnamed arguments. This can be calculated by counting the number of
registers used for passing named arguments. For example, if the callee
function is as follows:
int foo(int a, ...){ ... }
... then register R0 is used to access the argument ' a '. The registers
available for passing unnamed arguments are R1, R2, R3, R4, and R5.
2. Determine the number and size of the named arguments on the stack.
3. If the callee has named arguments on the stack, it should copy all of these
arguments to a location below the current position on the stack, and the
difference should be the size of the register-saved area plus padding
(if any is necessary).
The register-saved area constitutes all the registers that could have
been used to pass unnamed arguments. If the number of registers forming
the register-saved area is odd, it requires 4 bytes of padding; if the
number is even, no padding is required. This is done to ensure an 8-byte
alignment on the stack. For example, if the callee is as follows:
int foo(int a, ...){ ... }
... then the named arguments should be copied to the following location:
current_position - 5 (for R1-R5) * 4 (bytes) - 4 (bytes of padding)
If the callee is as follows:
int foo(int a, int b, ...){ ... }
... then the named arguments should be copied to the following location:
current_position - 4 (for R2-R5) * 4 (bytes) - 0 (bytes of padding)
4. After any named arguments have been copied, copy all the registers that
could have been used to pass unnamed arguments on the stack. If the number
of registers is odd, leave 4 bytes of padding and then start copying them
on the stack; if the number is even, no padding is required. This
constitutes the register-saved area. If padding is required, ensure
that the start location of padding is 8-byte aligned. If no padding is
required, ensure that the start location of the on-stack copy of the
first register which might have a variable argument is 8-byte aligned.
5. Decrement the stack pointer by the size of register saved area plus the
padding. For example, if the callee is as follows:
int foo(int a, ...){ ... } ;
... then the decrement value should be the following:
5 (for R1-R5) * 4 (bytes) + 4 (bytes of padding) = 24 bytes
The decrement should be performed before the allocframe instruction.
Increment the stack-pointer back by the same amount before returning
from the function.
2019-12-28 03:03:01 +08:00
|
|
|
MachinePointerInfo(DestSV), MachinePointerInfo(SrcSV));
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
|
|
|
|
2015-03-20 00:33:08 +08:00
|
|
|
SDValue HexagonTargetLowering::LowerSETCC(SDValue Op, SelectionDAG &DAG) const {
|
2018-04-19 22:24:31 +08:00
|
|
|
const SDLoc &dl(Op);
|
2015-03-20 00:33:08 +08:00
|
|
|
SDValue LHS = Op.getOperand(0);
|
|
|
|
SDValue RHS = Op.getOperand(1);
|
2018-04-19 22:24:31 +08:00
|
|
|
ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(2))->get();
|
|
|
|
MVT ResTy = ty(Op);
|
|
|
|
MVT OpTy = ty(LHS);
|
|
|
|
|
|
|
|
if (OpTy == MVT::v2i16 || OpTy == MVT::v4i8) {
|
|
|
|
MVT ElemTy = OpTy.getVectorElementType();
|
|
|
|
assert(ElemTy.isScalarInteger());
|
|
|
|
MVT WideTy = MVT::getVectorVT(MVT::getIntegerVT(2*ElemTy.getSizeInBits()),
|
|
|
|
OpTy.getVectorNumElements());
|
|
|
|
return DAG.getSetCC(dl, ResTy,
|
|
|
|
DAG.getSExtOrTrunc(LHS, SDLoc(LHS), WideTy),
|
|
|
|
DAG.getSExtOrTrunc(RHS, SDLoc(RHS), WideTy), CC);
|
2015-03-20 00:33:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Treat all other vector types as legal.
|
2018-04-19 22:24:31 +08:00
|
|
|
if (ResTy.isVector())
|
2015-03-20 00:33:08 +08:00
|
|
|
return Op;
|
|
|
|
|
2018-04-19 22:24:31 +08:00
|
|
|
// Comparisons of short integers should use sign-extend, not zero-extend,
|
|
|
|
// since we can represent small negative values in the compare instructions.
|
2015-03-20 00:33:08 +08:00
|
|
|
// The LLVM default is to use zero-extend arbitrarily in these cases.
|
2018-04-19 22:24:31 +08:00
|
|
|
auto isSExtFree = [this](SDValue N) {
|
|
|
|
switch (N.getOpcode()) {
|
|
|
|
case ISD::TRUNCATE: {
|
|
|
|
// A sign-extend of a truncate of a sign-extend is free.
|
|
|
|
SDValue Op = N.getOperand(0);
|
|
|
|
if (Op.getOpcode() != ISD::AssertSext)
|
|
|
|
return false;
|
2018-07-12 07:26:35 +08:00
|
|
|
EVT OrigTy = cast<VTSDNode>(Op.getOperand(1))->getVT();
|
2018-04-19 22:24:31 +08:00
|
|
|
unsigned ThisBW = ty(N).getSizeInBits();
|
|
|
|
unsigned OrigBW = OrigTy.getSizeInBits();
|
|
|
|
// The type that was sign-extended to get the AssertSext must be
|
|
|
|
// narrower than the type of N (so that N has still the same value
|
|
|
|
// as the original).
|
|
|
|
return ThisBW >= OrigBW;
|
|
|
|
}
|
|
|
|
case ISD::LOAD:
|
|
|
|
// We have sign-extended loads.
|
|
|
|
return true;
|
2015-03-20 00:33:08 +08:00
|
|
|
}
|
2018-04-19 22:24:31 +08:00
|
|
|
return false;
|
|
|
|
};
|
|
|
|
|
|
|
|
if (OpTy == MVT::i8 || OpTy == MVT::i16) {
|
|
|
|
ConstantSDNode *C = dyn_cast<ConstantSDNode>(RHS);
|
|
|
|
bool IsNegative = C && C->getAPIntValue().isNegative();
|
|
|
|
if (IsNegative || isSExtFree(LHS) || isSExtFree(RHS))
|
|
|
|
return DAG.getSetCC(dl, ResTy,
|
|
|
|
DAG.getSExtOrTrunc(LHS, SDLoc(LHS), MVT::i32),
|
|
|
|
DAG.getSExtOrTrunc(RHS, SDLoc(RHS), MVT::i32), CC);
|
2015-03-20 00:33:08 +08:00
|
|
|
}
|
2018-04-19 22:24:31 +08:00
|
|
|
|
2015-03-20 00:33:08 +08:00
|
|
|
return SDValue();
|
|
|
|
}
|
|
|
|
|
2015-12-19 04:19:30 +08:00
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerVSELECT(SDValue Op, SelectionDAG &DAG) const {
|
2015-03-20 00:33:08 +08:00
|
|
|
SDValue PredOp = Op.getOperand(0);
|
|
|
|
SDValue Op1 = Op.getOperand(1), Op2 = Op.getOperand(2);
|
2019-08-16 03:20:09 +08:00
|
|
|
MVT OpTy = ty(Op1);
|
|
|
|
const SDLoc &dl(Op);
|
2015-03-20 00:33:08 +08:00
|
|
|
|
2019-08-16 03:20:09 +08:00
|
|
|
if (OpTy == MVT::v2i16 || OpTy == MVT::v4i8) {
|
|
|
|
MVT ElemTy = OpTy.getVectorElementType();
|
|
|
|
assert(ElemTy.isScalarInteger());
|
|
|
|
MVT WideTy = MVT::getVectorVT(MVT::getIntegerVT(2*ElemTy.getSizeInBits()),
|
|
|
|
OpTy.getVectorNumElements());
|
|
|
|
// Generate (trunc (select (_, sext, sext))).
|
|
|
|
return DAG.getSExtOrTrunc(
|
|
|
|
DAG.getSelect(dl, WideTy, PredOp,
|
|
|
|
DAG.getSExtOrTrunc(Op1, dl, WideTy),
|
|
|
|
DAG.getSExtOrTrunc(Op2, dl, WideTy)),
|
|
|
|
dl, OpTy);
|
2015-03-20 00:33:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return SDValue();
|
|
|
|
}
|
|
|
|
|
2012-05-11 04:20:25 +08:00
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerConstantPool(SDValue Op, SelectionDAG &DAG) const {
|
|
|
|
EVT ValTy = Op.getValueType();
|
2015-12-19 04:19:30 +08:00
|
|
|
ConstantPoolSDNode *CPN = cast<ConstantPoolSDNode>(Op);
|
2017-08-01 21:12:53 +08:00
|
|
|
Constant *CVal = nullptr;
|
|
|
|
bool isVTi1Type = false;
|
2020-02-07 23:33:18 +08:00
|
|
|
if (auto *CV = dyn_cast<ConstantVector>(CPN->getConstVal())) {
|
2020-04-04 02:24:59 +08:00
|
|
|
if (cast<VectorType>(CV->getType())->getElementType()->isIntegerTy(1)) {
|
2020-02-07 23:33:18 +08:00
|
|
|
IRBuilder<> IRB(CV->getContext());
|
|
|
|
SmallVector<Constant*, 128> NewConst;
|
|
|
|
unsigned VecLen = CV->getNumOperands();
|
|
|
|
assert(isPowerOf2_32(VecLen) &&
|
|
|
|
"conversion only supported for pow2 VectorSize");
|
|
|
|
for (unsigned i = 0; i < VecLen; ++i)
|
|
|
|
NewConst.push_back(IRB.getInt8(CV->getOperand(i)->isZeroValue()));
|
|
|
|
|
|
|
|
CVal = ConstantVector::get(NewConst);
|
|
|
|
isVTi1Type = true;
|
2017-08-01 21:12:53 +08:00
|
|
|
}
|
|
|
|
}
|
2020-05-09 06:06:15 +08:00
|
|
|
Align Alignment = CPN->getAlign();
|
2016-06-27 06:24:01 +08:00
|
|
|
bool IsPositionIndependent = isPositionIndependent();
|
|
|
|
unsigned char TF = IsPositionIndependent ? HexagonII::MO_PCREL : 0;
|
2015-12-19 04:19:30 +08:00
|
|
|
|
2016-08-14 07:41:11 +08:00
|
|
|
unsigned Offset = 0;
|
2015-12-19 04:19:30 +08:00
|
|
|
SDValue T;
|
|
|
|
if (CPN->isMachineConstantPoolEntry())
|
2020-05-09 06:06:15 +08:00
|
|
|
T = DAG.getTargetConstantPool(CPN->getMachineCPVal(), ValTy, Alignment,
|
|
|
|
Offset, TF);
|
2017-08-01 21:12:53 +08:00
|
|
|
else if (isVTi1Type)
|
2020-05-09 06:06:15 +08:00
|
|
|
T = DAG.getTargetConstantPool(CVal, ValTy, Alignment, Offset, TF);
|
2012-05-11 04:20:25 +08:00
|
|
|
else
|
2020-05-09 06:06:15 +08:00
|
|
|
T = DAG.getTargetConstantPool(CPN->getConstVal(), ValTy, Alignment, Offset,
|
|
|
|
TF);
|
2016-08-14 07:41:11 +08:00
|
|
|
|
|
|
|
assert(cast<ConstantPoolSDNode>(T)->getTargetFlags() == TF &&
|
|
|
|
"Inconsistent target flag encountered");
|
|
|
|
|
2016-06-27 06:24:01 +08:00
|
|
|
if (IsPositionIndependent)
|
2015-12-19 04:19:30 +08:00
|
|
|
return DAG.getNode(HexagonISD::AT_PCREL, SDLoc(Op), ValTy, T);
|
|
|
|
return DAG.getNode(HexagonISD::CP, SDLoc(Op), ValTy, T);
|
|
|
|
}
|
|
|
|
|
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerJumpTable(SDValue Op, SelectionDAG &DAG) const {
|
|
|
|
EVT VT = Op.getValueType();
|
|
|
|
int Idx = cast<JumpTableSDNode>(Op)->getIndex();
|
2016-06-27 06:24:01 +08:00
|
|
|
if (isPositionIndependent()) {
|
2015-12-19 04:19:30 +08:00
|
|
|
SDValue T = DAG.getTargetJumpTable(Idx, VT, HexagonII::MO_PCREL);
|
|
|
|
return DAG.getNode(HexagonISD::AT_PCREL, SDLoc(Op), VT, T);
|
|
|
|
}
|
|
|
|
|
|
|
|
SDValue T = DAG.getTargetJumpTable(Idx, VT);
|
|
|
|
return DAG.getNode(HexagonISD::JT, SDLoc(Op), VT, T);
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerRETURNADDR(SDValue Op, SelectionDAG &DAG) const {
|
2015-04-23 05:17:00 +08:00
|
|
|
const HexagonRegisterInfo &HRI = *Subtarget.getRegisterInfo();
|
2011-12-13 05:14:40 +08:00
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
2016-07-29 02:40:00 +08:00
|
|
|
MachineFrameInfo &MFI = MF.getFrameInfo();
|
2015-04-23 05:17:00 +08:00
|
|
|
MFI.setReturnAddressIsTaken(true);
|
2011-12-13 05:14:40 +08:00
|
|
|
|
2014-01-06 08:43:20 +08:00
|
|
|
if (verifyReturnAddressArgumentIsConstant(Op, DAG))
|
2014-01-05 09:47:20 +08:00
|
|
|
return SDValue();
|
|
|
|
|
2011-12-13 05:14:40 +08:00
|
|
|
EVT VT = Op.getValueType();
|
2013-05-25 10:42:55 +08:00
|
|
|
SDLoc dl(Op);
|
2011-12-13 05:14:40 +08:00
|
|
|
unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
|
|
|
|
if (Depth) {
|
|
|
|
SDValue FrameAddr = LowerFRAMEADDR(Op, DAG);
|
2015-04-28 22:05:47 +08:00
|
|
|
SDValue Offset = DAG.getConstant(4, dl, MVT::i32);
|
2011-12-13 05:14:40 +08:00
|
|
|
return DAG.getLoad(VT, dl, DAG.getEntryNode(),
|
|
|
|
DAG.getNode(ISD::ADD, dl, VT, FrameAddr, Offset),
|
[SelectionDAG] Get rid of bool parameters in SelectionDAG::getLoad, getStore, and friends.
Summary:
Instead, we take a single flags arg (a bitset).
Also add a default 0 alignment, and change the order of arguments so the
alignment comes before the flags.
This greatly simplifies many callsites, and fixes a bug in
AMDGPUISelLowering, wherein the order of the args to getLoad was
inverted. It also greatly simplifies the process of adding another flag
to getLoad.
Reviewers: chandlerc, tstellarAMD
Subscribers: jholewinski, arsenm, jyknight, dsanders, nemanjai, llvm-commits
Differential Revision: http://reviews.llvm.org/D22249
llvm-svn: 275592
2016-07-16 02:27:10 +08:00
|
|
|
MachinePointerInfo());
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Return LR, which contains the return address. Mark it an implicit live-in.
|
2015-04-23 05:17:00 +08:00
|
|
|
unsigned Reg = MF.addLiveIn(HRI.getRARegister(), getRegClassFor(MVT::i32));
|
2011-12-13 05:14:40 +08:00
|
|
|
return DAG.getCopyFromReg(DAG.getEntryNode(), dl, Reg, VT);
|
|
|
|
}
|
|
|
|
|
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const {
|
2015-04-23 05:17:00 +08:00
|
|
|
const HexagonRegisterInfo &HRI = *Subtarget.getRegisterInfo();
|
2016-07-29 02:40:00 +08:00
|
|
|
MachineFrameInfo &MFI = DAG.getMachineFunction().getFrameInfo();
|
2015-04-23 05:17:00 +08:00
|
|
|
MFI.setFrameAddressIsTaken(true);
|
2011-12-13 05:14:40 +08:00
|
|
|
|
|
|
|
EVT VT = Op.getValueType();
|
2013-05-25 10:42:55 +08:00
|
|
|
SDLoc dl(Op);
|
2011-12-13 05:14:40 +08:00
|
|
|
unsigned Depth = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue();
|
|
|
|
SDValue FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl,
|
2015-04-23 05:17:00 +08:00
|
|
|
HRI.getFrameRegister(), VT);
|
2011-12-13 05:14:40 +08:00
|
|
|
while (Depth--)
|
|
|
|
FrameAddr = DAG.getLoad(VT, dl, DAG.getEntryNode(), FrameAddr,
|
[SelectionDAG] Get rid of bool parameters in SelectionDAG::getLoad, getStore, and friends.
Summary:
Instead, we take a single flags arg (a bitset).
Also add a default 0 alignment, and change the order of arguments so the
alignment comes before the flags.
This greatly simplifies many callsites, and fixes a bug in
AMDGPUISelLowering, wherein the order of the args to getLoad was
inverted. It also greatly simplifies the process of adding another flag
to getLoad.
Reviewers: chandlerc, tstellarAMD
Subscribers: jholewinski, arsenm, jyknight, dsanders, nemanjai, llvm-commits
Differential Revision: http://reviews.llvm.org/D22249
llvm-svn: 275592
2016-07-16 02:27:10 +08:00
|
|
|
MachinePointerInfo());
|
2011-12-13 05:14:40 +08:00
|
|
|
return FrameAddr;
|
|
|
|
}
|
|
|
|
|
2015-12-19 04:19:30 +08:00
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerATOMIC_FENCE(SDValue Op, SelectionDAG& DAG) const {
|
2013-05-25 10:42:55 +08:00
|
|
|
SDLoc dl(Op);
|
2011-12-13 05:14:40 +08:00
|
|
|
return DAG.getNode(HexagonISD::BARRIER, dl, MVT::Other, Op.getOperand(0));
|
|
|
|
}
|
|
|
|
|
2015-12-19 04:19:30 +08:00
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerGLOBALADDRESS(SDValue Op, SelectionDAG &DAG) const {
|
2013-05-25 10:42:55 +08:00
|
|
|
SDLoc dl(Op);
|
2015-12-19 04:19:30 +08:00
|
|
|
auto *GAN = cast<GlobalAddressSDNode>(Op);
|
2015-07-09 10:09:04 +08:00
|
|
|
auto PtrVT = getPointerTy(DAG.getDataLayout());
|
2018-01-31 02:10:27 +08:00
|
|
|
auto *GV = GAN->getGlobal();
|
|
|
|
int64_t Offset = GAN->getOffset();
|
2011-12-13 05:14:40 +08:00
|
|
|
|
2015-12-19 04:19:30 +08:00
|
|
|
auto &HLOF = *HTM.getObjFileLowering();
|
|
|
|
Reloc::Model RM = HTM.getRelocationModel();
|
|
|
|
|
|
|
|
if (RM == Reloc::Static) {
|
|
|
|
SDValue GA = DAG.getTargetGlobalAddress(GV, dl, PtrVT, Offset);
|
2016-10-25 03:23:39 +08:00
|
|
|
const GlobalObject *GO = GV->getBaseObject();
|
2018-05-15 05:01:56 +08:00
|
|
|
if (GO && Subtarget.useSmallData() && HLOF.isGlobalInSmallSection(GO, HTM))
|
2018-01-31 02:10:27 +08:00
|
|
|
return DAG.getNode(HexagonISD::CONST32_GP, dl, PtrVT, GA);
|
|
|
|
return DAG.getNode(HexagonISD::CONST32, dl, PtrVT, GA);
|
2015-12-19 04:19:30 +08:00
|
|
|
}
|
|
|
|
|
2018-01-31 02:10:27 +08:00
|
|
|
bool UsePCRel = getTargetMachine().shouldAssumeDSOLocal(*GV->getParent(), GV);
|
|
|
|
if (UsePCRel) {
|
|
|
|
SDValue GA = DAG.getTargetGlobalAddress(GV, dl, PtrVT, Offset,
|
|
|
|
HexagonII::MO_PCREL);
|
|
|
|
return DAG.getNode(HexagonISD::AT_PCREL, dl, PtrVT, GA);
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
|
|
|
|
2018-01-31 02:10:27 +08:00
|
|
|
// Use GOT index.
|
|
|
|
SDValue GOT = DAG.getGLOBAL_OFFSET_TABLE(PtrVT);
|
|
|
|
SDValue GA = DAG.getTargetGlobalAddress(GV, dl, PtrVT, 0, HexagonII::MO_GOT);
|
|
|
|
SDValue Off = DAG.getConstant(Offset, dl, MVT::i32);
|
|
|
|
return DAG.getNode(HexagonISD::AT_GOT, dl, PtrVT, GOT, GA, Off);
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
|
|
|
|
2015-03-20 00:33:08 +08:00
|
|
|
// Specifies that for loads and stores VT can be promoted to PromotedLdStVT.
|
2015-12-19 04:19:30 +08:00
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const {
|
|
|
|
const BlockAddress *BA = cast<BlockAddressSDNode>(Op)->getBlockAddress();
|
|
|
|
SDLoc dl(Op);
|
|
|
|
EVT PtrVT = getPointerTy(DAG.getDataLayout());
|
2015-03-20 00:33:08 +08:00
|
|
|
|
2015-12-19 04:19:30 +08:00
|
|
|
Reloc::Model RM = HTM.getRelocationModel();
|
|
|
|
if (RM == Reloc::Static) {
|
2016-02-18 23:42:57 +08:00
|
|
|
SDValue A = DAG.getTargetBlockAddress(BA, PtrVT);
|
2015-12-19 04:19:30 +08:00
|
|
|
return DAG.getNode(HexagonISD::CONST32_GP, dl, PtrVT, A);
|
2015-03-20 00:33:08 +08:00
|
|
|
}
|
2015-12-19 04:19:30 +08:00
|
|
|
|
|
|
|
SDValue A = DAG.getTargetBlockAddress(BA, PtrVT, 0, HexagonII::MO_PCREL);
|
|
|
|
return DAG.getNode(HexagonISD::AT_PCREL, dl, PtrVT, A);
|
2015-03-20 00:33:08 +08:00
|
|
|
}
|
|
|
|
|
2013-03-08 03:10:28 +08:00
|
|
|
SDValue
|
2015-12-19 04:19:30 +08:00
|
|
|
HexagonTargetLowering::LowerGLOBAL_OFFSET_TABLE(SDValue Op, SelectionDAG &DAG)
|
|
|
|
const {
|
|
|
|
EVT PtrVT = getPointerTy(DAG.getDataLayout());
|
|
|
|
SDValue GOTSym = DAG.getTargetExternalSymbol(HEXAGON_GOT_SYM_NAME, PtrVT,
|
|
|
|
HexagonII::MO_PCREL);
|
|
|
|
return DAG.getNode(HexagonISD::AT_PCREL, SDLoc(Op), PtrVT, GOTSym);
|
2013-03-08 03:10:28 +08:00
|
|
|
}
|
|
|
|
|
2016-02-18 23:42:57 +08:00
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::GetDynamicTLSAddr(SelectionDAG &DAG, SDValue Chain,
|
2017-02-18 06:14:51 +08:00
|
|
|
GlobalAddressSDNode *GA, SDValue Glue, EVT PtrVT, unsigned ReturnReg,
|
2016-02-18 23:42:57 +08:00
|
|
|
unsigned char OperandFlags) const {
|
2017-02-18 06:14:51 +08:00
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
|
|
|
MachineFrameInfo &MFI = MF.getFrameInfo();
|
2016-02-18 23:42:57 +08:00
|
|
|
SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
|
|
|
|
SDLoc dl(GA);
|
|
|
|
SDValue TGA = DAG.getTargetGlobalAddress(GA->getGlobal(), dl,
|
|
|
|
GA->getValueType(0),
|
|
|
|
GA->getOffset(),
|
|
|
|
OperandFlags);
|
|
|
|
// Create Operands for the call.The Operands should have the following:
|
|
|
|
// 1. Chain SDValue
|
|
|
|
// 2. Callee which in this case is the Global address value.
|
|
|
|
// 3. Registers live into the call.In this case its R0, as we
|
|
|
|
// have just one argument to be passed.
|
2017-02-18 06:14:51 +08:00
|
|
|
// 4. Glue.
|
2016-02-18 23:42:57 +08:00
|
|
|
// Note: The order is important.
|
|
|
|
|
2017-02-18 06:14:51 +08:00
|
|
|
const auto &HRI = *Subtarget.getRegisterInfo();
|
|
|
|
const uint32_t *Mask = HRI.getCallPreservedMask(MF, CallingConv::C);
|
|
|
|
assert(Mask && "Missing call preserved mask for calling convention");
|
|
|
|
SDValue Ops[] = { Chain, TGA, DAG.getRegister(Hexagon::R0, PtrVT),
|
|
|
|
DAG.getRegisterMask(Mask), Glue };
|
|
|
|
Chain = DAG.getNode(HexagonISD::CALL, dl, NodeTys, Ops);
|
2016-02-18 23:42:57 +08:00
|
|
|
|
|
|
|
// Inform MFI that function has calls.
|
2016-07-29 02:40:00 +08:00
|
|
|
MFI.setAdjustsStack(true);
|
2016-02-18 23:42:57 +08:00
|
|
|
|
2017-02-18 06:14:51 +08:00
|
|
|
Glue = Chain.getValue(1);
|
|
|
|
return DAG.getCopyFromReg(Chain, dl, ReturnReg, PtrVT, Glue);
|
2016-02-18 23:42:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Lower using the intial executable model for TLS addresses
|
|
|
|
//
|
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerToTLSInitialExecModel(GlobalAddressSDNode *GA,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
SDLoc dl(GA);
|
|
|
|
int64_t Offset = GA->getOffset();
|
|
|
|
auto PtrVT = getPointerTy(DAG.getDataLayout());
|
|
|
|
|
|
|
|
// Get the thread pointer.
|
|
|
|
SDValue TP = DAG.getCopyFromReg(DAG.getEntryNode(), dl, Hexagon::UGP, PtrVT);
|
|
|
|
|
2016-06-27 06:24:01 +08:00
|
|
|
bool IsPositionIndependent = isPositionIndependent();
|
|
|
|
unsigned char TF =
|
|
|
|
IsPositionIndependent ? HexagonII::MO_IEGOT : HexagonII::MO_IE;
|
2016-02-18 23:42:57 +08:00
|
|
|
|
|
|
|
// First generate the TLS symbol address
|
|
|
|
SDValue TGA = DAG.getTargetGlobalAddress(GA->getGlobal(), dl, PtrVT,
|
|
|
|
Offset, TF);
|
|
|
|
|
|
|
|
SDValue Sym = DAG.getNode(HexagonISD::CONST32, dl, PtrVT, TGA);
|
|
|
|
|
2016-06-27 06:24:01 +08:00
|
|
|
if (IsPositionIndependent) {
|
2016-02-18 23:42:57 +08:00
|
|
|
// Generate the GOT pointer in case of position independent code
|
|
|
|
SDValue GOT = LowerGLOBAL_OFFSET_TABLE(Sym, DAG);
|
|
|
|
|
|
|
|
// Add the TLS Symbol address to GOT pointer.This gives
|
|
|
|
// GOT relative relocation for the symbol.
|
|
|
|
Sym = DAG.getNode(ISD::ADD, dl, PtrVT, GOT, Sym);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Load the offset value for TLS symbol.This offset is relative to
|
|
|
|
// thread pointer.
|
[SelectionDAG] Get rid of bool parameters in SelectionDAG::getLoad, getStore, and friends.
Summary:
Instead, we take a single flags arg (a bitset).
Also add a default 0 alignment, and change the order of arguments so the
alignment comes before the flags.
This greatly simplifies many callsites, and fixes a bug in
AMDGPUISelLowering, wherein the order of the args to getLoad was
inverted. It also greatly simplifies the process of adding another flag
to getLoad.
Reviewers: chandlerc, tstellarAMD
Subscribers: jholewinski, arsenm, jyknight, dsanders, nemanjai, llvm-commits
Differential Revision: http://reviews.llvm.org/D22249
llvm-svn: 275592
2016-07-16 02:27:10 +08:00
|
|
|
SDValue LoadOffset =
|
|
|
|
DAG.getLoad(PtrVT, dl, DAG.getEntryNode(), Sym, MachinePointerInfo());
|
2016-02-18 23:42:57 +08:00
|
|
|
|
|
|
|
// Address of the thread local variable is the add of thread
|
|
|
|
// pointer and the offset of the variable.
|
|
|
|
return DAG.getNode(ISD::ADD, dl, PtrVT, TP, LoadOffset);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Lower using the local executable model for TLS addresses
|
|
|
|
//
|
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerToTLSLocalExecModel(GlobalAddressSDNode *GA,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
SDLoc dl(GA);
|
|
|
|
int64_t Offset = GA->getOffset();
|
|
|
|
auto PtrVT = getPointerTy(DAG.getDataLayout());
|
|
|
|
|
|
|
|
// Get the thread pointer.
|
|
|
|
SDValue TP = DAG.getCopyFromReg(DAG.getEntryNode(), dl, Hexagon::UGP, PtrVT);
|
|
|
|
// Generate the TLS symbol address
|
|
|
|
SDValue TGA = DAG.getTargetGlobalAddress(GA->getGlobal(), dl, PtrVT, Offset,
|
|
|
|
HexagonII::MO_TPREL);
|
|
|
|
SDValue Sym = DAG.getNode(HexagonISD::CONST32, dl, PtrVT, TGA);
|
|
|
|
|
|
|
|
// Address of the thread local variable is the add of thread
|
|
|
|
// pointer and the offset of the variable.
|
|
|
|
return DAG.getNode(ISD::ADD, dl, PtrVT, TP, Sym);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Lower using the general dynamic model for TLS addresses
|
|
|
|
//
|
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerToTLSGeneralDynamicModel(GlobalAddressSDNode *GA,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
SDLoc dl(GA);
|
|
|
|
int64_t Offset = GA->getOffset();
|
|
|
|
auto PtrVT = getPointerTy(DAG.getDataLayout());
|
|
|
|
|
|
|
|
// First generate the TLS symbol address
|
|
|
|
SDValue TGA = DAG.getTargetGlobalAddress(GA->getGlobal(), dl, PtrVT, Offset,
|
|
|
|
HexagonII::MO_GDGOT);
|
|
|
|
|
|
|
|
// Then, generate the GOT pointer
|
|
|
|
SDValue GOT = LowerGLOBAL_OFFSET_TABLE(TGA, DAG);
|
|
|
|
|
|
|
|
// Add the TLS symbol and the GOT pointer
|
|
|
|
SDValue Sym = DAG.getNode(HexagonISD::CONST32, dl, PtrVT, TGA);
|
|
|
|
SDValue Chain = DAG.getNode(ISD::ADD, dl, PtrVT, GOT, Sym);
|
|
|
|
|
|
|
|
// Copy over the argument to R0
|
|
|
|
SDValue InFlag;
|
|
|
|
Chain = DAG.getCopyToReg(DAG.getEntryNode(), dl, Hexagon::R0, Chain, InFlag);
|
|
|
|
InFlag = Chain.getValue(1);
|
|
|
|
|
2017-05-03 02:15:33 +08:00
|
|
|
unsigned Flags =
|
|
|
|
static_cast<const HexagonSubtarget &>(DAG.getSubtarget()).useLongCalls()
|
|
|
|
? HexagonII::MO_GDPLT | HexagonII::HMOTF_ConstExtended
|
|
|
|
: HexagonII::MO_GDPLT;
|
|
|
|
|
2017-02-18 06:14:51 +08:00
|
|
|
return GetDynamicTLSAddr(DAG, Chain, GA, InFlag, PtrVT,
|
2017-05-03 02:15:33 +08:00
|
|
|
Hexagon::R0, Flags);
|
2016-02-18 23:42:57 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Lower TLS addresses.
|
|
|
|
//
|
|
|
|
// For now for dynamic models, we only support the general dynamic model.
|
|
|
|
//
|
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerGlobalTLSAddress(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Op);
|
|
|
|
|
|
|
|
switch (HTM.getTLSModel(GA->getGlobal())) {
|
|
|
|
case TLSModel::GeneralDynamic:
|
|
|
|
case TLSModel::LocalDynamic:
|
|
|
|
return LowerToTLSGeneralDynamicModel(GA, DAG);
|
|
|
|
case TLSModel::InitialExec:
|
|
|
|
return LowerToTLSInitialExecModel(GA, DAG);
|
|
|
|
case TLSModel::LocalExec:
|
|
|
|
return LowerToTLSLocalExecModel(GA, DAG);
|
|
|
|
}
|
|
|
|
llvm_unreachable("Bogus TLS model");
|
|
|
|
}
|
|
|
|
|
2011-12-13 05:14:40 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// TargetLowering Implementation
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2015-02-03 06:11:36 +08:00
|
|
|
HexagonTargetLowering::HexagonTargetLowering(const TargetMachine &TM,
|
2015-11-27 02:38:27 +08:00
|
|
|
const HexagonSubtarget &ST)
|
2015-04-23 05:17:00 +08:00
|
|
|
: TargetLowering(TM), HTM(static_cast<const HexagonTargetMachine&>(TM)),
|
2015-11-27 02:38:27 +08:00
|
|
|
Subtarget(ST) {
|
2015-04-23 05:17:00 +08:00
|
|
|
auto &HRI = *Subtarget.getRegisterInfo();
|
2015-03-20 00:33:08 +08:00
|
|
|
|
2019-09-27 20:54:21 +08:00
|
|
|
setPrefLoopAlignment(Align(16));
|
|
|
|
setMinFunctionAlignment(Align(4));
|
|
|
|
setPrefFunctionAlignment(Align(16));
|
2015-04-23 05:17:00 +08:00
|
|
|
setStackPointerRegisterToSaveRestore(HRI.getStackRegister());
|
2018-01-06 04:41:50 +08:00
|
|
|
setBooleanContents(TargetLoweringBase::UndefinedBooleanContent);
|
|
|
|
setBooleanVectorContents(TargetLoweringBase::UndefinedBooleanContent);
|
2015-04-23 05:17:00 +08:00
|
|
|
|
2016-06-23 00:07:10 +08:00
|
|
|
setMaxAtomicSizeInBitsSupported(64);
|
|
|
|
setMinCmpXchgSizeInBits(32);
|
|
|
|
|
2015-04-23 05:17:00 +08:00
|
|
|
if (EnableHexSDNodeSched)
|
|
|
|
setSchedulingPreference(Sched::VLIW);
|
|
|
|
else
|
|
|
|
setSchedulingPreference(Sched::Source);
|
2011-12-13 05:14:40 +08:00
|
|
|
|
2014-06-27 08:13:49 +08:00
|
|
|
// Limits for inline expansion of memcpy/memmove
|
2015-04-23 05:17:00 +08:00
|
|
|
MaxStoresPerMemcpy = MaxStoresPerMemcpyCL;
|
|
|
|
MaxStoresPerMemcpyOptSize = MaxStoresPerMemcpyOptSizeCL;
|
|
|
|
MaxStoresPerMemmove = MaxStoresPerMemmoveCL;
|
|
|
|
MaxStoresPerMemmoveOptSize = MaxStoresPerMemmoveOptSizeCL;
|
|
|
|
MaxStoresPerMemset = MaxStoresPerMemsetCL;
|
|
|
|
MaxStoresPerMemsetOptSize = MaxStoresPerMemsetOptSizeCL;
|
2011-12-13 05:14:40 +08:00
|
|
|
|
2014-06-27 08:13:49 +08:00
|
|
|
//
|
2015-04-23 05:17:00 +08:00
|
|
|
// Set up register classes.
|
2014-06-27 08:13:49 +08:00
|
|
|
//
|
2011-12-13 05:14:40 +08:00
|
|
|
|
2015-04-23 05:17:00 +08:00
|
|
|
addRegisterClass(MVT::i1, &Hexagon::PredRegsRegClass);
|
|
|
|
addRegisterClass(MVT::v2i1, &Hexagon::PredRegsRegClass); // bbbbaaaa
|
|
|
|
addRegisterClass(MVT::v4i1, &Hexagon::PredRegsRegClass); // ddccbbaa
|
|
|
|
addRegisterClass(MVT::v8i1, &Hexagon::PredRegsRegClass); // hgfedcba
|
|
|
|
addRegisterClass(MVT::i32, &Hexagon::IntRegsRegClass);
|
|
|
|
addRegisterClass(MVT::v2i16, &Hexagon::IntRegsRegClass);
|
2017-12-21 04:49:43 +08:00
|
|
|
addRegisterClass(MVT::v4i8, &Hexagon::IntRegsRegClass);
|
2015-04-23 05:17:00 +08:00
|
|
|
addRegisterClass(MVT::i64, &Hexagon::DoubleRegsRegClass);
|
|
|
|
addRegisterClass(MVT::v8i8, &Hexagon::DoubleRegsRegClass);
|
|
|
|
addRegisterClass(MVT::v4i16, &Hexagon::DoubleRegsRegClass);
|
|
|
|
addRegisterClass(MVT::v2i32, &Hexagon::DoubleRegsRegClass);
|
2012-05-11 04:20:25 +08:00
|
|
|
|
2018-10-20 01:31:11 +08:00
|
|
|
addRegisterClass(MVT::f32, &Hexagon::IntRegsRegClass);
|
|
|
|
addRegisterClass(MVT::f64, &Hexagon::DoubleRegsRegClass);
|
2012-05-11 04:20:25 +08:00
|
|
|
|
2015-04-23 05:17:00 +08:00
|
|
|
//
|
|
|
|
// Handling of scalar operations.
|
|
|
|
//
|
|
|
|
// All operations default to "legal", except:
|
|
|
|
// - indexed loads and stores (pre-/post-incremented),
|
|
|
|
// - ANY_EXTEND_VECTOR_INREG, ATOMIC_CMP_SWAP_WITH_SUCCESS, CONCAT_VECTORS,
|
|
|
|
// ConstantFP, DEBUGTRAP, FCEIL, FCOPYSIGN, FEXP, FEXP2, FFLOOR, FGETSIGN,
|
|
|
|
// FLOG, FLOG2, FLOG10, FMAXNUM, FMINNUM, FNEARBYINT, FRINT, FROUND, TRAP,
|
|
|
|
// FTRUNC, PREFETCH, SIGN_EXTEND_VECTOR_INREG, ZERO_EXTEND_VECTOR_INREG,
|
|
|
|
// which default to "expand" for at least one type.
|
|
|
|
|
|
|
|
// Misc operations.
|
2018-08-10 02:03:45 +08:00
|
|
|
setOperationAction(ISD::ConstantFP, MVT::f32, Legal);
|
|
|
|
setOperationAction(ISD::ConstantFP, MVT::f64, Legal);
|
|
|
|
setOperationAction(ISD::TRAP, MVT::Other, Legal);
|
|
|
|
setOperationAction(ISD::ConstantPool, MVT::i32, Custom);
|
|
|
|
setOperationAction(ISD::JumpTable, MVT::i32, Custom);
|
|
|
|
setOperationAction(ISD::BUILD_PAIR, MVT::i64, Expand);
|
|
|
|
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand);
|
|
|
|
setOperationAction(ISD::INLINEASM, MVT::Other, Custom);
|
2019-02-09 04:48:56 +08:00
|
|
|
setOperationAction(ISD::INLINEASM_BR, MVT::Other, Custom);
|
2018-08-10 02:03:45 +08:00
|
|
|
setOperationAction(ISD::PREFETCH, MVT::Other, Custom);
|
|
|
|
setOperationAction(ISD::READCYCLECOUNTER, MVT::i64, Custom);
|
|
|
|
setOperationAction(ISD::INTRINSIC_VOID, MVT::Other, Custom);
|
|
|
|
setOperationAction(ISD::EH_RETURN, MVT::Other, Custom);
|
|
|
|
setOperationAction(ISD::GLOBAL_OFFSET_TABLE, MVT::i32, Custom);
|
|
|
|
setOperationAction(ISD::GlobalTLSAddress, MVT::i32, Custom);
|
|
|
|
setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Custom);
|
2014-06-27 08:13:49 +08:00
|
|
|
|
|
|
|
// Custom legalize GlobalAddress nodes into CONST32.
|
|
|
|
setOperationAction(ISD::GlobalAddress, MVT::i32, Custom);
|
2015-04-23 05:17:00 +08:00
|
|
|
setOperationAction(ISD::GlobalAddress, MVT::i8, Custom);
|
|
|
|
setOperationAction(ISD::BlockAddress, MVT::i32, Custom);
|
2011-12-13 05:14:40 +08:00
|
|
|
|
2015-03-20 00:33:08 +08:00
|
|
|
// Hexagon needs to optimize cases with negative constants.
|
2018-04-19 22:24:31 +08:00
|
|
|
setOperationAction(ISD::SETCC, MVT::i8, Custom);
|
|
|
|
setOperationAction(ISD::SETCC, MVT::i16, Custom);
|
|
|
|
setOperationAction(ISD::SETCC, MVT::v4i8, Custom);
|
|
|
|
setOperationAction(ISD::SETCC, MVT::v2i16, Custom);
|
2015-03-20 00:33:08 +08:00
|
|
|
|
2015-04-23 05:17:00 +08:00
|
|
|
// VASTART needs to be custom lowered to use the VarArgsFrameIndex.
|
|
|
|
setOperationAction(ISD::VASTART, MVT::Other, Custom);
|
|
|
|
setOperationAction(ISD::VAEND, MVT::Other, Expand);
|
|
|
|
setOperationAction(ISD::VAARG, MVT::Other, Expand);
|
Add support for Linux/Musl ABI
Differential revision: https://reviews.llvm.org/D72701
The patch adds a new option ABI for Hexagon. It primary deals with
the way variable arguments are passed and is use in the Hexagon Linux Musl
environment.
If a callee function has a variable argument list, it must perform the
following operations to set up its function prologue:
1. Determine the number of registers which could have been used for passing
unnamed arguments. This can be calculated by counting the number of
registers used for passing named arguments. For example, if the callee
function is as follows:
int foo(int a, ...){ ... }
... then register R0 is used to access the argument ' a '. The registers
available for passing unnamed arguments are R1, R2, R3, R4, and R5.
2. Determine the number and size of the named arguments on the stack.
3. If the callee has named arguments on the stack, it should copy all of these
arguments to a location below the current position on the stack, and the
difference should be the size of the register-saved area plus padding
(if any is necessary).
The register-saved area constitutes all the registers that could have
been used to pass unnamed arguments. If the number of registers forming
the register-saved area is odd, it requires 4 bytes of padding; if the
number is even, no padding is required. This is done to ensure an 8-byte
alignment on the stack. For example, if the callee is as follows:
int foo(int a, ...){ ... }
... then the named arguments should be copied to the following location:
current_position - 5 (for R1-R5) * 4 (bytes) - 4 (bytes of padding)
If the callee is as follows:
int foo(int a, int b, ...){ ... }
... then the named arguments should be copied to the following location:
current_position - 4 (for R2-R5) * 4 (bytes) - 0 (bytes of padding)
4. After any named arguments have been copied, copy all the registers that
could have been used to pass unnamed arguments on the stack. If the number
of registers is odd, leave 4 bytes of padding and then start copying them
on the stack; if the number is even, no padding is required. This
constitutes the register-saved area. If padding is required, ensure
that the start location of padding is 8-byte aligned. If no padding is
required, ensure that the start location of the on-stack copy of the
first register which might have a variable argument is 8-byte aligned.
5. Decrement the stack pointer by the size of register saved area plus the
padding. For example, if the callee is as follows:
int foo(int a, ...){ ... } ;
... then the decrement value should be the following:
5 (for R1-R5) * 4 (bytes) + 4 (bytes of padding) = 24 bytes
The decrement should be performed before the allocframe instruction.
Increment the stack-pointer back by the same amount before returning
from the function.
2019-12-28 03:03:01 +08:00
|
|
|
if (Subtarget.isEnvironmentMusl())
|
|
|
|
setOperationAction(ISD::VACOPY, MVT::Other, Custom);
|
|
|
|
else
|
|
|
|
setOperationAction(ISD::VACOPY, MVT::Other, Expand);
|
2015-04-23 05:17:00 +08:00
|
|
|
|
|
|
|
setOperationAction(ISD::STACKSAVE, MVT::Other, Expand);
|
|
|
|
setOperationAction(ISD::STACKRESTORE, MVT::Other, Expand);
|
|
|
|
setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32, Custom);
|
|
|
|
|
|
|
|
if (EmitJumpTables)
|
2015-12-19 04:19:30 +08:00
|
|
|
setMinimumJumpTableEntries(MinimumJumpTables);
|
2016-01-14 05:43:13 +08:00
|
|
|
else
|
2019-06-20 00:12:01 +08:00
|
|
|
setMinimumJumpTableEntries(std::numeric_limits<unsigned>::max());
|
2015-12-19 04:19:30 +08:00
|
|
|
setOperationAction(ISD::BR_JT, MVT::Other, Expand);
|
2015-04-23 05:17:00 +08:00
|
|
|
|
2020-11-26 03:00:33 +08:00
|
|
|
for (unsigned LegalIntOp :
|
|
|
|
{ISD::ABS, ISD::SMIN, ISD::SMAX, ISD::UMIN, ISD::UMAX}) {
|
|
|
|
setOperationAction(LegalIntOp, MVT::i32, Legal);
|
|
|
|
setOperationAction(LegalIntOp, MVT::i64, Legal);
|
|
|
|
}
|
2018-06-13 05:51:49 +08:00
|
|
|
|
2018-06-01 22:00:32 +08:00
|
|
|
// Hexagon has A4_addp_c and A4_subp_c that take and generate a carry bit,
|
|
|
|
// but they only operate on i64.
|
2015-04-14 04:37:01 +08:00
|
|
|
for (MVT VT : MVT::integer_valuetypes()) {
|
2019-07-01 23:50:09 +08:00
|
|
|
setOperationAction(ISD::UADDO, VT, Custom);
|
|
|
|
setOperationAction(ISD::USUBO, VT, Custom);
|
2018-06-01 22:00:32 +08:00
|
|
|
setOperationAction(ISD::SADDO, VT, Expand);
|
|
|
|
setOperationAction(ISD::SSUBO, VT, Expand);
|
|
|
|
setOperationAction(ISD::ADDCARRY, VT, Expand);
|
|
|
|
setOperationAction(ISD::SUBCARRY, VT, Expand);
|
2015-04-14 04:37:01 +08:00
|
|
|
}
|
2018-06-01 22:00:32 +08:00
|
|
|
setOperationAction(ISD::ADDCARRY, MVT::i64, Custom);
|
|
|
|
setOperationAction(ISD::SUBCARRY, MVT::i64, Custom);
|
2015-04-14 04:37:01 +08:00
|
|
|
|
2015-04-23 05:17:00 +08:00
|
|
|
setOperationAction(ISD::CTLZ, MVT::i8, Promote);
|
|
|
|
setOperationAction(ISD::CTLZ, MVT::i16, Promote);
|
|
|
|
setOperationAction(ISD::CTTZ, MVT::i8, Promote);
|
|
|
|
setOperationAction(ISD::CTTZ, MVT::i16, Promote);
|
|
|
|
|
2018-10-20 01:31:11 +08:00
|
|
|
// Popcount can count # of 1s in i64 but returns i32.
|
2015-04-23 05:17:00 +08:00
|
|
|
setOperationAction(ISD::CTPOP, MVT::i8, Promote);
|
|
|
|
setOperationAction(ISD::CTPOP, MVT::i16, Promote);
|
|
|
|
setOperationAction(ISD::CTPOP, MVT::i32, Promote);
|
2017-02-23 23:02:09 +08:00
|
|
|
setOperationAction(ISD::CTPOP, MVT::i64, Legal);
|
|
|
|
|
|
|
|
setOperationAction(ISD::BITREVERSE, MVT::i32, Legal);
|
|
|
|
setOperationAction(ISD::BITREVERSE, MVT::i64, Legal);
|
|
|
|
setOperationAction(ISD::BSWAP, MVT::i32, Legal);
|
|
|
|
setOperationAction(ISD::BSWAP, MVT::i64, Legal);
|
2014-06-27 08:13:49 +08:00
|
|
|
|
2018-12-21 00:39:20 +08:00
|
|
|
setOperationAction(ISD::FSHL, MVT::i32, Legal);
|
|
|
|
setOperationAction(ISD::FSHL, MVT::i64, Legal);
|
|
|
|
setOperationAction(ISD::FSHR, MVT::i32, Legal);
|
|
|
|
setOperationAction(ISD::FSHR, MVT::i64, Legal);
|
|
|
|
|
2015-04-25 22:46:53 +08:00
|
|
|
for (unsigned IntExpOp :
|
2018-06-05 20:49:19 +08:00
|
|
|
{ISD::SDIV, ISD::UDIV, ISD::SREM, ISD::UREM,
|
|
|
|
ISD::SDIVREM, ISD::UDIVREM, ISD::ROTL, ISD::ROTR,
|
|
|
|
ISD::SHL_PARTS, ISD::SRA_PARTS, ISD::SRL_PARTS,
|
|
|
|
ISD::SMUL_LOHI, ISD::UMUL_LOHI}) {
|
|
|
|
for (MVT VT : MVT::integer_valuetypes())
|
|
|
|
setOperationAction(IntExpOp, VT, Expand);
|
2015-04-25 22:46:53 +08:00
|
|
|
}
|
2014-06-27 08:13:49 +08:00
|
|
|
|
2015-04-25 22:46:53 +08:00
|
|
|
for (unsigned FPExpOp :
|
|
|
|
{ISD::FDIV, ISD::FREM, ISD::FSQRT, ISD::FSIN, ISD::FCOS, ISD::FSINCOS,
|
|
|
|
ISD::FPOW, ISD::FCOPYSIGN}) {
|
2018-06-05 20:49:19 +08:00
|
|
|
for (MVT VT : MVT::fp_valuetypes())
|
|
|
|
setOperationAction(FPExpOp, VT, Expand);
|
2015-04-25 22:46:53 +08:00
|
|
|
}
|
2011-12-13 05:14:40 +08:00
|
|
|
|
2015-04-23 05:17:00 +08:00
|
|
|
// No extending loads from i32.
|
|
|
|
for (MVT VT : MVT::integer_valuetypes()) {
|
|
|
|
setLoadExtAction(ISD::ZEXTLOAD, VT, MVT::i32, Expand);
|
|
|
|
setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i32, Expand);
|
|
|
|
setLoadExtAction(ISD::EXTLOAD, VT, MVT::i32, Expand);
|
|
|
|
}
|
|
|
|
// Turn FP truncstore into trunc + store.
|
|
|
|
setTruncStoreAction(MVT::f64, MVT::f32, Expand);
|
2016-08-19 04:08:15 +08:00
|
|
|
// Turn FP extload into load/fpextend.
|
2015-04-23 05:17:00 +08:00
|
|
|
for (MVT VT : MVT::fp_valuetypes())
|
|
|
|
setLoadExtAction(ISD::EXTLOAD, VT, MVT::f32, Expand);
|
2011-12-13 05:14:40 +08:00
|
|
|
|
2015-04-23 05:17:00 +08:00
|
|
|
// Expand BR_CC and SELECT_CC for all integer and fp types.
|
|
|
|
for (MVT VT : MVT::integer_valuetypes()) {
|
|
|
|
setOperationAction(ISD::BR_CC, VT, Expand);
|
|
|
|
setOperationAction(ISD::SELECT_CC, VT, Expand);
|
|
|
|
}
|
|
|
|
for (MVT VT : MVT::fp_valuetypes()) {
|
|
|
|
setOperationAction(ISD::BR_CC, VT, Expand);
|
|
|
|
setOperationAction(ISD::SELECT_CC, VT, Expand);
|
|
|
|
}
|
|
|
|
setOperationAction(ISD::BR_CC, MVT::Other, Expand);
|
2011-12-13 05:14:40 +08:00
|
|
|
|
2015-04-23 05:17:00 +08:00
|
|
|
//
|
|
|
|
// Handling of vector operations.
|
|
|
|
//
|
2011-12-13 05:14:40 +08:00
|
|
|
|
2015-04-23 05:17:00 +08:00
|
|
|
// Set the action for vector operations to "expand", then override it with
|
|
|
|
// either "custom" or "legal" for specific cases.
|
2015-10-18 13:15:34 +08:00
|
|
|
static const unsigned VectExpOps[] = {
|
2015-04-23 05:17:00 +08:00
|
|
|
// Integer arithmetic:
|
Set ADDE/ADDC/SUBE/SUBC to expand by default
Summary:
They've been deprecated in favor of UADDO/ADDCARRY or USUBO/SUBCARRY for a while.
Target that uses these opcodes are changed in order to ensure their behavior doesn't change.
Reviewers: efriedma, craig.topper, dblaikie, bkramer
Subscribers: jholewinski, arsenm, jyknight, sdardis, nemanjai, nhaehnle, kbarton, fedor.sergeev, asb, rbar, johnrusso, simoncook, jordy.potman.lists, apazos, sabuasal, niosHD, jrtc27, zzheng, edward-jones, mgrang, atanasyan, llvm-commits
Differential Revision: https://reviews.llvm.org/D47422
llvm-svn: 333748
2018-06-01 21:21:33 +08:00
|
|
|
ISD::ADD, ISD::SUB, ISD::MUL, ISD::SDIV, ISD::UDIV,
|
|
|
|
ISD::SREM, ISD::UREM, ISD::SDIVREM, ISD::UDIVREM, ISD::SADDO,
|
|
|
|
ISD::UADDO, ISD::SSUBO, ISD::USUBO, ISD::SMUL_LOHI, ISD::UMUL_LOHI,
|
2015-04-23 05:17:00 +08:00
|
|
|
// Logical/bit:
|
|
|
|
ISD::AND, ISD::OR, ISD::XOR, ISD::ROTL, ISD::ROTR,
|
2016-04-28 11:34:31 +08:00
|
|
|
ISD::CTPOP, ISD::CTLZ, ISD::CTTZ,
|
2015-04-23 05:17:00 +08:00
|
|
|
// Floating point arithmetic/math functions:
|
|
|
|
ISD::FADD, ISD::FSUB, ISD::FMUL, ISD::FMA, ISD::FDIV,
|
|
|
|
ISD::FREM, ISD::FNEG, ISD::FABS, ISD::FSQRT, ISD::FSIN,
|
2017-05-30 23:27:55 +08:00
|
|
|
ISD::FCOS, ISD::FPOW, ISD::FLOG, ISD::FLOG2,
|
2015-04-23 05:17:00 +08:00
|
|
|
ISD::FLOG10, ISD::FEXP, ISD::FEXP2, ISD::FCEIL, ISD::FTRUNC,
|
|
|
|
ISD::FRINT, ISD::FNEARBYINT, ISD::FROUND, ISD::FFLOOR,
|
|
|
|
ISD::FMINNUM, ISD::FMAXNUM, ISD::FSINCOS,
|
|
|
|
// Misc:
|
2016-10-27 22:30:16 +08:00
|
|
|
ISD::BR_CC, ISD::SELECT_CC, ISD::ConstantPool,
|
2015-04-23 05:17:00 +08:00
|
|
|
// Vector:
|
|
|
|
ISD::BUILD_VECTOR, ISD::SCALAR_TO_VECTOR,
|
|
|
|
ISD::EXTRACT_VECTOR_ELT, ISD::INSERT_VECTOR_ELT,
|
|
|
|
ISD::EXTRACT_SUBVECTOR, ISD::INSERT_SUBVECTOR,
|
2020-10-10 09:17:50 +08:00
|
|
|
ISD::CONCAT_VECTORS, ISD::VECTOR_SHUFFLE,
|
|
|
|
ISD::SPLAT_VECTOR,
|
2015-04-23 05:17:00 +08:00
|
|
|
};
|
|
|
|
|
2019-09-17 18:19:23 +08:00
|
|
|
for (MVT VT : MVT::fixedlen_vector_valuetypes()) {
|
2015-04-25 22:46:53 +08:00
|
|
|
for (unsigned VectExpOp : VectExpOps)
|
|
|
|
setOperationAction(VectExpOp, VT, Expand);
|
2015-04-23 05:17:00 +08:00
|
|
|
|
2016-09-09 01:42:14 +08:00
|
|
|
// Expand all extending loads and truncating stores:
|
2019-09-17 18:19:23 +08:00
|
|
|
for (MVT TargetVT : MVT::fixedlen_vector_valuetypes()) {
|
2016-09-09 01:42:14 +08:00
|
|
|
if (TargetVT == VT)
|
|
|
|
continue;
|
2015-04-23 05:17:00 +08:00
|
|
|
setLoadExtAction(ISD::EXTLOAD, TargetVT, VT, Expand);
|
2016-09-09 01:42:14 +08:00
|
|
|
setLoadExtAction(ISD::ZEXTLOAD, TargetVT, VT, Expand);
|
|
|
|
setLoadExtAction(ISD::SEXTLOAD, TargetVT, VT, Expand);
|
2015-04-23 05:17:00 +08:00
|
|
|
setTruncStoreAction(VT, TargetVT, Expand);
|
|
|
|
}
|
|
|
|
|
2016-10-27 22:30:16 +08:00
|
|
|
// Normalize all inputs to SELECT to be vectors of i32.
|
|
|
|
if (VT.getVectorElementType() != MVT::i32) {
|
|
|
|
MVT VT32 = MVT::getVectorVT(MVT::i32, VT.getSizeInBits()/32);
|
|
|
|
setOperationAction(ISD::SELECT, VT, Promote);
|
|
|
|
AddPromotedToType(ISD::SELECT, VT, VT32);
|
|
|
|
}
|
2015-04-23 05:17:00 +08:00
|
|
|
setOperationAction(ISD::SRA, VT, Custom);
|
|
|
|
setOperationAction(ISD::SHL, VT, Custom);
|
|
|
|
setOperationAction(ISD::SRL, VT, Custom);
|
|
|
|
}
|
|
|
|
|
2017-10-21 03:33:12 +08:00
|
|
|
// Extending loads from (native) vectors of i8 into (native) vectors of i16
|
|
|
|
// are legal.
|
2018-01-24 01:53:59 +08:00
|
|
|
setLoadExtAction(ISD::EXTLOAD, MVT::v2i16, MVT::v2i8, Legal);
|
2017-10-21 03:33:12 +08:00
|
|
|
setLoadExtAction(ISD::ZEXTLOAD, MVT::v2i16, MVT::v2i8, Legal);
|
|
|
|
setLoadExtAction(ISD::SEXTLOAD, MVT::v2i16, MVT::v2i8, Legal);
|
2018-01-24 01:53:59 +08:00
|
|
|
setLoadExtAction(ISD::EXTLOAD, MVT::v4i16, MVT::v4i8, Legal);
|
2017-10-21 03:33:12 +08:00
|
|
|
setLoadExtAction(ISD::ZEXTLOAD, MVT::v4i16, MVT::v4i8, Legal);
|
|
|
|
setLoadExtAction(ISD::SEXTLOAD, MVT::v4i16, MVT::v4i8, Legal);
|
|
|
|
|
2020-01-03 11:26:41 +08:00
|
|
|
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::v2i8, Legal);
|
|
|
|
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::v2i16, Legal);
|
|
|
|
setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::v2i32, Legal);
|
|
|
|
|
2015-04-23 05:17:00 +08:00
|
|
|
// Types natively supported:
|
2018-01-24 01:53:59 +08:00
|
|
|
for (MVT NativeVT : {MVT::v8i1, MVT::v4i1, MVT::v2i1, MVT::v4i8,
|
|
|
|
MVT::v8i8, MVT::v2i16, MVT::v4i16, MVT::v2i32}) {
|
2015-04-25 22:46:53 +08:00
|
|
|
setOperationAction(ISD::BUILD_VECTOR, NativeVT, Custom);
|
|
|
|
setOperationAction(ISD::EXTRACT_VECTOR_ELT, NativeVT, Custom);
|
|
|
|
setOperationAction(ISD::INSERT_VECTOR_ELT, NativeVT, Custom);
|
|
|
|
setOperationAction(ISD::EXTRACT_SUBVECTOR, NativeVT, Custom);
|
|
|
|
setOperationAction(ISD::INSERT_SUBVECTOR, NativeVT, Custom);
|
|
|
|
setOperationAction(ISD::CONCAT_VECTORS, NativeVT, Custom);
|
|
|
|
|
|
|
|
setOperationAction(ISD::ADD, NativeVT, Legal);
|
|
|
|
setOperationAction(ISD::SUB, NativeVT, Legal);
|
|
|
|
setOperationAction(ISD::MUL, NativeVT, Legal);
|
|
|
|
setOperationAction(ISD::AND, NativeVT, Legal);
|
|
|
|
setOperationAction(ISD::OR, NativeVT, Legal);
|
|
|
|
setOperationAction(ISD::XOR, NativeVT, Legal);
|
2020-10-10 09:17:50 +08:00
|
|
|
|
|
|
|
if (NativeVT.getVectorElementType() != MVT::i1)
|
|
|
|
setOperationAction(ISD::SPLAT_VECTOR, NativeVT, Legal);
|
2015-04-23 05:17:00 +08:00
|
|
|
}
|
|
|
|
|
2020-11-26 03:00:33 +08:00
|
|
|
for (MVT VT : {MVT::v8i8, MVT::v4i16, MVT::v2i32}) {
|
|
|
|
setOperationAction(ISD::SMIN, VT, Legal);
|
|
|
|
setOperationAction(ISD::SMAX, VT, Legal);
|
|
|
|
setOperationAction(ISD::UMIN, VT, Legal);
|
|
|
|
setOperationAction(ISD::UMAX, VT, Legal);
|
|
|
|
}
|
|
|
|
|
2018-03-08 01:27:18 +08:00
|
|
|
// Custom lower unaligned loads.
|
2018-08-09 01:00:09 +08:00
|
|
|
// Also, for both loads and stores, verify the alignment of the address
|
|
|
|
// in case it is a compile-time constant. This is a usability feature to
|
|
|
|
// provide a meaningful error message to users.
|
|
|
|
for (MVT VT : {MVT::i16, MVT::i32, MVT::v4i8, MVT::i64, MVT::v8i8,
|
|
|
|
MVT::v2i16, MVT::v4i16, MVT::v2i32}) {
|
|
|
|
setOperationAction(ISD::LOAD, VT, Custom);
|
|
|
|
setOperationAction(ISD::STORE, VT, Custom);
|
2018-03-08 01:27:18 +08:00
|
|
|
}
|
|
|
|
|
2021-05-11 04:26:57 +08:00
|
|
|
// Custom-lower load/stores of boolean vectors.
|
|
|
|
for (MVT VT : {MVT::v2i1, MVT::v4i1, MVT::v8i1}) {
|
|
|
|
setOperationAction(ISD::LOAD, VT, Custom);
|
|
|
|
setOperationAction(ISD::STORE, VT, Custom);
|
|
|
|
}
|
|
|
|
|
2019-08-17 00:16:27 +08:00
|
|
|
for (MVT VT : {MVT::v2i16, MVT::v4i8, MVT::v8i8, MVT::v2i32, MVT::v4i16,
|
|
|
|
MVT::v2i32}) {
|
|
|
|
setCondCodeAction(ISD::SETNE, VT, Expand);
|
2018-03-16 23:03:37 +08:00
|
|
|
setCondCodeAction(ISD::SETLE, VT, Expand);
|
2019-08-17 00:16:27 +08:00
|
|
|
setCondCodeAction(ISD::SETGE, VT, Expand);
|
|
|
|
setCondCodeAction(ISD::SETLT, VT, Expand);
|
2018-03-16 23:03:37 +08:00
|
|
|
setCondCodeAction(ISD::SETULE, VT, Expand);
|
2019-08-17 00:16:27 +08:00
|
|
|
setCondCodeAction(ISD::SETUGE, VT, Expand);
|
|
|
|
setCondCodeAction(ISD::SETULT, VT, Expand);
|
2018-03-16 23:03:37 +08:00
|
|
|
}
|
|
|
|
|
2018-01-24 01:53:59 +08:00
|
|
|
// Custom-lower bitcasts from i8 to v8i1.
|
|
|
|
setOperationAction(ISD::BITCAST, MVT::i8, Custom);
|
2015-04-23 05:17:00 +08:00
|
|
|
setOperationAction(ISD::SETCC, MVT::v2i16, Custom);
|
2019-08-16 03:20:09 +08:00
|
|
|
setOperationAction(ISD::VSELECT, MVT::v4i8, Custom);
|
2015-04-23 05:17:00 +08:00
|
|
|
setOperationAction(ISD::VSELECT, MVT::v2i16, Custom);
|
2018-01-16 02:33:33 +08:00
|
|
|
setOperationAction(ISD::VECTOR_SHUFFLE, MVT::v4i8, Custom);
|
2015-04-23 05:17:00 +08:00
|
|
|
setOperationAction(ISD::VECTOR_SHUFFLE, MVT::v4i16, Custom);
|
|
|
|
setOperationAction(ISD::VECTOR_SHUFFLE, MVT::v8i8, Custom);
|
2016-09-14 05:16:07 +08:00
|
|
|
|
2018-10-20 01:31:11 +08:00
|
|
|
// V5+.
|
|
|
|
setOperationAction(ISD::FMA, MVT::f64, Expand);
|
|
|
|
setOperationAction(ISD::FADD, MVT::f64, Expand);
|
|
|
|
setOperationAction(ISD::FSUB, MVT::f64, Expand);
|
|
|
|
setOperationAction(ISD::FMUL, MVT::f64, Expand);
|
|
|
|
|
|
|
|
setOperationAction(ISD::FMINNUM, MVT::f32, Legal);
|
|
|
|
setOperationAction(ISD::FMAXNUM, MVT::f32, Legal);
|
|
|
|
|
|
|
|
setOperationAction(ISD::FP_TO_UINT, MVT::i1, Promote);
|
|
|
|
setOperationAction(ISD::FP_TO_UINT, MVT::i8, Promote);
|
|
|
|
setOperationAction(ISD::FP_TO_UINT, MVT::i16, Promote);
|
|
|
|
setOperationAction(ISD::FP_TO_SINT, MVT::i1, Promote);
|
|
|
|
setOperationAction(ISD::FP_TO_SINT, MVT::i8, Promote);
|
|
|
|
setOperationAction(ISD::FP_TO_SINT, MVT::i16, Promote);
|
|
|
|
setOperationAction(ISD::UINT_TO_FP, MVT::i1, Promote);
|
|
|
|
setOperationAction(ISD::UINT_TO_FP, MVT::i8, Promote);
|
|
|
|
setOperationAction(ISD::UINT_TO_FP, MVT::i16, Promote);
|
|
|
|
setOperationAction(ISD::SINT_TO_FP, MVT::i1, Promote);
|
|
|
|
setOperationAction(ISD::SINT_TO_FP, MVT::i8, Promote);
|
|
|
|
setOperationAction(ISD::SINT_TO_FP, MVT::i16, Promote);
|
2015-04-23 05:17:00 +08:00
|
|
|
|
|
|
|
// Handling of indexed loads/stores: default is "expand".
|
|
|
|
//
|
2018-05-19 02:14:44 +08:00
|
|
|
for (MVT VT : {MVT::i8, MVT::i16, MVT::i32, MVT::i64, MVT::f32, MVT::f64,
|
|
|
|
MVT::v2i16, MVT::v2i32, MVT::v4i8, MVT::v4i16, MVT::v8i8}) {
|
2016-07-27 04:30:30 +08:00
|
|
|
setIndexedLoadAction(ISD::POST_INC, VT, Legal);
|
|
|
|
setIndexedStoreAction(ISD::POST_INC, VT, Legal);
|
2015-04-23 05:17:00 +08:00
|
|
|
}
|
|
|
|
|
2018-12-06 05:01:07 +08:00
|
|
|
// Subtarget-specific operation actions.
|
|
|
|
//
|
|
|
|
if (Subtarget.hasV60Ops()) {
|
2018-12-21 00:39:20 +08:00
|
|
|
setOperationAction(ISD::ROTL, MVT::i32, Legal);
|
|
|
|
setOperationAction(ISD::ROTL, MVT::i64, Legal);
|
|
|
|
setOperationAction(ISD::ROTR, MVT::i32, Legal);
|
|
|
|
setOperationAction(ISD::ROTR, MVT::i64, Legal);
|
2018-12-06 05:01:07 +08:00
|
|
|
}
|
|
|
|
if (Subtarget.hasV66Ops()) {
|
|
|
|
setOperationAction(ISD::FADD, MVT::f64, Legal);
|
|
|
|
setOperationAction(ISD::FSUB, MVT::f64, Legal);
|
|
|
|
}
|
2020-01-18 06:29:40 +08:00
|
|
|
if (Subtarget.hasV67Ops()) {
|
|
|
|
setOperationAction(ISD::FMINNUM, MVT::f64, Legal);
|
|
|
|
setOperationAction(ISD::FMAXNUM, MVT::f64, Legal);
|
|
|
|
setOperationAction(ISD::FMUL, MVT::f64, Legal);
|
|
|
|
}
|
2018-12-06 05:01:07 +08:00
|
|
|
|
2019-08-17 00:16:27 +08:00
|
|
|
setTargetDAGCombine(ISD::VSELECT);
|
|
|
|
|
2018-02-07 04:22:20 +08:00
|
|
|
if (Subtarget.useHVXOps())
|
|
|
|
initializeHVXLowering();
|
2017-12-21 04:49:43 +08:00
|
|
|
|
2015-04-23 05:17:00 +08:00
|
|
|
computeRegisterProperties(&HRI);
|
|
|
|
|
|
|
|
//
|
|
|
|
// Library calls for unsupported operations
|
|
|
|
//
|
|
|
|
bool FastMath = EnableFastMath;
|
|
|
|
|
2015-04-25 22:46:46 +08:00
|
|
|
setLibcallName(RTLIB::SDIV_I32, "__hexagon_divsi3");
|
|
|
|
setLibcallName(RTLIB::SDIV_I64, "__hexagon_divdi3");
|
|
|
|
setLibcallName(RTLIB::UDIV_I32, "__hexagon_udivsi3");
|
|
|
|
setLibcallName(RTLIB::UDIV_I64, "__hexagon_udivdi3");
|
|
|
|
setLibcallName(RTLIB::SREM_I32, "__hexagon_modsi3");
|
|
|
|
setLibcallName(RTLIB::SREM_I64, "__hexagon_moddi3");
|
|
|
|
setLibcallName(RTLIB::UREM_I32, "__hexagon_umodsi3");
|
|
|
|
setLibcallName(RTLIB::UREM_I64, "__hexagon_umoddi3");
|
|
|
|
|
|
|
|
setLibcallName(RTLIB::SINTTOFP_I128_F64, "__hexagon_floattidf");
|
|
|
|
setLibcallName(RTLIB::SINTTOFP_I128_F32, "__hexagon_floattisf");
|
|
|
|
setLibcallName(RTLIB::FPTOUINT_F32_I128, "__hexagon_fixunssfti");
|
|
|
|
setLibcallName(RTLIB::FPTOUINT_F64_I128, "__hexagon_fixunsdfti");
|
|
|
|
setLibcallName(RTLIB::FPTOSINT_F32_I128, "__hexagon_fixsfti");
|
|
|
|
setLibcallName(RTLIB::FPTOSINT_F64_I128, "__hexagon_fixdfti");
|
2015-04-23 05:17:00 +08:00
|
|
|
|
|
|
|
// This is the only fast library function for sqrtd.
|
|
|
|
if (FastMath)
|
2015-04-25 22:46:46 +08:00
|
|
|
setLibcallName(RTLIB::SQRT_F64, "__hexagon_fast2_sqrtdf2");
|
2015-04-23 05:17:00 +08:00
|
|
|
|
2015-04-25 22:46:46 +08:00
|
|
|
// Prefix is: nothing for "slow-math",
|
2018-10-20 01:31:11 +08:00
|
|
|
// "fast2_" for V5+ fast-math double-precision
|
2015-04-23 05:17:00 +08:00
|
|
|
// (actually, keep fast-math and fast-math2 separate for now)
|
2015-04-25 22:46:46 +08:00
|
|
|
if (FastMath) {
|
|
|
|
setLibcallName(RTLIB::ADD_F64, "__hexagon_fast_adddf3");
|
|
|
|
setLibcallName(RTLIB::SUB_F64, "__hexagon_fast_subdf3");
|
|
|
|
setLibcallName(RTLIB::MUL_F64, "__hexagon_fast_muldf3");
|
|
|
|
setLibcallName(RTLIB::DIV_F64, "__hexagon_fast_divdf3");
|
|
|
|
setLibcallName(RTLIB::DIV_F32, "__hexagon_fast_divsf3");
|
|
|
|
} else {
|
|
|
|
setLibcallName(RTLIB::ADD_F64, "__hexagon_adddf3");
|
|
|
|
setLibcallName(RTLIB::SUB_F64, "__hexagon_subdf3");
|
|
|
|
setLibcallName(RTLIB::MUL_F64, "__hexagon_muldf3");
|
|
|
|
setLibcallName(RTLIB::DIV_F64, "__hexagon_divdf3");
|
|
|
|
setLibcallName(RTLIB::DIV_F32, "__hexagon_divsf3");
|
|
|
|
}
|
2015-04-23 05:17:00 +08:00
|
|
|
|
2018-10-20 01:31:11 +08:00
|
|
|
if (FastMath)
|
|
|
|
setLibcallName(RTLIB::SQRT_F32, "__hexagon_fast2_sqrtf");
|
|
|
|
else
|
|
|
|
setLibcallName(RTLIB::SQRT_F32, "__hexagon_sqrtf");
|
2015-04-23 05:17:00 +08:00
|
|
|
|
|
|
|
// These cause problems when the shift amount is non-constant.
|
|
|
|
setLibcallName(RTLIB::SHL_I128, nullptr);
|
|
|
|
setLibcallName(RTLIB::SRL_I128, nullptr);
|
|
|
|
setLibcallName(RTLIB::SRA_I128, nullptr);
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
|
|
|
|
2015-04-23 05:17:00 +08:00
|
|
|
const char* HexagonTargetLowering::getTargetNodeName(unsigned Opcode) const {
|
2015-05-08 05:33:59 +08:00
|
|
|
switch ((HexagonISD::NodeType)Opcode) {
|
2018-06-01 22:00:32 +08:00
|
|
|
case HexagonISD::ADDC: return "HexagonISD::ADDC";
|
|
|
|
case HexagonISD::SUBC: return "HexagonISD::SUBC";
|
2015-04-23 05:17:00 +08:00
|
|
|
case HexagonISD::ALLOCA: return "HexagonISD::ALLOCA";
|
|
|
|
case HexagonISD::AT_GOT: return "HexagonISD::AT_GOT";
|
|
|
|
case HexagonISD::AT_PCREL: return "HexagonISD::AT_PCREL";
|
|
|
|
case HexagonISD::BARRIER: return "HexagonISD::BARRIER";
|
2016-08-12 19:12:02 +08:00
|
|
|
case HexagonISD::CALL: return "HexagonISD::CALL";
|
|
|
|
case HexagonISD::CALLnr: return "HexagonISD::CALLnr";
|
2015-04-23 05:17:00 +08:00
|
|
|
case HexagonISD::CALLR: return "HexagonISD::CALLR";
|
|
|
|
case HexagonISD::COMBINE: return "HexagonISD::COMBINE";
|
|
|
|
case HexagonISD::CONST32_GP: return "HexagonISD::CONST32_GP";
|
|
|
|
case HexagonISD::CONST32: return "HexagonISD::CONST32";
|
|
|
|
case HexagonISD::CP: return "HexagonISD::CP";
|
|
|
|
case HexagonISD::DCFETCH: return "HexagonISD::DCFETCH";
|
|
|
|
case HexagonISD::EH_RETURN: return "HexagonISD::EH_RETURN";
|
2018-01-24 01:53:59 +08:00
|
|
|
case HexagonISD::TSTBIT: return "HexagonISD::TSTBIT";
|
2015-04-23 05:17:00 +08:00
|
|
|
case HexagonISD::EXTRACTU: return "HexagonISD::EXTRACTU";
|
|
|
|
case HexagonISD::INSERT: return "HexagonISD::INSERT";
|
|
|
|
case HexagonISD::JT: return "HexagonISD::JT";
|
|
|
|
case HexagonISD::RET_FLAG: return "HexagonISD::RET_FLAG";
|
|
|
|
case HexagonISD::TC_RETURN: return "HexagonISD::TC_RETURN";
|
2017-07-11 04:16:44 +08:00
|
|
|
case HexagonISD::VASL: return "HexagonISD::VASL";
|
|
|
|
case HexagonISD::VASR: return "HexagonISD::VASR";
|
|
|
|
case HexagonISD::VLSR: return "HexagonISD::VLSR";
|
2017-12-07 00:40:37 +08:00
|
|
|
case HexagonISD::VEXTRACTW: return "HexagonISD::VEXTRACTW";
|
|
|
|
case HexagonISD::VINSERTW0: return "HexagonISD::VINSERTW0";
|
|
|
|
case HexagonISD::VROR: return "HexagonISD::VROR";
|
2017-02-23 06:28:47 +08:00
|
|
|
case HexagonISD::READCYCLE: return "HexagonISD::READCYCLE";
|
2019-08-17 00:16:27 +08:00
|
|
|
case HexagonISD::PTRUE: return "HexagonISD::PTRUE";
|
|
|
|
case HexagonISD::PFALSE: return "HexagonISD::PFALSE";
|
2018-01-24 01:53:59 +08:00
|
|
|
case HexagonISD::D2P: return "HexagonISD::D2P";
|
|
|
|
case HexagonISD::P2D: return "HexagonISD::P2D";
|
|
|
|
case HexagonISD::V2Q: return "HexagonISD::V2Q";
|
|
|
|
case HexagonISD::Q2V: return "HexagonISD::Q2V";
|
2018-02-06 22:24:57 +08:00
|
|
|
case HexagonISD::QCAT: return "HexagonISD::QCAT";
|
2018-02-06 22:16:52 +08:00
|
|
|
case HexagonISD::QTRUE: return "HexagonISD::QTRUE";
|
|
|
|
case HexagonISD::QFALSE: return "HexagonISD::QFALSE";
|
2018-01-24 01:53:59 +08:00
|
|
|
case HexagonISD::TYPECAST: return "HexagonISD::TYPECAST";
|
2018-03-08 01:27:18 +08:00
|
|
|
case HexagonISD::VALIGN: return "HexagonISD::VALIGN";
|
2018-02-15 04:46:06 +08:00
|
|
|
case HexagonISD::VALIGNADDR: return "HexagonISD::VALIGNADDR";
|
2020-09-05 08:33:14 +08:00
|
|
|
case HexagonISD::VPACKL: return "HexagonISD::VPACKL";
|
2020-09-15 03:04:54 +08:00
|
|
|
case HexagonISD::VUNPACK: return "HexagonISD::VUNPACK";
|
|
|
|
case HexagonISD::VUNPACKU: return "HexagonISD::VUNPACKU";
|
2020-10-09 06:12:32 +08:00
|
|
|
case HexagonISD::ISEL: return "HexagonISD::ISEL";
|
2015-05-08 05:33:59 +08:00
|
|
|
case HexagonISD::OP_END: break;
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
2015-05-08 05:33:59 +08:00
|
|
|
return nullptr;
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
|
|
|
|
2021-06-25 22:30:59 +08:00
|
|
|
bool
|
2021-06-25 23:22:01 +08:00
|
|
|
HexagonTargetLowering::validateConstPtrAlignment(SDValue Ptr, Align NeedAlign,
|
2021-06-25 22:30:59 +08:00
|
|
|
const SDLoc &dl, SelectionDAG &DAG) const {
|
2018-08-09 01:00:09 +08:00
|
|
|
auto *CA = dyn_cast<ConstantSDNode>(Ptr);
|
|
|
|
if (!CA)
|
2021-06-25 22:30:59 +08:00
|
|
|
return true;
|
2018-08-09 01:00:09 +08:00
|
|
|
unsigned Addr = CA->getZExtValue();
|
2021-06-25 23:22:01 +08:00
|
|
|
Align HaveAlign =
|
2021-06-30 18:36:06 +08:00
|
|
|
Addr != 0 ? Align(1ull << countTrailingZeros(Addr)) : NeedAlign;
|
2021-06-25 22:30:59 +08:00
|
|
|
if (HaveAlign >= NeedAlign)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
static int DK_MisalignedTrap = llvm::getNextAvailablePluginDiagnosticKind();
|
|
|
|
|
|
|
|
struct DiagnosticInfoMisalignedTrap : public DiagnosticInfo {
|
|
|
|
DiagnosticInfoMisalignedTrap(StringRef M)
|
|
|
|
: DiagnosticInfo(DK_MisalignedTrap, DS_Remark), Msg(M) {}
|
|
|
|
void print(DiagnosticPrinter &DP) const override {
|
|
|
|
DP << Msg;
|
|
|
|
}
|
|
|
|
static bool classof(const DiagnosticInfo *DI) {
|
|
|
|
return DI->getKind() == DK_MisalignedTrap;
|
|
|
|
}
|
|
|
|
StringRef Msg;
|
|
|
|
};
|
|
|
|
|
|
|
|
std::string ErrMsg;
|
|
|
|
raw_string_ostream O(ErrMsg);
|
|
|
|
O << "Misaligned constant address: " << format_hex(Addr, 10)
|
|
|
|
<< " has alignment " << HaveAlign.value()
|
|
|
|
<< ", but the memory access requires " << NeedAlign.value();
|
|
|
|
if (DebugLoc DL = dl.getDebugLoc())
|
|
|
|
DL.print(O << ", at ");
|
|
|
|
O << ". The instruction has been replaced with a trap.";
|
|
|
|
|
|
|
|
DAG.getContext()->diagnose(DiagnosticInfoMisalignedTrap(O.str()));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::replaceMemWithUndef(SDValue Op, SelectionDAG &DAG)
|
|
|
|
const {
|
|
|
|
const SDLoc &dl(Op);
|
|
|
|
auto *LS = cast<LSBaseSDNode>(Op.getNode());
|
|
|
|
assert(!LS->isIndexed() && "Not expecting indexed ops on constant address");
|
|
|
|
|
|
|
|
SDValue Chain = LS->getChain();
|
|
|
|
SDValue Trap = DAG.getNode(ISD::TRAP, dl, MVT::Other, Chain);
|
|
|
|
if (LS->getOpcode() == ISD::LOAD)
|
|
|
|
return DAG.getMergeValues({DAG.getUNDEF(ty(Op)), Trap}, dl);
|
|
|
|
return Trap;
|
2018-08-09 01:00:09 +08:00
|
|
|
}
|
|
|
|
|
2018-03-29 21:52:46 +08:00
|
|
|
// Bit-reverse Load Intrinsic: Check if the instruction is a bit reverse load
|
|
|
|
// intrinsic.
|
|
|
|
static bool isBrevLdIntrinsic(const Value *Inst) {
|
|
|
|
unsigned ID = cast<IntrinsicInst>(Inst)->getIntrinsicID();
|
|
|
|
return (ID == Intrinsic::hexagon_L2_loadrd_pbr ||
|
|
|
|
ID == Intrinsic::hexagon_L2_loadri_pbr ||
|
|
|
|
ID == Intrinsic::hexagon_L2_loadrh_pbr ||
|
|
|
|
ID == Intrinsic::hexagon_L2_loadruh_pbr ||
|
|
|
|
ID == Intrinsic::hexagon_L2_loadrb_pbr ||
|
|
|
|
ID == Intrinsic::hexagon_L2_loadrub_pbr);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bit-reverse Load Intrinsic :Crawl up and figure out the object from previous
|
|
|
|
// instruction. So far we only handle bitcast, extract value and bit reverse
|
|
|
|
// load intrinsic instructions. Should we handle CGEP ?
|
|
|
|
static Value *getBrevLdObject(Value *V) {
|
|
|
|
if (Operator::getOpcode(V) == Instruction::ExtractValue ||
|
|
|
|
Operator::getOpcode(V) == Instruction::BitCast)
|
|
|
|
V = cast<Operator>(V)->getOperand(0);
|
|
|
|
else if (isa<IntrinsicInst>(V) && isBrevLdIntrinsic(V))
|
|
|
|
V = cast<Instruction>(V)->getOperand(0);
|
|
|
|
return V;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bit-reverse Load Intrinsic: For a PHI Node return either an incoming edge or
|
|
|
|
// a back edge. If the back edge comes from the intrinsic itself, the incoming
|
|
|
|
// edge is returned.
|
|
|
|
static Value *returnEdge(const PHINode *PN, Value *IntrBaseVal) {
|
|
|
|
const BasicBlock *Parent = PN->getParent();
|
|
|
|
int Idx = -1;
|
|
|
|
for (unsigned i = 0, e = PN->getNumIncomingValues(); i < e; ++i) {
|
|
|
|
BasicBlock *Blk = PN->getIncomingBlock(i);
|
|
|
|
// Determine if the back edge is originated from intrinsic.
|
|
|
|
if (Blk == Parent) {
|
|
|
|
Value *BackEdgeVal = PN->getIncomingValue(i);
|
|
|
|
Value *BaseVal;
|
|
|
|
// Loop over till we return the same Value or we hit the IntrBaseVal.
|
|
|
|
do {
|
|
|
|
BaseVal = BackEdgeVal;
|
|
|
|
BackEdgeVal = getBrevLdObject(BackEdgeVal);
|
|
|
|
} while ((BaseVal != BackEdgeVal) && (IntrBaseVal != BackEdgeVal));
|
|
|
|
// If the getBrevLdObject returns IntrBaseVal, we should return the
|
|
|
|
// incoming edge.
|
|
|
|
if (IntrBaseVal == BackEdgeVal)
|
|
|
|
continue;
|
|
|
|
Idx = i;
|
|
|
|
break;
|
|
|
|
} else // Set the node to incoming edge.
|
|
|
|
Idx = i;
|
|
|
|
}
|
|
|
|
assert(Idx >= 0 && "Unexpected index to incoming argument in PHI");
|
|
|
|
return PN->getIncomingValue(Idx);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Bit-reverse Load Intrinsic: Figure out the underlying object the base
|
|
|
|
// pointer points to, for the bit-reverse load intrinsic. Setting this to
|
|
|
|
// memoperand might help alias analysis to figure out the dependencies.
|
|
|
|
static Value *getUnderLyingObjectForBrevLdIntr(Value *V) {
|
|
|
|
Value *IntrBaseVal = V;
|
|
|
|
Value *BaseVal;
|
|
|
|
// Loop over till we return the same Value, implies we either figure out
|
|
|
|
// the object or we hit a PHI
|
|
|
|
do {
|
|
|
|
BaseVal = V;
|
|
|
|
V = getBrevLdObject(V);
|
|
|
|
} while (BaseVal != V);
|
|
|
|
|
|
|
|
// Identify the object from PHINode.
|
|
|
|
if (const PHINode *PN = dyn_cast<PHINode>(V))
|
|
|
|
return returnEdge(PN, IntrBaseVal);
|
|
|
|
// For non PHI nodes, the object is the last value returned by getBrevLdObject
|
|
|
|
else
|
|
|
|
return V;
|
|
|
|
}
|
|
|
|
|
2017-12-12 02:57:54 +08:00
|
|
|
/// Given an intrinsic, checks if on the target the intrinsic will need to map
|
|
|
|
/// to a MemIntrinsicNode (touches memory). If this is the case, it returns
|
|
|
|
/// true and store the intrinsic information into the IntrinsicInfo that was
|
|
|
|
/// passed to the function.
|
|
|
|
bool HexagonTargetLowering::getTgtMemIntrinsic(IntrinsicInfo &Info,
|
|
|
|
const CallInst &I,
|
2017-12-15 06:34:10 +08:00
|
|
|
MachineFunction &MF,
|
2017-12-12 02:57:54 +08:00
|
|
|
unsigned Intrinsic) const {
|
|
|
|
switch (Intrinsic) {
|
2018-03-29 21:52:46 +08:00
|
|
|
case Intrinsic::hexagon_L2_loadrd_pbr:
|
|
|
|
case Intrinsic::hexagon_L2_loadri_pbr:
|
|
|
|
case Intrinsic::hexagon_L2_loadrh_pbr:
|
|
|
|
case Intrinsic::hexagon_L2_loadruh_pbr:
|
|
|
|
case Intrinsic::hexagon_L2_loadrb_pbr:
|
|
|
|
case Intrinsic::hexagon_L2_loadrub_pbr: {
|
|
|
|
Info.opc = ISD::INTRINSIC_W_CHAIN;
|
|
|
|
auto &DL = I.getCalledFunction()->getParent()->getDataLayout();
|
|
|
|
auto &Cont = I.getCalledFunction()->getParent()->getContext();
|
|
|
|
// The intrinsic function call is of the form { ElTy, i8* }
|
|
|
|
// @llvm.hexagon.L2.loadXX.pbr(i8*, i32). The pointer and memory access type
|
|
|
|
// should be derived from ElTy.
|
2019-01-11 00:07:20 +08:00
|
|
|
Type *ElTy = I.getCalledFunction()->getReturnType()->getStructElementType(0);
|
|
|
|
Info.memVT = MVT::getVT(ElTy);
|
2018-03-29 21:52:46 +08:00
|
|
|
llvm::Value *BasePtrVal = I.getOperand(0);
|
|
|
|
Info.ptrVal = getUnderLyingObjectForBrevLdIntr(BasePtrVal);
|
|
|
|
// The offset value comes through Modifier register. For now, assume the
|
|
|
|
// offset is 0.
|
|
|
|
Info.offset = 0;
|
2020-07-01 22:31:56 +08:00
|
|
|
Info.align = DL.getABITypeAlign(Info.memVT.getTypeForEVT(Cont));
|
2018-03-29 21:52:46 +08:00
|
|
|
Info.flags = MachineMemOperand::MOLoad;
|
|
|
|
return true;
|
|
|
|
}
|
2017-12-12 02:57:54 +08:00
|
|
|
case Intrinsic::hexagon_V6_vgathermw:
|
|
|
|
case Intrinsic::hexagon_V6_vgathermw_128B:
|
|
|
|
case Intrinsic::hexagon_V6_vgathermh:
|
|
|
|
case Intrinsic::hexagon_V6_vgathermh_128B:
|
|
|
|
case Intrinsic::hexagon_V6_vgathermhw:
|
|
|
|
case Intrinsic::hexagon_V6_vgathermhw_128B:
|
|
|
|
case Intrinsic::hexagon_V6_vgathermwq:
|
|
|
|
case Intrinsic::hexagon_V6_vgathermwq_128B:
|
|
|
|
case Intrinsic::hexagon_V6_vgathermhq:
|
|
|
|
case Intrinsic::hexagon_V6_vgathermhq_128B:
|
|
|
|
case Intrinsic::hexagon_V6_vgathermhwq:
|
|
|
|
case Intrinsic::hexagon_V6_vgathermhwq_128B: {
|
|
|
|
const Module &M = *I.getParent()->getParent()->getParent();
|
|
|
|
Info.opc = ISD::INTRINSIC_W_CHAIN;
|
|
|
|
Type *VecTy = I.getArgOperand(1)->getType();
|
|
|
|
Info.memVT = MVT::getVT(VecTy);
|
|
|
|
Info.ptrVal = I.getArgOperand(0);
|
|
|
|
Info.offset = 0;
|
[LLVM][Alignment] Introduce Alignment Type
Summary:
This is patch is part of a serie to introduce an Alignment type.
See this thread for context: http://lists.llvm.org/pipermail/llvm-dev/2019-July/133851.html
See this patch for the introduction of the type: https://reviews.llvm.org/D64790
Reviewers: courbet, jfb, jakehehrlich
Reviewed By: jfb
Subscribers: wuzish, jholewinski, arsenm, dschuff, nemanjai, jvesely, nhaehnle, javed.absar, sbc100, jgravelle-google, hiraditya, aheejin, kbarton, asb, rbar, johnrusso, simoncook, apazos, sabuasal, niosHD, jrtc27, MaskRay, zzheng, edward-jones, rogfer01, MartinMosbeck, brucehoult, the_o, dexonsmith, PkmX, jocewei, jsji, s.egerton, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D65514
llvm-svn: 367828
2019-08-05 19:02:05 +08:00
|
|
|
Info.align =
|
|
|
|
MaybeAlign(M.getDataLayout().getTypeAllocSizeInBits(VecTy) / 8);
|
2017-12-15 05:39:51 +08:00
|
|
|
Info.flags = MachineMemOperand::MOLoad |
|
|
|
|
MachineMemOperand::MOStore |
|
|
|
|
MachineMemOperand::MOVolatile;
|
2017-12-12 02:57:54 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
[Codegen] (X & (C l>>/<< Y)) ==/!= 0 --> ((X <</l>> Y) & C) ==/!= 0 fold
Summary:
This was originally reported in D62818.
https://rise4fun.com/Alive/oPH
InstCombine does the opposite fold, in hope that `C l>>/<< Y` expression
will be hoisted out of a loop if `Y` is invariant and `X` is not.
But as it is seen from the diffs here, if it didn't get hoisted,
the produced assembly is almost universally worse.
Much like with my recent "hoist add/sub by/from const" patches,
we should get almost universal win if we hoist constant,
there is almost always an "and/test by imm" instruction,
but "shift of imm" not so much, so we may avoid having to
materialize the immediate, and thus need one less register.
And since we now shift not by constant, but by something else,
the live-range of that something else may reduce.
Special care needs to be applied not to disturb x86 `BT` / hexagon `tstbit`
instruction pattern. And to not get into endless combine loop.
Reviewers: RKSimon, efriedma, t.p.northover, craig.topper, spatel, arsenm
Reviewed By: spatel
Subscribers: hiraditya, MaskRay, wuzish, xbolva00, nikic, nemanjai, jvesely, wdng, nhaehnle, javed.absar, tpr, kristof.beyls, jsji, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D62871
llvm-svn: 366955
2019-07-25 06:57:22 +08:00
|
|
|
bool HexagonTargetLowering::hasBitTest(SDValue X, SDValue Y) const {
|
|
|
|
return X.getValueType().isScalarInteger(); // 'tstbit'
|
|
|
|
}
|
|
|
|
|
2015-04-23 05:17:00 +08:00
|
|
|
bool HexagonTargetLowering::isTruncateFree(Type *Ty1, Type *Ty2) const {
|
2018-02-13 23:35:07 +08:00
|
|
|
return isTruncateFree(EVT::getEVT(Ty1), EVT::getEVT(Ty2));
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool HexagonTargetLowering::isTruncateFree(EVT VT1, EVT VT2) const {
|
2015-04-23 05:17:00 +08:00
|
|
|
if (!VT1.isSimple() || !VT2.isSimple())
|
2011-12-13 05:14:40 +08:00
|
|
|
return false;
|
2018-02-13 23:35:07 +08:00
|
|
|
return VT1.getSimpleVT() == MVT::i64 && VT2.getSimpleVT() == MVT::i32;
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
|
|
|
|
2019-10-29 08:38:44 +08:00
|
|
|
bool HexagonTargetLowering::isFMAFasterThanFMulAndFAdd(
|
|
|
|
const MachineFunction &MF, EVT VT) const {
|
2016-08-19 21:34:31 +08:00
|
|
|
return isOperationLegalOrCustom(ISD::FMA, VT);
|
|
|
|
}
|
|
|
|
|
2015-03-20 00:33:08 +08:00
|
|
|
// Should we expand the build vector with shuffles?
|
2016-09-14 05:16:07 +08:00
|
|
|
bool HexagonTargetLowering::shouldExpandBuildVectorWithShuffles(EVT VT,
|
|
|
|
unsigned DefinedValues) const {
|
2017-12-07 00:40:37 +08:00
|
|
|
return false;
|
2016-07-30 00:44:27 +08:00
|
|
|
}
|
|
|
|
|
2017-07-26 16:06:58 +08:00
|
|
|
bool HexagonTargetLowering::isShuffleMaskLegal(ArrayRef<int> Mask,
|
|
|
|
EVT VT) const {
|
2016-09-14 05:16:07 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2017-12-19 02:21:01 +08:00
|
|
|
TargetLoweringBase::LegalizeTypeAction
|
2018-11-06 07:26:13 +08:00
|
|
|
HexagonTargetLowering::getPreferredVectorAction(MVT VT) const {
|
2021-05-12 22:27:52 +08:00
|
|
|
unsigned VecLen = VT.getVectorMinNumElements();
|
2018-11-06 07:26:13 +08:00
|
|
|
MVT ElemTy = VT.getVectorElementType();
|
2019-09-20 23:19:20 +08:00
|
|
|
|
|
|
|
if (VecLen == 1 || VT.isScalableVector())
|
|
|
|
return TargetLoweringBase::TypeScalarizeVector;
|
2017-12-21 04:49:43 +08:00
|
|
|
|
2017-12-19 02:21:01 +08:00
|
|
|
if (Subtarget.useHVXOps()) {
|
2020-08-27 10:00:49 +08:00
|
|
|
unsigned Action = getPreferredHvxVectorAction(VT);
|
|
|
|
if (Action != ~0u)
|
|
|
|
return static_cast<TargetLoweringBase::LegalizeTypeAction>(Action);
|
2017-12-19 02:21:01 +08:00
|
|
|
}
|
2019-09-20 23:19:20 +08:00
|
|
|
|
|
|
|
// Always widen (remaining) vectors of i1.
|
|
|
|
if (ElemTy == MVT::i1)
|
|
|
|
return TargetLoweringBase::TypeWidenVector;
|
|
|
|
|
2017-12-21 04:49:43 +08:00
|
|
|
return TargetLoweringBase::TypeSplitVector;
|
2017-12-19 02:21:01 +08:00
|
|
|
}
|
|
|
|
|
2018-02-15 04:46:06 +08:00
|
|
|
std::pair<SDValue, int>
|
|
|
|
HexagonTargetLowering::getBaseAndOffset(SDValue Addr) const {
|
|
|
|
if (Addr.getOpcode() == ISD::ADD) {
|
|
|
|
SDValue Op1 = Addr.getOperand(1);
|
|
|
|
if (auto *CN = dyn_cast<const ConstantSDNode>(Op1.getNode()))
|
|
|
|
return { Addr.getOperand(0), CN->getSExtValue() };
|
|
|
|
}
|
|
|
|
return { Addr, 0 };
|
|
|
|
}
|
|
|
|
|
2016-07-30 00:44:27 +08:00
|
|
|
// Lower a vector shuffle (V1, V2, V3). V1 and V2 are the two vectors
|
|
|
|
// to select data from, V3 is the permutation.
|
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerVECTOR_SHUFFLE(SDValue Op, SelectionDAG &DAG)
|
|
|
|
const {
|
2018-01-16 02:33:33 +08:00
|
|
|
const auto *SVN = cast<ShuffleVectorSDNode>(Op);
|
|
|
|
ArrayRef<int> AM = SVN->getMask();
|
|
|
|
assert(AM.size() <= 8 && "Unexpected shuffle mask");
|
|
|
|
unsigned VecLen = AM.size();
|
|
|
|
|
|
|
|
MVT VecTy = ty(Op);
|
2018-02-07 04:22:20 +08:00
|
|
|
assert(!Subtarget.isHVXVectorType(VecTy, true) &&
|
|
|
|
"HVX shuffles should be legal");
|
2018-01-16 02:33:33 +08:00
|
|
|
assert(VecTy.getSizeInBits() <= 64 && "Unexpected vector length");
|
|
|
|
|
|
|
|
SDValue Op0 = Op.getOperand(0);
|
|
|
|
SDValue Op1 = Op.getOperand(1);
|
2018-02-09 23:30:02 +08:00
|
|
|
const SDLoc &dl(Op);
|
|
|
|
|
2018-01-16 02:33:33 +08:00
|
|
|
// If the inputs are not the same as the output, bail. This is not an
|
|
|
|
// error situation, but complicates the handling and the default expansion
|
|
|
|
// (into BUILD_VECTOR) should be adequate.
|
|
|
|
if (ty(Op0) != VecTy || ty(Op1) != VecTy)
|
|
|
|
return SDValue();
|
2015-03-20 00:33:08 +08:00
|
|
|
|
2018-01-16 02:33:33 +08:00
|
|
|
// Normalize the mask so that the first non-negative index comes from
|
|
|
|
// the first operand.
|
|
|
|
SmallVector<int,8> Mask(AM.begin(), AM.end());
|
|
|
|
unsigned F = llvm::find_if(AM, [](int M) { return M >= 0; }) - AM.data();
|
|
|
|
if (F == AM.size())
|
|
|
|
return DAG.getUNDEF(VecTy);
|
|
|
|
if (AM[F] >= int(VecLen)) {
|
|
|
|
ShuffleVectorSDNode::commuteMask(Mask);
|
|
|
|
std::swap(Op0, Op1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Express the shuffle mask in terms of bytes.
|
|
|
|
SmallVector<int,8> ByteMask;
|
|
|
|
unsigned ElemBytes = VecTy.getVectorElementType().getSizeInBits() / 8;
|
|
|
|
for (unsigned i = 0, e = Mask.size(); i != e; ++i) {
|
|
|
|
int M = Mask[i];
|
|
|
|
if (M < 0) {
|
|
|
|
for (unsigned j = 0; j != ElemBytes; ++j)
|
|
|
|
ByteMask.push_back(-1);
|
|
|
|
} else {
|
|
|
|
for (unsigned j = 0; j != ElemBytes; ++j)
|
|
|
|
ByteMask.push_back(M*ElemBytes + j);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
assert(ByteMask.size() <= 8);
|
|
|
|
|
|
|
|
// All non-undef (non-negative) indexes are well within [0..127], so they
|
|
|
|
// fit in a single byte. Build two 64-bit words:
|
|
|
|
// - MaskIdx where each byte is the corresponding index (for non-negative
|
|
|
|
// indexes), and 0xFF for negative indexes, and
|
|
|
|
// - MaskUnd that has 0xFF for each negative index.
|
|
|
|
uint64_t MaskIdx = 0;
|
|
|
|
uint64_t MaskUnd = 0;
|
|
|
|
for (unsigned i = 0, e = ByteMask.size(); i != e; ++i) {
|
|
|
|
unsigned S = 8*i;
|
|
|
|
uint64_t M = ByteMask[i] & 0xFF;
|
|
|
|
if (M == 0xFF)
|
|
|
|
MaskUnd |= M << S;
|
|
|
|
MaskIdx |= M << S;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ByteMask.size() == 4) {
|
|
|
|
// Identity.
|
|
|
|
if (MaskIdx == (0x03020100 | MaskUnd))
|
|
|
|
return Op0;
|
|
|
|
// Byte swap.
|
|
|
|
if (MaskIdx == (0x00010203 | MaskUnd)) {
|
|
|
|
SDValue T0 = DAG.getBitcast(MVT::i32, Op0);
|
|
|
|
SDValue T1 = DAG.getNode(ISD::BSWAP, dl, MVT::i32, T0);
|
|
|
|
return DAG.getBitcast(VecTy, T1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Byte packs.
|
|
|
|
SDValue Concat10 = DAG.getNode(HexagonISD::COMBINE, dl,
|
|
|
|
typeJoin({ty(Op1), ty(Op0)}), {Op1, Op0});
|
|
|
|
if (MaskIdx == (0x06040200 | MaskUnd))
|
2018-02-01 05:17:03 +08:00
|
|
|
return getInstr(Hexagon::S2_vtrunehb, dl, VecTy, {Concat10}, DAG);
|
2018-01-16 02:33:33 +08:00
|
|
|
if (MaskIdx == (0x07050301 | MaskUnd))
|
2018-02-01 05:17:03 +08:00
|
|
|
return getInstr(Hexagon::S2_vtrunohb, dl, VecTy, {Concat10}, DAG);
|
2018-01-16 02:33:33 +08:00
|
|
|
|
|
|
|
SDValue Concat01 = DAG.getNode(HexagonISD::COMBINE, dl,
|
|
|
|
typeJoin({ty(Op0), ty(Op1)}), {Op0, Op1});
|
|
|
|
if (MaskIdx == (0x02000604 | MaskUnd))
|
2018-02-01 05:17:03 +08:00
|
|
|
return getInstr(Hexagon::S2_vtrunehb, dl, VecTy, {Concat01}, DAG);
|
2018-01-16 02:33:33 +08:00
|
|
|
if (MaskIdx == (0x03010705 | MaskUnd))
|
2018-02-01 05:17:03 +08:00
|
|
|
return getInstr(Hexagon::S2_vtrunohb, dl, VecTy, {Concat01}, DAG);
|
2018-01-16 02:33:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ByteMask.size() == 8) {
|
|
|
|
// Identity.
|
|
|
|
if (MaskIdx == (0x0706050403020100ull | MaskUnd))
|
|
|
|
return Op0;
|
|
|
|
// Byte swap.
|
|
|
|
if (MaskIdx == (0x0001020304050607ull | MaskUnd)) {
|
|
|
|
SDValue T0 = DAG.getBitcast(MVT::i64, Op0);
|
|
|
|
SDValue T1 = DAG.getNode(ISD::BSWAP, dl, MVT::i64, T0);
|
|
|
|
return DAG.getBitcast(VecTy, T1);
|
2015-03-20 00:33:08 +08:00
|
|
|
}
|
2018-01-16 02:33:33 +08:00
|
|
|
|
|
|
|
// Halfword picks.
|
|
|
|
if (MaskIdx == (0x0d0c050409080100ull | MaskUnd))
|
2018-02-01 05:17:03 +08:00
|
|
|
return getInstr(Hexagon::S2_shuffeh, dl, VecTy, {Op1, Op0}, DAG);
|
2018-01-16 02:33:33 +08:00
|
|
|
if (MaskIdx == (0x0f0e07060b0a0302ull | MaskUnd))
|
2018-02-01 05:17:03 +08:00
|
|
|
return getInstr(Hexagon::S2_shuffoh, dl, VecTy, {Op1, Op0}, DAG);
|
2018-01-16 02:33:33 +08:00
|
|
|
if (MaskIdx == (0x0d0c090805040100ull | MaskUnd))
|
2018-02-01 05:17:03 +08:00
|
|
|
return getInstr(Hexagon::S2_vtrunewh, dl, VecTy, {Op1, Op0}, DAG);
|
2018-01-16 02:33:33 +08:00
|
|
|
if (MaskIdx == (0x0f0e0b0a07060302ull | MaskUnd))
|
2018-02-01 05:17:03 +08:00
|
|
|
return getInstr(Hexagon::S2_vtrunowh, dl, VecTy, {Op1, Op0}, DAG);
|
2018-01-16 02:33:33 +08:00
|
|
|
if (MaskIdx == (0x0706030205040100ull | MaskUnd)) {
|
|
|
|
VectorPair P = opSplit(Op0, dl, DAG);
|
2018-02-01 05:17:03 +08:00
|
|
|
return getInstr(Hexagon::S2_packhl, dl, VecTy, {P.second, P.first}, DAG);
|
2018-01-16 02:33:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Byte packs.
|
|
|
|
if (MaskIdx == (0x0e060c040a020800ull | MaskUnd))
|
2018-02-01 05:17:03 +08:00
|
|
|
return getInstr(Hexagon::S2_shuffeb, dl, VecTy, {Op1, Op0}, DAG);
|
2018-01-16 02:33:33 +08:00
|
|
|
if (MaskIdx == (0x0f070d050b030901ull | MaskUnd))
|
2018-02-01 05:17:03 +08:00
|
|
|
return getInstr(Hexagon::S2_shuffob, dl, VecTy, {Op1, Op0}, DAG);
|
2015-03-20 00:33:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return SDValue();
|
|
|
|
}
|
|
|
|
|
2018-02-07 04:22:20 +08:00
|
|
|
// Create a Hexagon-specific node for shifting a vector by an integer.
|
2016-07-30 00:44:27 +08:00
|
|
|
SDValue
|
2018-02-07 04:22:20 +08:00
|
|
|
HexagonTargetLowering::getVectorShiftByInt(SDValue Op, SelectionDAG &DAG)
|
|
|
|
const {
|
2020-10-10 09:17:50 +08:00
|
|
|
unsigned NewOpc;
|
|
|
|
switch (Op.getOpcode()) {
|
|
|
|
case ISD::SHL:
|
|
|
|
NewOpc = HexagonISD::VASL;
|
|
|
|
break;
|
|
|
|
case ISD::SRA:
|
|
|
|
NewOpc = HexagonISD::VASR;
|
|
|
|
break;
|
|
|
|
case ISD::SRL:
|
|
|
|
NewOpc = HexagonISD::VLSR;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
llvm_unreachable("Unexpected shift opcode");
|
2015-03-20 00:33:08 +08:00
|
|
|
}
|
|
|
|
|
2020-10-10 09:17:50 +08:00
|
|
|
SDValue Op0 = Op.getOperand(0);
|
|
|
|
SDValue Op1 = Op.getOperand(1);
|
|
|
|
const SDLoc &dl(Op);
|
|
|
|
|
|
|
|
switch (Op1.getOpcode()) {
|
|
|
|
case ISD::BUILD_VECTOR:
|
|
|
|
if (SDValue S = cast<BuildVectorSDNode>(Op1)->getSplatValue())
|
|
|
|
return DAG.getNode(NewOpc, dl, ty(Op), Op0, S);
|
|
|
|
break;
|
|
|
|
case ISD::SPLAT_VECTOR:
|
|
|
|
return DAG.getNode(NewOpc, dl, ty(Op), Op0, Op1.getOperand(0));
|
|
|
|
}
|
2018-02-01 04:49:24 +08:00
|
|
|
return SDValue();
|
2015-03-20 00:33:08 +08:00
|
|
|
}
|
|
|
|
|
2018-02-07 04:22:20 +08:00
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerVECTOR_SHIFT(SDValue Op, SelectionDAG &DAG) const {
|
|
|
|
return getVectorShiftByInt(Op, DAG);
|
|
|
|
}
|
|
|
|
|
2018-06-12 20:49:36 +08:00
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerROTL(SDValue Op, SelectionDAG &DAG) const {
|
|
|
|
if (isa<ConstantSDNode>(Op.getOperand(1).getNode()))
|
|
|
|
return Op;
|
|
|
|
return SDValue();
|
|
|
|
}
|
|
|
|
|
2018-01-24 01:53:59 +08:00
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerBITCAST(SDValue Op, SelectionDAG &DAG) const {
|
|
|
|
MVT ResTy = ty(Op);
|
|
|
|
SDValue InpV = Op.getOperand(0);
|
|
|
|
MVT InpTy = ty(InpV);
|
|
|
|
assert(ResTy.getSizeInBits() == InpTy.getSizeInBits());
|
|
|
|
const SDLoc &dl(Op);
|
|
|
|
|
|
|
|
// Handle conversion from i8 to v8i1.
|
2020-01-10 03:23:28 +08:00
|
|
|
if (InpTy == MVT::i8) {
|
|
|
|
if (ResTy == MVT::v8i1) {
|
|
|
|
SDValue Sc = DAG.getBitcast(tyScalar(InpTy), InpV);
|
|
|
|
SDValue Ext = DAG.getZExtOrTrunc(Sc, dl, MVT::i32);
|
|
|
|
return getInstr(Hexagon::C2_tfrrp, dl, ResTy, Ext, DAG);
|
|
|
|
}
|
|
|
|
return SDValue();
|
2018-01-24 01:53:59 +08:00
|
|
|
}
|
|
|
|
|
2020-01-10 03:23:28 +08:00
|
|
|
return Op;
|
2018-01-24 01:53:59 +08:00
|
|
|
}
|
|
|
|
|
2017-12-21 04:49:43 +08:00
|
|
|
bool
|
|
|
|
HexagonTargetLowering::getBuildVectorConstInts(ArrayRef<SDValue> Values,
|
|
|
|
MVT VecTy, SelectionDAG &DAG,
|
|
|
|
MutableArrayRef<ConstantInt*> Consts) const {
|
|
|
|
MVT ElemTy = VecTy.getVectorElementType();
|
|
|
|
unsigned ElemWidth = ElemTy.getSizeInBits();
|
|
|
|
IntegerType *IntTy = IntegerType::get(*DAG.getContext(), ElemWidth);
|
|
|
|
bool AllConst = true;
|
|
|
|
|
|
|
|
for (unsigned i = 0, e = Values.size(); i != e; ++i) {
|
|
|
|
SDValue V = Values[i];
|
|
|
|
if (V.isUndef()) {
|
|
|
|
Consts[i] = ConstantInt::get(IntTy, 0);
|
|
|
|
continue;
|
|
|
|
}
|
2018-01-12 02:03:23 +08:00
|
|
|
// Make sure to always cast to IntTy.
|
2017-12-21 04:49:43 +08:00
|
|
|
if (auto *CN = dyn_cast<ConstantSDNode>(V.getNode())) {
|
|
|
|
const ConstantInt *CI = CN->getConstantIntValue();
|
2018-01-12 02:03:23 +08:00
|
|
|
Consts[i] = ConstantInt::get(IntTy, CI->getValue().getSExtValue());
|
2017-12-21 04:49:43 +08:00
|
|
|
} else if (auto *CN = dyn_cast<ConstantFPSDNode>(V.getNode())) {
|
|
|
|
const ConstantFP *CF = CN->getConstantFPValue();
|
|
|
|
APInt A = CF->getValueAPF().bitcastToAPInt();
|
|
|
|
Consts[i] = ConstantInt::get(IntTy, A.getZExtValue());
|
|
|
|
} else {
|
|
|
|
AllConst = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return AllConst;
|
|
|
|
}
|
|
|
|
|
2015-03-20 00:33:08 +08:00
|
|
|
SDValue
|
2017-11-23 04:56:23 +08:00
|
|
|
HexagonTargetLowering::buildVector32(ArrayRef<SDValue> Elem, const SDLoc &dl,
|
|
|
|
MVT VecTy, SelectionDAG &DAG) const {
|
|
|
|
MVT ElemTy = VecTy.getVectorElementType();
|
|
|
|
assert(VecTy.getVectorNumElements() == Elem.size());
|
|
|
|
|
2017-12-21 04:49:43 +08:00
|
|
|
SmallVector<ConstantInt*,4> Consts(Elem.size());
|
|
|
|
bool AllConst = getBuildVectorConstInts(Elem, VecTy, DAG, Consts);
|
2017-11-23 04:56:23 +08:00
|
|
|
|
|
|
|
unsigned First, Num = Elem.size();
|
2020-10-10 09:17:50 +08:00
|
|
|
for (First = 0; First != Num; ++First) {
|
2017-12-07 00:40:37 +08:00
|
|
|
if (!isUndef(Elem[First]))
|
2017-11-23 04:56:23 +08:00
|
|
|
break;
|
2020-10-10 09:17:50 +08:00
|
|
|
}
|
2017-11-23 04:56:23 +08:00
|
|
|
if (First == Num)
|
|
|
|
return DAG.getUNDEF(VecTy);
|
|
|
|
|
2017-12-21 04:49:43 +08:00
|
|
|
if (AllConst &&
|
|
|
|
llvm::all_of(Consts, [](ConstantInt *CI) { return CI->isZero(); }))
|
|
|
|
return getZero(dl, VecTy, DAG);
|
|
|
|
|
2017-11-23 04:56:23 +08:00
|
|
|
if (ElemTy == MVT::i16) {
|
|
|
|
assert(Elem.size() == 2);
|
|
|
|
if (AllConst) {
|
|
|
|
uint32_t V = (Consts[0]->getZExtValue() & 0xFFFF) |
|
|
|
|
Consts[1]->getZExtValue() << 16;
|
|
|
|
return DAG.getBitcast(MVT::v2i16, DAG.getConstant(V, dl, MVT::i32));
|
2017-07-14 02:17:58 +08:00
|
|
|
}
|
2018-02-01 05:17:03 +08:00
|
|
|
SDValue N = getInstr(Hexagon::A2_combine_ll, dl, MVT::i32,
|
|
|
|
{Elem[1], Elem[0]}, DAG);
|
2017-12-07 00:40:37 +08:00
|
|
|
return DAG.getBitcast(MVT::v2i16, N);
|
2015-03-20 00:33:08 +08:00
|
|
|
}
|
|
|
|
|
2017-12-21 04:49:43 +08:00
|
|
|
if (ElemTy == MVT::i8) {
|
|
|
|
// First try generating a constant.
|
|
|
|
if (AllConst) {
|
|
|
|
int32_t V = (Consts[0]->getZExtValue() & 0xFF) |
|
|
|
|
(Consts[1]->getZExtValue() & 0xFF) << 8 |
|
|
|
|
(Consts[1]->getZExtValue() & 0xFF) << 16 |
|
|
|
|
Consts[2]->getZExtValue() << 24;
|
|
|
|
return DAG.getBitcast(MVT::v4i8, DAG.getConstant(V, dl, MVT::i32));
|
|
|
|
}
|
2015-03-20 00:33:08 +08:00
|
|
|
|
2017-12-21 04:49:43 +08:00
|
|
|
// Then try splat.
|
|
|
|
bool IsSplat = true;
|
2020-10-10 09:17:50 +08:00
|
|
|
for (unsigned i = First+1; i != Num; ++i) {
|
2017-12-21 04:49:43 +08:00
|
|
|
if (Elem[i] == Elem[First] || isUndef(Elem[i]))
|
|
|
|
continue;
|
|
|
|
IsSplat = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (IsSplat) {
|
2020-10-10 09:17:50 +08:00
|
|
|
// Legalize the operand of SPLAT_VECTOR.
|
2017-12-21 04:49:43 +08:00
|
|
|
SDValue Ext = DAG.getZExtOrTrunc(Elem[First], dl, MVT::i32);
|
2020-10-10 09:17:50 +08:00
|
|
|
return DAG.getNode(ISD::SPLAT_VECTOR, dl, VecTy, Ext);
|
2017-12-21 04:49:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Generate
|
|
|
|
// (zxtb(Elem[0]) | (zxtb(Elem[1]) << 8)) |
|
|
|
|
// (zxtb(Elem[2]) | (zxtb(Elem[3]) << 8)) << 16
|
|
|
|
assert(Elem.size() == 4);
|
|
|
|
SDValue Vs[4];
|
|
|
|
for (unsigned i = 0; i != 4; ++i) {
|
|
|
|
Vs[i] = DAG.getZExtOrTrunc(Elem[i], dl, MVT::i32);
|
|
|
|
Vs[i] = DAG.getZeroExtendInReg(Vs[i], dl, MVT::i8);
|
|
|
|
}
|
|
|
|
SDValue S8 = DAG.getConstant(8, dl, MVT::i32);
|
|
|
|
SDValue T0 = DAG.getNode(ISD::SHL, dl, MVT::i32, {Vs[1], S8});
|
|
|
|
SDValue T1 = DAG.getNode(ISD::SHL, dl, MVT::i32, {Vs[3], S8});
|
|
|
|
SDValue B0 = DAG.getNode(ISD::OR, dl, MVT::i32, {Vs[0], T0});
|
|
|
|
SDValue B1 = DAG.getNode(ISD::OR, dl, MVT::i32, {Vs[2], T1});
|
2017-11-23 04:56:23 +08:00
|
|
|
|
2018-02-01 05:17:03 +08:00
|
|
|
SDValue R = getInstr(Hexagon::A2_combine_ll, dl, MVT::i32, {B1, B0}, DAG);
|
2017-12-21 04:49:43 +08:00
|
|
|
return DAG.getBitcast(MVT::v4i8, R);
|
2017-12-21 04:33:49 +08:00
|
|
|
}
|
|
|
|
|
2017-12-21 04:49:43 +08:00
|
|
|
#ifndef NDEBUG
|
|
|
|
dbgs() << "VecTy: " << EVT(VecTy).getEVTString() << '\n';
|
|
|
|
#endif
|
|
|
|
llvm_unreachable("Unexpected vector element type");
|
2017-11-23 04:56:23 +08:00
|
|
|
}
|
2015-03-20 00:33:08 +08:00
|
|
|
|
2017-11-23 04:56:23 +08:00
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::buildVector64(ArrayRef<SDValue> Elem, const SDLoc &dl,
|
|
|
|
MVT VecTy, SelectionDAG &DAG) const {
|
|
|
|
MVT ElemTy = VecTy.getVectorElementType();
|
|
|
|
assert(VecTy.getVectorNumElements() == Elem.size());
|
|
|
|
|
2017-12-21 04:49:43 +08:00
|
|
|
SmallVector<ConstantInt*,8> Consts(Elem.size());
|
|
|
|
bool AllConst = getBuildVectorConstInts(Elem, VecTy, DAG, Consts);
|
2017-11-23 04:56:23 +08:00
|
|
|
|
|
|
|
unsigned First, Num = Elem.size();
|
2020-10-10 09:17:50 +08:00
|
|
|
for (First = 0; First != Num; ++First) {
|
2017-12-07 00:40:37 +08:00
|
|
|
if (!isUndef(Elem[First]))
|
2017-11-23 04:56:23 +08:00
|
|
|
break;
|
2020-10-10 09:17:50 +08:00
|
|
|
}
|
2017-11-23 04:56:23 +08:00
|
|
|
if (First == Num)
|
|
|
|
return DAG.getUNDEF(VecTy);
|
|
|
|
|
2017-12-21 04:49:43 +08:00
|
|
|
if (AllConst &&
|
|
|
|
llvm::all_of(Consts, [](ConstantInt *CI) { return CI->isZero(); }))
|
|
|
|
return getZero(dl, VecTy, DAG);
|
|
|
|
|
2017-11-23 04:56:23 +08:00
|
|
|
// First try splat if possible.
|
|
|
|
if (ElemTy == MVT::i16) {
|
|
|
|
bool IsSplat = true;
|
2020-10-10 09:17:50 +08:00
|
|
|
for (unsigned i = First+1; i != Num; ++i) {
|
2017-12-07 00:40:37 +08:00
|
|
|
if (Elem[i] == Elem[First] || isUndef(Elem[i]))
|
2017-11-23 04:56:23 +08:00
|
|
|
continue;
|
|
|
|
IsSplat = false;
|
|
|
|
break;
|
2015-03-20 00:33:08 +08:00
|
|
|
}
|
2017-12-21 04:33:49 +08:00
|
|
|
if (IsSplat) {
|
2020-10-10 09:17:50 +08:00
|
|
|
// Legalize the operand of SPLAT_VECTOR
|
2017-12-21 04:33:49 +08:00
|
|
|
SDValue Ext = DAG.getZExtOrTrunc(Elem[First], dl, MVT::i32);
|
2020-10-10 09:17:50 +08:00
|
|
|
return DAG.getNode(ISD::SPLAT_VECTOR, dl, VecTy, Ext);
|
2017-12-21 04:33:49 +08:00
|
|
|
}
|
2017-11-23 04:56:23 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Then try constant.
|
|
|
|
if (AllConst) {
|
|
|
|
uint64_t Val = 0;
|
|
|
|
unsigned W = ElemTy.getSizeInBits();
|
|
|
|
uint64_t Mask = (ElemTy == MVT::i8) ? 0xFFull
|
|
|
|
: (ElemTy == MVT::i16) ? 0xFFFFull : 0xFFFFFFFFull;
|
|
|
|
for (unsigned i = 0; i != Num; ++i)
|
2018-01-12 02:30:41 +08:00
|
|
|
Val = (Val << W) | (Consts[Num-1-i]->getZExtValue() & Mask);
|
2017-11-23 04:56:23 +08:00
|
|
|
SDValue V0 = DAG.getConstant(Val, dl, MVT::i64);
|
|
|
|
return DAG.getBitcast(VecTy, V0);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Build two 32-bit vectors and concatenate.
|
|
|
|
MVT HalfTy = MVT::getVectorVT(ElemTy, Num/2);
|
|
|
|
SDValue L = (ElemTy == MVT::i32)
|
|
|
|
? Elem[0]
|
2017-12-21 04:49:43 +08:00
|
|
|
: buildVector32(Elem.take_front(Num/2), dl, HalfTy, DAG);
|
2017-11-23 04:56:23 +08:00
|
|
|
SDValue H = (ElemTy == MVT::i32)
|
|
|
|
? Elem[1]
|
2017-12-21 04:49:43 +08:00
|
|
|
: buildVector32(Elem.drop_front(Num/2), dl, HalfTy, DAG);
|
2017-12-07 00:40:37 +08:00
|
|
|
return DAG.getNode(HexagonISD::COMBINE, dl, VecTy, {H, L});
|
2017-11-23 04:56:23 +08:00
|
|
|
}
|
|
|
|
|
2017-11-30 03:58:10 +08:00
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::extractVector(SDValue VecV, SDValue IdxV,
|
|
|
|
const SDLoc &dl, MVT ValTy, MVT ResTy,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
MVT VecTy = ty(VecV);
|
|
|
|
assert(!ValTy.isVector() ||
|
|
|
|
VecTy.getVectorElementType() == ValTy.getVectorElementType());
|
|
|
|
unsigned VecWidth = VecTy.getSizeInBits();
|
|
|
|
unsigned ValWidth = ValTy.getSizeInBits();
|
|
|
|
unsigned ElemWidth = VecTy.getVectorElementType().getSizeInBits();
|
|
|
|
assert((VecWidth % ElemWidth) == 0);
|
2018-01-24 01:53:59 +08:00
|
|
|
auto *IdxN = dyn_cast<ConstantSDNode>(IdxV);
|
|
|
|
|
|
|
|
// Special case for v{8,4,2}i1 (the only boolean vectors legal in Hexagon
|
|
|
|
// without any coprocessors).
|
|
|
|
if (ElemWidth == 1) {
|
|
|
|
assert(VecWidth == VecTy.getVectorNumElements() && "Sanity failure");
|
|
|
|
assert(VecWidth == 8 || VecWidth == 4 || VecWidth == 2);
|
|
|
|
// Check if this is an extract of the lowest bit.
|
|
|
|
if (IdxN) {
|
|
|
|
// Extracting the lowest bit is a no-op, but it changes the type,
|
|
|
|
// so it must be kept as an operation to avoid errors related to
|
|
|
|
// type mismatches.
|
|
|
|
if (IdxN->isNullValue() && ValTy.getSizeInBits() == 1)
|
|
|
|
return DAG.getNode(HexagonISD::TYPECAST, dl, MVT::i1, VecV);
|
|
|
|
}
|
|
|
|
|
|
|
|
// If the value extracted is a single bit, use tstbit.
|
|
|
|
if (ValWidth == 1) {
|
2018-02-01 05:17:03 +08:00
|
|
|
SDValue A0 = getInstr(Hexagon::C2_tfrpr, dl, MVT::i32, {VecV}, DAG);
|
2018-07-26 00:20:59 +08:00
|
|
|
SDValue M0 = DAG.getConstant(8 / VecWidth, dl, MVT::i32);
|
|
|
|
SDValue I0 = DAG.getNode(ISD::MUL, dl, MVT::i32, IdxV, M0);
|
|
|
|
return DAG.getNode(HexagonISD::TSTBIT, dl, MVT::i1, A0, I0);
|
2018-01-24 01:53:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Each bool vector (v2i1, v4i1, v8i1) always occupies 8 bits in
|
|
|
|
// a predicate register. The elements of the vector are repeated
|
|
|
|
// in the register (if necessary) so that the total number is 8.
|
|
|
|
// The extracted subvector will need to be expanded in such a way.
|
|
|
|
unsigned Scale = VecWidth / ValWidth;
|
|
|
|
|
|
|
|
// Generate (p2d VecV) >> 8*Idx to move the interesting bytes to
|
|
|
|
// position 0.
|
|
|
|
assert(ty(IdxV) == MVT::i32);
|
2018-10-02 23:05:43 +08:00
|
|
|
unsigned VecRep = 8 / VecWidth;
|
2018-01-24 01:53:59 +08:00
|
|
|
SDValue S0 = DAG.getNode(ISD::MUL, dl, MVT::i32, IdxV,
|
2018-10-02 23:05:43 +08:00
|
|
|
DAG.getConstant(8*VecRep, dl, MVT::i32));
|
2018-01-24 01:53:59 +08:00
|
|
|
SDValue T0 = DAG.getNode(HexagonISD::P2D, dl, MVT::i64, VecV);
|
|
|
|
SDValue T1 = DAG.getNode(ISD::SRL, dl, MVT::i64, T0, S0);
|
|
|
|
while (Scale > 1) {
|
|
|
|
// The longest possible subvector is at most 32 bits, so it is always
|
|
|
|
// contained in the low subregister.
|
|
|
|
T1 = DAG.getTargetExtractSubreg(Hexagon::isub_lo, dl, MVT::i32, T1);
|
|
|
|
T1 = expandPredicate(T1, dl, DAG);
|
|
|
|
Scale /= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
return DAG.getNode(HexagonISD::D2P, dl, ResTy, T1);
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(VecWidth == 32 || VecWidth == 64);
|
2017-11-30 03:58:10 +08:00
|
|
|
|
|
|
|
// Cast everything to scalar integer types.
|
|
|
|
MVT ScalarTy = tyScalar(VecTy);
|
|
|
|
VecV = DAG.getBitcast(ScalarTy, VecV);
|
|
|
|
|
|
|
|
SDValue WidthV = DAG.getConstant(ValWidth, dl, MVT::i32);
|
|
|
|
SDValue ExtV;
|
|
|
|
|
2018-01-24 01:53:59 +08:00
|
|
|
if (IdxN) {
|
|
|
|
unsigned Off = IdxN->getZExtValue() * ElemWidth;
|
2017-11-30 03:58:10 +08:00
|
|
|
if (VecWidth == 64 && ValWidth == 32) {
|
|
|
|
assert(Off == 0 || Off == 32);
|
|
|
|
unsigned SubIdx = Off == 0 ? Hexagon::isub_lo : Hexagon::isub_hi;
|
|
|
|
ExtV = DAG.getTargetExtractSubreg(SubIdx, dl, MVT::i32, VecV);
|
|
|
|
} else if (Off == 0 && (ValWidth % 8) == 0) {
|
|
|
|
ExtV = DAG.getZeroExtendInReg(VecV, dl, tyScalar(ValTy));
|
|
|
|
} else {
|
|
|
|
SDValue OffV = DAG.getConstant(Off, dl, MVT::i32);
|
|
|
|
// The return type of EXTRACTU must be the same as the type of the
|
|
|
|
// input vector.
|
|
|
|
ExtV = DAG.getNode(HexagonISD::EXTRACTU, dl, ScalarTy,
|
|
|
|
{VecV, WidthV, OffV});
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (ty(IdxV) != MVT::i32)
|
|
|
|
IdxV = DAG.getZExtOrTrunc(IdxV, dl, MVT::i32);
|
|
|
|
SDValue OffV = DAG.getNode(ISD::MUL, dl, MVT::i32, IdxV,
|
|
|
|
DAG.getConstant(ElemWidth, dl, MVT::i32));
|
2018-01-04 21:56:04 +08:00
|
|
|
ExtV = DAG.getNode(HexagonISD::EXTRACTU, dl, ScalarTy,
|
|
|
|
{VecV, WidthV, OffV});
|
2017-11-30 03:58:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// Cast ExtV to the requested result type.
|
|
|
|
ExtV = DAG.getZExtOrTrunc(ExtV, dl, tyScalar(ResTy));
|
|
|
|
ExtV = DAG.getBitcast(ResTy, ExtV);
|
|
|
|
return ExtV;
|
|
|
|
}
|
|
|
|
|
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::insertVector(SDValue VecV, SDValue ValV, SDValue IdxV,
|
|
|
|
const SDLoc &dl, MVT ValTy,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
MVT VecTy = ty(VecV);
|
2018-01-24 01:53:59 +08:00
|
|
|
if (VecTy.getVectorElementType() == MVT::i1) {
|
|
|
|
MVT ValTy = ty(ValV);
|
|
|
|
assert(ValTy.getVectorElementType() == MVT::i1);
|
|
|
|
SDValue ValR = DAG.getNode(HexagonISD::P2D, dl, MVT::i64, ValV);
|
|
|
|
unsigned VecLen = VecTy.getVectorNumElements();
|
|
|
|
unsigned Scale = VecLen / ValTy.getVectorNumElements();
|
|
|
|
assert(Scale > 1);
|
|
|
|
|
|
|
|
for (unsigned R = Scale; R > 1; R /= 2) {
|
|
|
|
ValR = contractPredicate(ValR, dl, DAG);
|
|
|
|
ValR = DAG.getNode(HexagonISD::COMBINE, dl, MVT::i64,
|
|
|
|
DAG.getUNDEF(MVT::i32), ValR);
|
|
|
|
}
|
|
|
|
// The longest possible subvector is at most 32 bits, so it is always
|
|
|
|
// contained in the low subregister.
|
|
|
|
ValR = DAG.getTargetExtractSubreg(Hexagon::isub_lo, dl, MVT::i32, ValR);
|
|
|
|
|
|
|
|
unsigned ValBytes = 64 / Scale;
|
|
|
|
SDValue Width = DAG.getConstant(ValBytes*8, dl, MVT::i32);
|
|
|
|
SDValue Idx = DAG.getNode(ISD::MUL, dl, MVT::i32, IdxV,
|
|
|
|
DAG.getConstant(8, dl, MVT::i32));
|
|
|
|
SDValue VecR = DAG.getNode(HexagonISD::P2D, dl, MVT::i64, VecV);
|
|
|
|
SDValue Ins = DAG.getNode(HexagonISD::INSERT, dl, MVT::i32,
|
|
|
|
{VecR, ValR, Width, Idx});
|
|
|
|
return DAG.getNode(HexagonISD::D2P, dl, VecTy, Ins);
|
|
|
|
}
|
|
|
|
|
2017-11-30 03:58:10 +08:00
|
|
|
unsigned VecWidth = VecTy.getSizeInBits();
|
|
|
|
unsigned ValWidth = ValTy.getSizeInBits();
|
|
|
|
assert(VecWidth == 32 || VecWidth == 64);
|
|
|
|
assert((VecWidth % ValWidth) == 0);
|
|
|
|
|
|
|
|
// Cast everything to scalar integer types.
|
|
|
|
MVT ScalarTy = MVT::getIntegerVT(VecWidth);
|
|
|
|
// The actual type of ValV may be different than ValTy (which is related
|
|
|
|
// to the vector type).
|
|
|
|
unsigned VW = ty(ValV).getSizeInBits();
|
|
|
|
ValV = DAG.getBitcast(MVT::getIntegerVT(VW), ValV);
|
|
|
|
VecV = DAG.getBitcast(ScalarTy, VecV);
|
|
|
|
if (VW != VecWidth)
|
|
|
|
ValV = DAG.getAnyExtOrTrunc(ValV, dl, ScalarTy);
|
|
|
|
|
|
|
|
SDValue WidthV = DAG.getConstant(ValWidth, dl, MVT::i32);
|
|
|
|
SDValue InsV;
|
|
|
|
|
|
|
|
if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(IdxV)) {
|
|
|
|
unsigned W = C->getZExtValue() * ValWidth;
|
|
|
|
SDValue OffV = DAG.getConstant(W, dl, MVT::i32);
|
|
|
|
InsV = DAG.getNode(HexagonISD::INSERT, dl, ScalarTy,
|
|
|
|
{VecV, ValV, WidthV, OffV});
|
|
|
|
} else {
|
|
|
|
if (ty(IdxV) != MVT::i32)
|
|
|
|
IdxV = DAG.getZExtOrTrunc(IdxV, dl, MVT::i32);
|
|
|
|
SDValue OffV = DAG.getNode(ISD::MUL, dl, MVT::i32, IdxV, WidthV);
|
2018-01-04 21:56:04 +08:00
|
|
|
InsV = DAG.getNode(HexagonISD::INSERT, dl, ScalarTy,
|
|
|
|
{VecV, ValV, WidthV, OffV});
|
2017-11-30 03:58:10 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return DAG.getNode(ISD::BITCAST, dl, VecTy, InsV);
|
|
|
|
}
|
|
|
|
|
2018-01-24 01:53:59 +08:00
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::expandPredicate(SDValue Vec32, const SDLoc &dl,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
assert(ty(Vec32).getSizeInBits() == 32);
|
|
|
|
if (isUndef(Vec32))
|
|
|
|
return DAG.getUNDEF(MVT::i64);
|
2018-02-01 05:17:03 +08:00
|
|
|
return getInstr(Hexagon::S2_vsxtbh, dl, MVT::i64, {Vec32}, DAG);
|
2018-01-24 01:53:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::contractPredicate(SDValue Vec64, const SDLoc &dl,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
assert(ty(Vec64).getSizeInBits() == 64);
|
|
|
|
if (isUndef(Vec64))
|
|
|
|
return DAG.getUNDEF(MVT::i32);
|
2018-02-01 05:17:03 +08:00
|
|
|
return getInstr(Hexagon::S2_vtrunehb, dl, MVT::i32, {Vec64}, DAG);
|
2018-01-24 01:53:59 +08:00
|
|
|
}
|
|
|
|
|
2017-12-21 04:49:43 +08:00
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::getZero(const SDLoc &dl, MVT Ty, SelectionDAG &DAG)
|
|
|
|
const {
|
|
|
|
if (Ty.isVector()) {
|
|
|
|
assert(Ty.isInteger() && "Only integer vectors are supported here");
|
|
|
|
unsigned W = Ty.getSizeInBits();
|
|
|
|
if (W <= 64)
|
|
|
|
return DAG.getBitcast(Ty, DAG.getConstant(0, dl, MVT::getIntegerVT(W)));
|
2020-10-10 09:17:50 +08:00
|
|
|
return DAG.getNode(ISD::SPLAT_VECTOR, dl, Ty, getZero(dl, MVT::i32, DAG));
|
2017-12-21 04:49:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Ty.isInteger())
|
|
|
|
return DAG.getConstant(0, dl, Ty);
|
|
|
|
if (Ty.isFloatingPoint())
|
|
|
|
return DAG.getConstantFP(0.0, dl, Ty);
|
|
|
|
llvm_unreachable("Invalid type for zero");
|
|
|
|
}
|
|
|
|
|
2020-09-15 03:04:54 +08:00
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::appendUndef(SDValue Val, MVT ResTy, SelectionDAG &DAG)
|
|
|
|
const {
|
|
|
|
MVT ValTy = ty(Val);
|
|
|
|
assert(ValTy.getVectorElementType() == ResTy.getVectorElementType());
|
|
|
|
|
|
|
|
unsigned ValLen = ValTy.getVectorNumElements();
|
|
|
|
unsigned ResLen = ResTy.getVectorNumElements();
|
|
|
|
if (ValLen == ResLen)
|
|
|
|
return Val;
|
|
|
|
|
|
|
|
const SDLoc &dl(Val);
|
|
|
|
assert(ValLen < ResLen);
|
|
|
|
assert(ResLen % ValLen == 0);
|
|
|
|
|
|
|
|
SmallVector<SDValue, 4> Concats = {Val};
|
|
|
|
for (unsigned i = 1, e = ResLen / ValLen; i < e; ++i)
|
|
|
|
Concats.push_back(DAG.getUNDEF(ValTy));
|
|
|
|
|
|
|
|
return DAG.getNode(ISD::CONCAT_VECTORS, dl, ResTy, Concats);
|
|
|
|
}
|
|
|
|
|
2017-11-23 04:56:23 +08:00
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerBUILD_VECTOR(SDValue Op, SelectionDAG &DAG) const {
|
2017-12-07 00:40:37 +08:00
|
|
|
MVT VecTy = ty(Op);
|
2018-01-24 01:53:59 +08:00
|
|
|
unsigned BW = VecTy.getSizeInBits();
|
|
|
|
const SDLoc &dl(Op);
|
|
|
|
SmallVector<SDValue,8> Ops;
|
|
|
|
for (unsigned i = 0, e = Op.getNumOperands(); i != e; ++i)
|
|
|
|
Ops.push_back(Op.getOperand(i));
|
|
|
|
|
|
|
|
if (BW == 32)
|
|
|
|
return buildVector32(Ops, dl, VecTy, DAG);
|
|
|
|
if (BW == 64)
|
2017-12-21 04:49:43 +08:00
|
|
|
return buildVector64(Ops, dl, VecTy, DAG);
|
2018-01-24 01:53:59 +08:00
|
|
|
|
|
|
|
if (VecTy == MVT::v8i1 || VecTy == MVT::v4i1 || VecTy == MVT::v2i1) {
|
2019-08-17 00:16:27 +08:00
|
|
|
// Check if this is a special case or all-0 or all-1.
|
|
|
|
bool All0 = true, All1 = true;
|
|
|
|
for (SDValue P : Ops) {
|
|
|
|
auto *CN = dyn_cast<ConstantSDNode>(P.getNode());
|
|
|
|
if (CN == nullptr) {
|
|
|
|
All0 = All1 = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
uint32_t C = CN->getZExtValue();
|
|
|
|
All0 &= (C == 0);
|
|
|
|
All1 &= (C == 1);
|
|
|
|
}
|
|
|
|
if (All0)
|
|
|
|
return DAG.getNode(HexagonISD::PFALSE, dl, VecTy);
|
|
|
|
if (All1)
|
|
|
|
return DAG.getNode(HexagonISD::PTRUE, dl, VecTy);
|
|
|
|
|
2018-01-24 01:53:59 +08:00
|
|
|
// For each i1 element in the resulting predicate register, put 1
|
|
|
|
// shifted by the index of the element into a general-purpose register,
|
|
|
|
// then or them together and transfer it back into a predicate register.
|
|
|
|
SDValue Rs[8];
|
|
|
|
SDValue Z = getZero(dl, MVT::i32, DAG);
|
|
|
|
// Always produce 8 bits, repeat inputs if necessary.
|
|
|
|
unsigned Rep = 8 / VecTy.getVectorNumElements();
|
|
|
|
for (unsigned i = 0; i != 8; ++i) {
|
2018-01-24 05:22:16 +08:00
|
|
|
SDValue S = DAG.getConstant(1ull << i, dl, MVT::i32);
|
2018-01-24 01:53:59 +08:00
|
|
|
Rs[i] = DAG.getSelect(dl, MVT::i32, Ops[i/Rep], S, Z);
|
|
|
|
}
|
|
|
|
for (ArrayRef<SDValue> A(Rs); A.size() != 1; A = A.drop_back(A.size()/2)) {
|
|
|
|
for (unsigned i = 0, e = A.size()/2; i != e; ++i)
|
|
|
|
Rs[i] = DAG.getNode(ISD::OR, dl, MVT::i32, Rs[2*i], Rs[2*i+1]);
|
|
|
|
}
|
|
|
|
// Move the value directly to a predicate register.
|
2018-02-01 05:17:03 +08:00
|
|
|
return getInstr(Hexagon::C2_tfrrp, dl, VecTy, {Rs[0]}, DAG);
|
2015-03-20 00:33:08 +08:00
|
|
|
}
|
|
|
|
|
2017-11-23 04:56:23 +08:00
|
|
|
return SDValue();
|
2015-03-20 00:33:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerCONCAT_VECTORS(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
2017-12-07 00:40:37 +08:00
|
|
|
MVT VecTy = ty(Op);
|
2018-01-24 01:53:59 +08:00
|
|
|
const SDLoc &dl(Op);
|
2017-12-07 00:40:37 +08:00
|
|
|
if (VecTy.getSizeInBits() == 64) {
|
|
|
|
assert(Op.getNumOperands() == 2);
|
2018-01-24 01:53:59 +08:00
|
|
|
return DAG.getNode(HexagonISD::COMBINE, dl, VecTy, Op.getOperand(1),
|
2017-12-07 00:40:37 +08:00
|
|
|
Op.getOperand(0));
|
2016-07-30 00:44:27 +08:00
|
|
|
}
|
|
|
|
|
2018-01-24 01:53:59 +08:00
|
|
|
MVT ElemTy = VecTy.getVectorElementType();
|
|
|
|
if (ElemTy == MVT::i1) {
|
|
|
|
assert(VecTy == MVT::v2i1 || VecTy == MVT::v4i1 || VecTy == MVT::v8i1);
|
|
|
|
MVT OpTy = ty(Op.getOperand(0));
|
|
|
|
// Scale is how many times the operands need to be contracted to match
|
|
|
|
// the representation in the target register.
|
|
|
|
unsigned Scale = VecTy.getVectorNumElements() / OpTy.getVectorNumElements();
|
|
|
|
assert(Scale == Op.getNumOperands() && Scale > 1);
|
|
|
|
|
|
|
|
// First, convert all bool vectors to integers, then generate pairwise
|
|
|
|
// inserts to form values of doubled length. Up until there are only
|
|
|
|
// two values left to concatenate, all of these values will fit in a
|
|
|
|
// 32-bit integer, so keep them as i32 to use 32-bit inserts.
|
|
|
|
SmallVector<SDValue,4> Words[2];
|
|
|
|
unsigned IdxW = 0;
|
|
|
|
|
|
|
|
for (SDValue P : Op.getNode()->op_values()) {
|
|
|
|
SDValue W = DAG.getNode(HexagonISD::P2D, dl, MVT::i64, P);
|
|
|
|
for (unsigned R = Scale; R > 1; R /= 2) {
|
|
|
|
W = contractPredicate(W, dl, DAG);
|
|
|
|
W = DAG.getNode(HexagonISD::COMBINE, dl, MVT::i64,
|
|
|
|
DAG.getUNDEF(MVT::i32), W);
|
|
|
|
}
|
|
|
|
W = DAG.getTargetExtractSubreg(Hexagon::isub_lo, dl, MVT::i32, W);
|
|
|
|
Words[IdxW].push_back(W);
|
|
|
|
}
|
|
|
|
|
|
|
|
while (Scale > 2) {
|
|
|
|
SDValue WidthV = DAG.getConstant(64 / Scale, dl, MVT::i32);
|
|
|
|
Words[IdxW ^ 1].clear();
|
|
|
|
|
|
|
|
for (unsigned i = 0, e = Words[IdxW].size(); i != e; i += 2) {
|
|
|
|
SDValue W0 = Words[IdxW][i], W1 = Words[IdxW][i+1];
|
|
|
|
// Insert W1 into W0 right next to the significant bits of W0.
|
|
|
|
SDValue T = DAG.getNode(HexagonISD::INSERT, dl, MVT::i32,
|
|
|
|
{W0, W1, WidthV, WidthV});
|
|
|
|
Words[IdxW ^ 1].push_back(T);
|
|
|
|
}
|
|
|
|
IdxW ^= 1;
|
|
|
|
Scale /= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Another sanity check. At this point there should only be two words
|
|
|
|
// left, and Scale should be 2.
|
|
|
|
assert(Scale == 2 && Words[IdxW].size() == 2);
|
|
|
|
|
|
|
|
SDValue WW = DAG.getNode(HexagonISD::COMBINE, dl, MVT::i64,
|
|
|
|
Words[IdxW][1], Words[IdxW][0]);
|
|
|
|
return DAG.getNode(HexagonISD::D2P, dl, VecTy, WW);
|
|
|
|
}
|
|
|
|
|
2016-07-30 00:44:27 +08:00
|
|
|
return SDValue();
|
|
|
|
}
|
|
|
|
|
2015-03-20 00:33:08 +08:00
|
|
|
SDValue
|
2017-11-30 03:58:10 +08:00
|
|
|
HexagonTargetLowering::LowerEXTRACT_VECTOR_ELT(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
2015-03-20 00:33:08 +08:00
|
|
|
SDValue Vec = Op.getOperand(0);
|
2017-11-30 03:58:10 +08:00
|
|
|
MVT ElemTy = ty(Vec).getVectorElementType();
|
|
|
|
return extractVector(Vec, Op.getOperand(1), SDLoc(Op), ElemTy, ty(Op), DAG);
|
2015-03-20 00:33:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
SDValue
|
2017-11-30 03:58:10 +08:00
|
|
|
HexagonTargetLowering::LowerEXTRACT_SUBVECTOR(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
2018-02-07 04:22:20 +08:00
|
|
|
return extractVector(Op.getOperand(0), Op.getOperand(1), SDLoc(Op),
|
|
|
|
ty(Op), ty(Op), DAG);
|
2017-11-30 03:58:10 +08:00
|
|
|
}
|
2015-03-20 00:33:08 +08:00
|
|
|
|
2017-11-30 03:58:10 +08:00
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerINSERT_VECTOR_ELT(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
return insertVector(Op.getOperand(0), Op.getOperand(1), Op.getOperand(2),
|
2018-02-07 04:22:20 +08:00
|
|
|
SDLoc(Op), ty(Op).getVectorElementType(), DAG);
|
2017-11-30 03:58:10 +08:00
|
|
|
}
|
2015-03-20 00:33:08 +08:00
|
|
|
|
2017-11-30 03:58:10 +08:00
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerINSERT_SUBVECTOR(SDValue Op,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
SDValue ValV = Op.getOperand(1);
|
|
|
|
return insertVector(Op.getOperand(0), ValV, Op.getOperand(2),
|
|
|
|
SDLoc(Op), ty(ValV), DAG);
|
2015-03-20 00:33:08 +08:00
|
|
|
}
|
|
|
|
|
Refactor isInTailCallPosition handling
This change came about primarily because of two issues in the existing code.
Niether of:
define i64 @test1(i64 %val) {
%in = trunc i64 %val to i32
tail call i32 @ret32(i32 returned %in)
ret i64 %val
}
define i64 @test2(i64 %val) {
tail call i32 @ret32(i32 returned undef)
ret i32 42
}
should be tail calls, and the function sameNoopInput is responsible. The main
problem is that it is completely symmetric in the "tail call" and "ret" value,
but in reality different things are allowed on each side.
For these cases:
1. Any truncation should lead to a larger value being generated by "tail call"
than needed by "ret".
2. Undef should only be allowed as a source for ret, not as a result of the
call.
Along the way I noticed that a mismatch between what this function treats as a
valid truncation and what the backends see can lead to invalid calls as well
(see x86-32 test case).
This patch refactors the code so that instead of being based primarily on
values which it recurses into when necessary, it starts by inspecting the type
and considers each fundamental slot that the backend will see in turn. For
example, given a pathological function that returned {{}, {{}, i32, {}}, i32}
we would consider each "real" i32 in turn, and ask if it passes through
unchanged. This is much closer to what the backend sees as a result of
ComputeValueVTs.
Aside from the bug fixes, this eliminates the recursion that's going on and, I
believe, makes the bulk of the code significantly easier to understand. The
trade-off is the nasty iterators needed to find the real types inside a
returned value.
llvm-svn: 187787
2013-08-06 17:12:35 +08:00
|
|
|
bool
|
|
|
|
HexagonTargetLowering::allowTruncateForTailCall(Type *Ty1, Type *Ty2) const {
|
|
|
|
// Assuming the caller does not have either a signext or zeroext modifier, and
|
|
|
|
// only one value is accepted, any reasonable truncation is allowed.
|
|
|
|
if (!Ty1->isIntegerTy() || !Ty2->isIntegerTy())
|
|
|
|
return false;
|
|
|
|
|
|
|
|
// FIXME: in principle up to 64-bit could be made safe, but it would be very
|
|
|
|
// fragile at the moment: any support for multiple value returns would be
|
|
|
|
// liable to disallow tail calls involving i64 -> iN truncation in many cases.
|
|
|
|
return Ty1->getPrimitiveSizeInBits() <= 32;
|
|
|
|
}
|
|
|
|
|
2018-08-09 01:00:09 +08:00
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerLoad(SDValue Op, SelectionDAG &DAG) const {
|
2021-05-11 04:26:57 +08:00
|
|
|
MVT Ty = ty(Op);
|
|
|
|
const SDLoc &dl(Op);
|
|
|
|
// Lower loads of scalar predicate vectors (v2i1, v4i1, v8i1) to loads of i1
|
|
|
|
// followed by a TYPECAST.
|
2018-08-09 01:00:09 +08:00
|
|
|
LoadSDNode *LN = cast<LoadSDNode>(Op.getNode());
|
2021-05-11 04:26:57 +08:00
|
|
|
bool DoCast = (Ty == MVT::v2i1 || Ty == MVT::v4i1 || Ty == MVT::v8i1);
|
|
|
|
if (DoCast) {
|
|
|
|
SDValue NL = DAG.getLoad(
|
|
|
|
LN->getAddressingMode(), LN->getExtensionType(), MVT::i1, dl,
|
|
|
|
LN->getChain(), LN->getBasePtr(), LN->getOffset(), LN->getPointerInfo(),
|
|
|
|
/*MemoryVT*/ MVT::i1, LN->getAlign(), LN->getMemOperand()->getFlags(),
|
|
|
|
LN->getAAInfo(), LN->getRanges());
|
|
|
|
LN = cast<LoadSDNode>(NL.getNode());
|
|
|
|
}
|
|
|
|
|
2021-06-25 23:22:01 +08:00
|
|
|
Align ClaimAlign = LN->getAlign();
|
2021-06-25 22:30:59 +08:00
|
|
|
if (!validateConstPtrAlignment(LN->getBasePtr(), ClaimAlign, dl, DAG))
|
|
|
|
return replaceMemWithUndef(Op, DAG);
|
|
|
|
|
2018-08-09 01:00:09 +08:00
|
|
|
// Call LowerUnalignedLoad for all loads, it recognizes loads that
|
|
|
|
// don't need extra aligning.
|
2021-05-11 04:26:57 +08:00
|
|
|
SDValue LU = LowerUnalignedLoad(SDValue(LN, 0), DAG);
|
|
|
|
if (DoCast) {
|
|
|
|
SDValue TC = DAG.getNode(HexagonISD::TYPECAST, dl, Ty, LU);
|
|
|
|
SDValue Ch = cast<LoadSDNode>(LU.getNode())->getChain();
|
|
|
|
return DAG.getMergeValues({TC, Ch}, dl);
|
|
|
|
}
|
|
|
|
return LU;
|
2018-08-09 01:00:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerStore(SDValue Op, SelectionDAG &DAG) const {
|
2021-05-11 04:26:57 +08:00
|
|
|
const SDLoc &dl(Op);
|
2018-08-09 01:00:09 +08:00
|
|
|
StoreSDNode *SN = cast<StoreSDNode>(Op.getNode());
|
2021-05-11 04:26:57 +08:00
|
|
|
SDValue Val = SN->getValue();
|
|
|
|
MVT Ty = ty(Val);
|
|
|
|
|
|
|
|
bool DoCast = (Ty == MVT::v2i1 || Ty == MVT::v4i1 || Ty == MVT::v8i1);
|
|
|
|
if (DoCast) {
|
|
|
|
SDValue TC = DAG.getNode(HexagonISD::TYPECAST, dl, MVT::i1, Val);
|
|
|
|
SDValue NS = DAG.getStore(SN->getChain(), dl, TC, SN->getBasePtr(),
|
|
|
|
SN->getMemOperand());
|
|
|
|
if (SN->isIndexed()) {
|
|
|
|
NS = DAG.getIndexedStore(NS, dl, SN->getBasePtr(), SN->getOffset(),
|
|
|
|
SN->getAddressingMode());
|
|
|
|
}
|
|
|
|
SN = cast<StoreSDNode>(NS.getNode());
|
|
|
|
}
|
|
|
|
|
2021-06-25 23:22:01 +08:00
|
|
|
Align ClaimAlign = SN->getAlign();
|
2021-06-25 22:30:59 +08:00
|
|
|
if (!validateConstPtrAlignment(SN->getBasePtr(), ClaimAlign, dl, DAG))
|
|
|
|
return replaceMemWithUndef(Op, DAG);
|
2018-08-09 01:00:09 +08:00
|
|
|
|
|
|
|
MVT StoreTy = SN->getMemoryVT().getSimpleVT();
|
2021-06-25 23:22:01 +08:00
|
|
|
Align NeedAlign = Subtarget.getTypeAlignment(StoreTy);
|
2018-08-09 01:00:09 +08:00
|
|
|
if (ClaimAlign < NeedAlign)
|
|
|
|
return expandUnalignedStore(SN, DAG);
|
2021-05-11 04:26:57 +08:00
|
|
|
return SDValue(SN, 0);
|
2018-08-09 01:00:09 +08:00
|
|
|
}
|
|
|
|
|
2018-03-08 01:27:18 +08:00
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerUnalignedLoad(SDValue Op, SelectionDAG &DAG)
|
|
|
|
const {
|
|
|
|
LoadSDNode *LN = cast<LoadSDNode>(Op.getNode());
|
|
|
|
MVT LoadTy = ty(Op);
|
2021-06-25 23:22:01 +08:00
|
|
|
unsigned NeedAlign = Subtarget.getTypeAlignment(LoadTy).value();
|
|
|
|
unsigned HaveAlign = LN->getAlign().value();
|
2018-03-08 01:27:18 +08:00
|
|
|
if (HaveAlign >= NeedAlign)
|
|
|
|
return Op;
|
|
|
|
|
|
|
|
const SDLoc &dl(Op);
|
|
|
|
const DataLayout &DL = DAG.getDataLayout();
|
|
|
|
LLVMContext &Ctx = *DAG.getContext();
|
|
|
|
|
|
|
|
// If the load aligning is disabled or the load can be broken up into two
|
|
|
|
// smaller legal loads, do the default (target-independent) expansion.
|
|
|
|
bool DoDefault = false;
|
2018-03-09 02:15:13 +08:00
|
|
|
// Handle it in the default way if this is an indexed load.
|
|
|
|
if (!LN->isUnindexed())
|
|
|
|
DoDefault = true;
|
|
|
|
|
2018-03-08 01:27:18 +08:00
|
|
|
if (!AlignLoads) {
|
2019-09-26 08:16:01 +08:00
|
|
|
if (allowsMemoryAccessForAlignment(Ctx, DL, LN->getMemoryVT(),
|
|
|
|
*LN->getMemOperand()))
|
2018-03-08 01:27:18 +08:00
|
|
|
return Op;
|
|
|
|
DoDefault = true;
|
|
|
|
}
|
2019-06-11 19:00:23 +08:00
|
|
|
if (!DoDefault && (2 * HaveAlign) == NeedAlign) {
|
2018-03-08 01:27:18 +08:00
|
|
|
// The PartTy is the equivalent of "getLoadableTypeOfSize(HaveAlign)".
|
2019-06-11 19:00:23 +08:00
|
|
|
MVT PartTy = HaveAlign <= 8 ? MVT::getIntegerVT(8 * HaveAlign)
|
2018-03-08 01:27:18 +08:00
|
|
|
: MVT::getVectorVT(MVT::i8, HaveAlign);
|
2019-09-26 08:16:01 +08:00
|
|
|
DoDefault =
|
|
|
|
allowsMemoryAccessForAlignment(Ctx, DL, PartTy, *LN->getMemOperand());
|
2018-03-08 01:27:18 +08:00
|
|
|
}
|
|
|
|
if (DoDefault) {
|
|
|
|
std::pair<SDValue, SDValue> P = expandUnalignedLoad(LN, DAG);
|
|
|
|
return DAG.getMergeValues({P.first, P.second}, dl);
|
|
|
|
}
|
|
|
|
|
|
|
|
// The code below generates two loads, both aligned as NeedAlign, and
|
|
|
|
// with the distance of NeedAlign between them. For that to cover the
|
|
|
|
// bits that need to be loaded (and without overlapping), the size of
|
|
|
|
// the loads should be equal to NeedAlign. This is true for all loadable
|
|
|
|
// types, but add an assertion in case something changes in the future.
|
|
|
|
assert(LoadTy.getSizeInBits() == 8*NeedAlign);
|
|
|
|
|
|
|
|
unsigned LoadLen = NeedAlign;
|
|
|
|
SDValue Base = LN->getBasePtr();
|
|
|
|
SDValue Chain = LN->getChain();
|
|
|
|
auto BO = getBaseAndOffset(Base);
|
|
|
|
unsigned BaseOpc = BO.first.getOpcode();
|
|
|
|
if (BaseOpc == HexagonISD::VALIGNADDR && BO.second % LoadLen == 0)
|
|
|
|
return Op;
|
|
|
|
|
|
|
|
if (BO.second % LoadLen != 0) {
|
|
|
|
BO.first = DAG.getNode(ISD::ADD, dl, MVT::i32, BO.first,
|
|
|
|
DAG.getConstant(BO.second % LoadLen, dl, MVT::i32));
|
|
|
|
BO.second -= BO.second % LoadLen;
|
|
|
|
}
|
|
|
|
SDValue BaseNoOff = (BaseOpc != HexagonISD::VALIGNADDR)
|
|
|
|
? DAG.getNode(HexagonISD::VALIGNADDR, dl, MVT::i32, BO.first,
|
|
|
|
DAG.getConstant(NeedAlign, dl, MVT::i32))
|
|
|
|
: BO.first;
|
2020-08-11 18:38:08 +08:00
|
|
|
SDValue Base0 =
|
|
|
|
DAG.getMemBasePlusOffset(BaseNoOff, TypeSize::Fixed(BO.second), dl);
|
|
|
|
SDValue Base1 = DAG.getMemBasePlusOffset(
|
|
|
|
BaseNoOff, TypeSize::Fixed(BO.second + LoadLen), dl);
|
2018-03-08 01:27:18 +08:00
|
|
|
|
|
|
|
MachineMemOperand *WideMMO = nullptr;
|
|
|
|
if (MachineMemOperand *MMO = LN->getMemOperand()) {
|
|
|
|
MachineFunction &MF = DAG.getMachineFunction();
|
[Alignment][NFC] Transitionning more getMachineMemOperand call sites
Summary:
This is patch is part of a series to introduce an Alignment type.
See this thread for context: http://lists.llvm.org/pipermail/llvm-dev/2019-July/133851.html
See this patch for the introduction of the type: https://reviews.llvm.org/D64790
Reviewers: courbet
Subscribers: arsenm, dylanmckay, sdardis, nemanjai, jvesely, nhaehnle, hiraditya, kbarton, jrtc27, atanasyan, Jim, kerbowa, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D77121
2020-03-31 16:05:00 +08:00
|
|
|
WideMMO = MF.getMachineMemOperand(
|
|
|
|
MMO->getPointerInfo(), MMO->getFlags(), 2 * LoadLen, Align(LoadLen),
|
|
|
|
MMO->getAAInfo(), MMO->getRanges(), MMO->getSyncScopeID(),
|
2021-06-22 07:34:02 +08:00
|
|
|
MMO->getSuccessOrdering(), MMO->getFailureOrdering());
|
2018-03-08 01:27:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
SDValue Load0 = DAG.getLoad(LoadTy, dl, Chain, Base0, WideMMO);
|
|
|
|
SDValue Load1 = DAG.getLoad(LoadTy, dl, Chain, Base1, WideMMO);
|
|
|
|
|
|
|
|
SDValue Aligned = DAG.getNode(HexagonISD::VALIGN, dl, LoadTy,
|
|
|
|
{Load1, Load0, BaseNoOff.getOperand(0)});
|
|
|
|
SDValue NewChain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other,
|
|
|
|
Load0.getValue(1), Load1.getValue(1));
|
|
|
|
SDValue M = DAG.getMergeValues({Aligned, NewChain}, dl);
|
|
|
|
return M;
|
|
|
|
}
|
|
|
|
|
2019-07-01 23:50:09 +08:00
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerUAddSubO(SDValue Op, SelectionDAG &DAG) const {
|
|
|
|
SDValue X = Op.getOperand(0), Y = Op.getOperand(1);
|
|
|
|
auto *CY = dyn_cast<ConstantSDNode>(Y);
|
|
|
|
if (!CY)
|
|
|
|
return SDValue();
|
|
|
|
|
|
|
|
const SDLoc &dl(Op);
|
|
|
|
SDVTList VTs = Op.getNode()->getVTList();
|
|
|
|
assert(VTs.NumVTs == 2);
|
|
|
|
assert(VTs.VTs[1] == MVT::i1);
|
|
|
|
unsigned Opc = Op.getOpcode();
|
|
|
|
|
|
|
|
if (CY) {
|
|
|
|
uint32_t VY = CY->getZExtValue();
|
|
|
|
assert(VY != 0 && "This should have been folded");
|
|
|
|
// X +/- 1
|
|
|
|
if (VY != 1)
|
|
|
|
return SDValue();
|
|
|
|
|
|
|
|
if (Opc == ISD::UADDO) {
|
|
|
|
SDValue Op = DAG.getNode(ISD::ADD, dl, VTs.VTs[0], {X, Y});
|
|
|
|
SDValue Ov = DAG.getSetCC(dl, MVT::i1, Op, getZero(dl, ty(Op), DAG),
|
|
|
|
ISD::SETEQ);
|
|
|
|
return DAG.getMergeValues({Op, Ov}, dl);
|
|
|
|
}
|
|
|
|
if (Opc == ISD::USUBO) {
|
|
|
|
SDValue Op = DAG.getNode(ISD::SUB, dl, VTs.VTs[0], {X, Y});
|
|
|
|
SDValue Ov = DAG.getSetCC(dl, MVT::i1, Op,
|
|
|
|
DAG.getConstant(-1, dl, ty(Op)), ISD::SETEQ);
|
|
|
|
return DAG.getMergeValues({Op, Ov}, dl);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return SDValue();
|
|
|
|
}
|
|
|
|
|
2018-06-01 22:00:32 +08:00
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerAddSubCarry(SDValue Op, SelectionDAG &DAG) const {
|
|
|
|
const SDLoc &dl(Op);
|
|
|
|
unsigned Opc = Op.getOpcode();
|
|
|
|
SDValue X = Op.getOperand(0), Y = Op.getOperand(1), C = Op.getOperand(2);
|
|
|
|
|
|
|
|
if (Opc == ISD::ADDCARRY)
|
|
|
|
return DAG.getNode(HexagonISD::ADDC, dl, Op.getNode()->getVTList(),
|
|
|
|
{ X, Y, C });
|
|
|
|
|
|
|
|
EVT CarryTy = C.getValueType();
|
|
|
|
SDValue SubC = DAG.getNode(HexagonISD::SUBC, dl, Op.getNode()->getVTList(),
|
|
|
|
{ X, Y, DAG.getLogicalNOT(dl, C, CarryTy) });
|
|
|
|
SDValue Out[] = { SubC.getValue(0),
|
|
|
|
DAG.getLogicalNOT(dl, SubC.getValue(1), CarryTy) };
|
|
|
|
return DAG.getMergeValues(Out, dl);
|
|
|
|
}
|
|
|
|
|
2013-05-02 05:37:34 +08:00
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerEH_RETURN(SDValue Op, SelectionDAG &DAG) const {
|
|
|
|
SDValue Chain = Op.getOperand(0);
|
|
|
|
SDValue Offset = Op.getOperand(1);
|
|
|
|
SDValue Handler = Op.getOperand(2);
|
2013-05-25 10:42:55 +08:00
|
|
|
SDLoc dl(Op);
|
2015-07-09 10:09:04 +08:00
|
|
|
auto PtrVT = getPointerTy(DAG.getDataLayout());
|
2013-05-02 05:37:34 +08:00
|
|
|
|
|
|
|
// Mark function as containing a call to EH_RETURN.
|
|
|
|
HexagonMachineFunctionInfo *FuncInfo =
|
|
|
|
DAG.getMachineFunction().getInfo<HexagonMachineFunctionInfo>();
|
|
|
|
FuncInfo->setHasEHReturn();
|
|
|
|
|
|
|
|
unsigned OffsetReg = Hexagon::R28;
|
|
|
|
|
2015-07-09 10:09:04 +08:00
|
|
|
SDValue StoreAddr =
|
|
|
|
DAG.getNode(ISD::ADD, dl, PtrVT, DAG.getRegister(Hexagon::R30, PtrVT),
|
|
|
|
DAG.getIntPtrConstant(4, dl));
|
[SelectionDAG] Get rid of bool parameters in SelectionDAG::getLoad, getStore, and friends.
Summary:
Instead, we take a single flags arg (a bitset).
Also add a default 0 alignment, and change the order of arguments so the
alignment comes before the flags.
This greatly simplifies many callsites, and fixes a bug in
AMDGPUISelLowering, wherein the order of the args to getLoad was
inverted. It also greatly simplifies the process of adding another flag
to getLoad.
Reviewers: chandlerc, tstellarAMD
Subscribers: jholewinski, arsenm, jyknight, dsanders, nemanjai, llvm-commits
Differential Revision: http://reviews.llvm.org/D22249
llvm-svn: 275592
2016-07-16 02:27:10 +08:00
|
|
|
Chain = DAG.getStore(Chain, dl, Handler, StoreAddr, MachinePointerInfo());
|
2013-05-02 05:37:34 +08:00
|
|
|
Chain = DAG.getCopyToReg(Chain, dl, OffsetReg, Offset);
|
|
|
|
|
|
|
|
// Not needed we already use it as explict input to EH_RETURN.
|
|
|
|
// MF.getRegInfo().addLiveOut(OffsetReg);
|
|
|
|
|
|
|
|
return DAG.getNode(HexagonISD::EH_RETURN, dl, MVT::Other, Chain);
|
|
|
|
}
|
|
|
|
|
2011-12-13 05:14:40 +08:00
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const {
|
2015-04-23 05:17:00 +08:00
|
|
|
unsigned Opc = Op.getOpcode();
|
2018-02-06 22:24:57 +08:00
|
|
|
|
|
|
|
// Handle INLINEASM first.
|
2019-02-09 04:48:56 +08:00
|
|
|
if (Opc == ISD::INLINEASM || Opc == ISD::INLINEASM_BR)
|
2018-02-06 22:24:57 +08:00
|
|
|
return LowerINLINEASM(Op, DAG);
|
|
|
|
|
2020-09-05 08:33:14 +08:00
|
|
|
if (isHvxOperation(Op.getNode(), DAG)) {
|
2018-03-08 01:27:18 +08:00
|
|
|
// If HVX lowering returns nothing, try the default lowering.
|
|
|
|
if (SDValue V = LowerHvxOperation(Op, DAG))
|
|
|
|
return V;
|
|
|
|
}
|
2018-02-06 22:24:57 +08:00
|
|
|
|
2015-04-23 05:17:00 +08:00
|
|
|
switch (Opc) {
|
|
|
|
default:
|
|
|
|
#ifndef NDEBUG
|
|
|
|
Op.getNode()->dumpr(&DAG);
|
|
|
|
if (Opc > HexagonISD::OP_BEGIN && Opc < HexagonISD::OP_END)
|
2017-12-21 04:49:43 +08:00
|
|
|
errs() << "Error: check for a non-legal type in this operation\n";
|
2015-04-23 05:17:00 +08:00
|
|
|
#endif
|
|
|
|
llvm_unreachable("Should not custom lower this!");
|
|
|
|
case ISD::CONCAT_VECTORS: return LowerCONCAT_VECTORS(Op, DAG);
|
2017-11-30 03:58:10 +08:00
|
|
|
case ISD::INSERT_SUBVECTOR: return LowerINSERT_SUBVECTOR(Op, DAG);
|
|
|
|
case ISD::INSERT_VECTOR_ELT: return LowerINSERT_VECTOR_ELT(Op, DAG);
|
|
|
|
case ISD::EXTRACT_SUBVECTOR: return LowerEXTRACT_SUBVECTOR(Op, DAG);
|
|
|
|
case ISD::EXTRACT_VECTOR_ELT: return LowerEXTRACT_VECTOR_ELT(Op, DAG);
|
2015-04-23 05:17:00 +08:00
|
|
|
case ISD::BUILD_VECTOR: return LowerBUILD_VECTOR(Op, DAG);
|
|
|
|
case ISD::VECTOR_SHUFFLE: return LowerVECTOR_SHUFFLE(Op, DAG);
|
2018-01-24 01:53:59 +08:00
|
|
|
case ISD::BITCAST: return LowerBITCAST(Op, DAG);
|
2018-08-09 01:00:09 +08:00
|
|
|
case ISD::LOAD: return LowerLoad(Op, DAG);
|
|
|
|
case ISD::STORE: return LowerStore(Op, DAG);
|
2019-07-01 23:50:09 +08:00
|
|
|
case ISD::UADDO:
|
|
|
|
case ISD::USUBO: return LowerUAddSubO(Op, DAG);
|
2018-06-01 22:00:32 +08:00
|
|
|
case ISD::ADDCARRY:
|
|
|
|
case ISD::SUBCARRY: return LowerAddSubCarry(Op, DAG);
|
2015-03-20 00:33:08 +08:00
|
|
|
case ISD::SRA:
|
|
|
|
case ISD::SHL:
|
2015-04-23 05:17:00 +08:00
|
|
|
case ISD::SRL: return LowerVECTOR_SHIFT(Op, DAG);
|
2018-06-12 20:49:36 +08:00
|
|
|
case ISD::ROTL: return LowerROTL(Op, DAG);
|
2015-04-23 05:17:00 +08:00
|
|
|
case ISD::ConstantPool: return LowerConstantPool(Op, DAG);
|
2015-12-19 04:19:30 +08:00
|
|
|
case ISD::JumpTable: return LowerJumpTable(Op, DAG);
|
2015-04-23 05:17:00 +08:00
|
|
|
case ISD::EH_RETURN: return LowerEH_RETURN(Op, DAG);
|
|
|
|
case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG);
|
|
|
|
case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG);
|
2016-02-18 23:42:57 +08:00
|
|
|
case ISD::GlobalTLSAddress: return LowerGlobalTLSAddress(Op, DAG);
|
2015-04-23 05:17:00 +08:00
|
|
|
case ISD::ATOMIC_FENCE: return LowerATOMIC_FENCE(Op, DAG);
|
|
|
|
case ISD::GlobalAddress: return LowerGLOBALADDRESS(Op, DAG);
|
|
|
|
case ISD::BlockAddress: return LowerBlockAddress(Op, DAG);
|
2015-12-19 04:19:30 +08:00
|
|
|
case ISD::GLOBAL_OFFSET_TABLE: return LowerGLOBAL_OFFSET_TABLE(Op, DAG);
|
2020-02-21 06:42:02 +08:00
|
|
|
case ISD::VACOPY: return LowerVACOPY(Op, DAG);
|
2015-04-23 05:17:00 +08:00
|
|
|
case ISD::VASTART: return LowerVASTART(Op, DAG);
|
|
|
|
case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG);
|
|
|
|
case ISD::SETCC: return LowerSETCC(Op, DAG);
|
|
|
|
case ISD::VSELECT: return LowerVSELECT(Op, DAG);
|
|
|
|
case ISD::INTRINSIC_WO_CHAIN: return LowerINTRINSIC_WO_CHAIN(Op, DAG);
|
2016-02-18 21:58:38 +08:00
|
|
|
case ISD::INTRINSIC_VOID: return LowerINTRINSIC_VOID(Op, DAG);
|
|
|
|
case ISD::PREFETCH: return LowerPREFETCH(Op, DAG);
|
2017-02-23 06:28:47 +08:00
|
|
|
case ISD::READCYCLECOUNTER: return LowerREADCYCLECOUNTER(Op, DAG);
|
2018-02-01 04:48:11 +08:00
|
|
|
break;
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
2018-02-06 22:24:57 +08:00
|
|
|
|
2017-12-07 00:40:37 +08:00
|
|
|
return SDValue();
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
|
|
|
|
2018-08-09 01:00:09 +08:00
|
|
|
void
|
|
|
|
HexagonTargetLowering::LowerOperationWrapper(SDNode *N,
|
|
|
|
SmallVectorImpl<SDValue> &Results,
|
|
|
|
SelectionDAG &DAG) const {
|
2020-09-05 08:33:14 +08:00
|
|
|
if (isHvxOperation(N, DAG)) {
|
2020-02-26 23:56:12 +08:00
|
|
|
LowerHvxOperationWrapper(N, Results, DAG);
|
|
|
|
if (!Results.empty())
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-08-09 01:00:09 +08:00
|
|
|
// We are only custom-lowering stores to verify the alignment of the
|
|
|
|
// address if it is a compile-time constant. Since a store can be modified
|
|
|
|
// during type-legalization (the value being stored may need legalization),
|
|
|
|
// return empty Results here to indicate that we don't really make any
|
|
|
|
// changes in the custom lowering.
|
|
|
|
if (N->getOpcode() != ISD::STORE)
|
|
|
|
return TargetLowering::LowerOperationWrapper(N, Results, DAG);
|
|
|
|
}
|
|
|
|
|
2018-01-24 01:53:59 +08:00
|
|
|
void
|
|
|
|
HexagonTargetLowering::ReplaceNodeResults(SDNode *N,
|
|
|
|
SmallVectorImpl<SDValue> &Results,
|
|
|
|
SelectionDAG &DAG) const {
|
2020-09-05 08:33:14 +08:00
|
|
|
if (isHvxOperation(N, DAG)) {
|
2020-02-26 23:56:12 +08:00
|
|
|
ReplaceHvxNodeResults(N, Results, DAG);
|
|
|
|
if (!Results.empty())
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-01-24 01:53:59 +08:00
|
|
|
const SDLoc &dl(N);
|
|
|
|
switch (N->getOpcode()) {
|
|
|
|
case ISD::SRL:
|
|
|
|
case ISD::SRA:
|
|
|
|
case ISD::SHL:
|
|
|
|
return;
|
|
|
|
case ISD::BITCAST:
|
|
|
|
// Handle a bitcast from v8i1 to i8.
|
|
|
|
if (N->getValueType(0) == MVT::i8) {
|
2020-12-16 05:59:59 +08:00
|
|
|
if (N->getOperand(0).getValueType() == MVT::v8i1) {
|
|
|
|
SDValue P = getInstr(Hexagon::C2_tfrpr, dl, MVT::i32,
|
|
|
|
N->getOperand(0), DAG);
|
|
|
|
SDValue T = DAG.getAnyExtOrTrunc(P, dl, MVT::i8);
|
|
|
|
Results.push_back(T);
|
|
|
|
}
|
2018-01-24 01:53:59 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-16 00:13:17 +08:00
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::PerformDAGCombine(SDNode *N, DAGCombinerInfo &DCI)
|
|
|
|
const {
|
2020-09-05 08:33:14 +08:00
|
|
|
if (isHvxOperation(N, DCI.DAG)) {
|
2019-08-16 00:13:17 +08:00
|
|
|
if (SDValue V = PerformHvxDAGCombine(N, DCI))
|
|
|
|
return V;
|
2019-08-17 00:16:27 +08:00
|
|
|
return SDValue();
|
|
|
|
}
|
|
|
|
|
2020-10-10 09:17:50 +08:00
|
|
|
if (DCI.isBeforeLegalizeOps())
|
|
|
|
return SDValue();
|
|
|
|
|
2020-08-26 00:42:42 +08:00
|
|
|
SDValue Op(N, 0);
|
2019-08-17 00:16:27 +08:00
|
|
|
const SDLoc &dl(Op);
|
|
|
|
unsigned Opc = Op.getOpcode();
|
|
|
|
|
|
|
|
if (Opc == HexagonISD::P2D) {
|
|
|
|
SDValue P = Op.getOperand(0);
|
|
|
|
switch (P.getOpcode()) {
|
|
|
|
case HexagonISD::PTRUE:
|
|
|
|
return DCI.DAG.getConstant(-1, dl, ty(Op));
|
|
|
|
case HexagonISD::PFALSE:
|
|
|
|
return getZero(dl, ty(Op), DCI.DAG);
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else if (Opc == ISD::VSELECT) {
|
|
|
|
// This is pretty much duplicated in HexagonISelLoweringHVX...
|
|
|
|
//
|
|
|
|
// (vselect (xor x, ptrue), v0, v1) -> (vselect x, v1, v0)
|
|
|
|
SDValue Cond = Op.getOperand(0);
|
|
|
|
if (Cond->getOpcode() == ISD::XOR) {
|
|
|
|
SDValue C0 = Cond.getOperand(0), C1 = Cond.getOperand(1);
|
|
|
|
if (C1->getOpcode() == HexagonISD::PTRUE) {
|
|
|
|
SDValue VSel = DCI.DAG.getNode(ISD::VSELECT, dl, ty(Op), C0,
|
|
|
|
Op.getOperand(2), Op.getOperand(1));
|
|
|
|
return VSel;
|
|
|
|
}
|
|
|
|
}
|
2019-08-16 00:13:17 +08:00
|
|
|
}
|
2019-08-17 00:16:27 +08:00
|
|
|
|
2019-08-16 00:13:17 +08:00
|
|
|
return SDValue();
|
|
|
|
}
|
|
|
|
|
2015-12-19 04:19:30 +08:00
|
|
|
/// Returns relocation base for the given PIC jumptable.
|
|
|
|
SDValue
|
|
|
|
HexagonTargetLowering::getPICJumpTableRelocBase(SDValue Table,
|
|
|
|
SelectionDAG &DAG) const {
|
|
|
|
int Idx = cast<JumpTableSDNode>(Table)->getIndex();
|
|
|
|
EVT VT = Table.getValueType();
|
|
|
|
SDValue T = DAG.getTargetJumpTable(Idx, VT, HexagonII::MO_PCREL);
|
|
|
|
return DAG.getNode(HexagonISD::AT_PCREL, SDLoc(Table), VT, T);
|
|
|
|
}
|
|
|
|
|
2011-12-13 05:14:40 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Inline Assembly Support
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2016-05-18 22:34:51 +08:00
|
|
|
TargetLowering::ConstraintType
|
|
|
|
HexagonTargetLowering::getConstraintType(StringRef Constraint) const {
|
|
|
|
if (Constraint.size() == 1) {
|
|
|
|
switch (Constraint[0]) {
|
|
|
|
case 'q':
|
|
|
|
case 'v':
|
|
|
|
if (Subtarget.useHVXOps())
|
2017-07-22 01:51:27 +08:00
|
|
|
return C_RegisterClass;
|
|
|
|
break;
|
|
|
|
case 'a':
|
|
|
|
return C_RegisterClass;
|
|
|
|
default:
|
2016-05-18 22:34:51 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return TargetLowering::getConstraintType(Constraint);
|
|
|
|
}
|
|
|
|
|
2016-08-20 03:29:15 +08:00
|
|
|
std::pair<unsigned, const TargetRegisterClass*>
|
2015-02-27 06:38:43 +08:00
|
|
|
HexagonTargetLowering::getRegForInlineAsmConstraint(
|
2015-07-06 03:29:18 +08:00
|
|
|
const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const {
|
2015-11-27 02:38:27 +08:00
|
|
|
|
2011-12-13 05:14:40 +08:00
|
|
|
if (Constraint.size() == 1) {
|
|
|
|
switch (Constraint[0]) {
|
|
|
|
case 'r': // R0-R31
|
2016-08-20 03:29:15 +08:00
|
|
|
switch (VT.SimpleTy) {
|
|
|
|
default:
|
2017-10-21 04:24:44 +08:00
|
|
|
return {0u, nullptr};
|
2016-08-20 03:29:15 +08:00
|
|
|
case MVT::i1:
|
|
|
|
case MVT::i8:
|
|
|
|
case MVT::i16:
|
|
|
|
case MVT::i32:
|
|
|
|
case MVT::f32:
|
2017-10-21 04:24:44 +08:00
|
|
|
return {0u, &Hexagon::IntRegsRegClass};
|
2016-08-20 03:29:15 +08:00
|
|
|
case MVT::i64:
|
|
|
|
case MVT::f64:
|
2017-10-21 04:24:44 +08:00
|
|
|
return {0u, &Hexagon::DoubleRegsRegClass};
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
2017-07-22 01:51:27 +08:00
|
|
|
break;
|
|
|
|
case 'a': // M0-M1
|
2017-10-21 04:24:44 +08:00
|
|
|
if (VT != MVT::i32)
|
|
|
|
return {0u, nullptr};
|
|
|
|
return {0u, &Hexagon::ModRegsRegClass};
|
2015-11-27 02:38:27 +08:00
|
|
|
case 'q': // q0-q3
|
2017-03-03 01:50:24 +08:00
|
|
|
switch (VT.getSizeInBits()) {
|
2016-08-20 03:29:15 +08:00
|
|
|
default:
|
2017-10-21 04:24:44 +08:00
|
|
|
return {0u, nullptr};
|
2020-02-07 23:33:18 +08:00
|
|
|
case 64:
|
|
|
|
case 128:
|
2017-10-21 04:24:44 +08:00
|
|
|
return {0u, &Hexagon::HvxQRRegClass};
|
2016-08-20 03:29:15 +08:00
|
|
|
}
|
2017-07-22 01:51:27 +08:00
|
|
|
break;
|
2015-11-27 02:38:27 +08:00
|
|
|
case 'v': // V0-V31
|
2017-03-03 01:50:24 +08:00
|
|
|
switch (VT.getSizeInBits()) {
|
2016-08-20 03:29:15 +08:00
|
|
|
default:
|
2017-10-21 04:24:44 +08:00
|
|
|
return {0u, nullptr};
|
2017-03-03 01:50:24 +08:00
|
|
|
case 512:
|
2017-10-21 04:24:44 +08:00
|
|
|
return {0u, &Hexagon::HvxVRRegClass};
|
2017-03-03 01:50:24 +08:00
|
|
|
case 1024:
|
2018-06-20 21:56:09 +08:00
|
|
|
if (Subtarget.hasV60Ops() && Subtarget.useHVX128BOps())
|
2017-10-21 04:24:44 +08:00
|
|
|
return {0u, &Hexagon::HvxVRRegClass};
|
|
|
|
return {0u, &Hexagon::HvxWRRegClass};
|
2017-03-03 01:50:24 +08:00
|
|
|
case 2048:
|
2017-10-21 04:24:44 +08:00
|
|
|
return {0u, &Hexagon::HvxWRRegClass};
|
2016-08-20 03:29:15 +08:00
|
|
|
}
|
2017-07-22 01:51:27 +08:00
|
|
|
break;
|
2011-12-13 05:14:40 +08:00
|
|
|
default:
|
2017-10-21 04:24:44 +08:00
|
|
|
return {0u, nullptr};
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-02-27 06:38:43 +08:00
|
|
|
return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
|
2011-12-13 05:14:40 +08:00
|
|
|
}
|
|
|
|
|
2012-05-11 04:20:25 +08:00
|
|
|
/// isFPImmLegal - Returns true if the target can instruction select the
|
|
|
|
/// specified FP immediate natively. If false, the legalizer will
|
|
|
|
/// materialize the FP immediate as a load from a constant pool.
|
2019-03-19 02:40:07 +08:00
|
|
|
bool HexagonTargetLowering::isFPImmLegal(const APFloat &Imm, EVT VT,
|
|
|
|
bool ForCodeSize) const {
|
2018-10-20 01:31:11 +08:00
|
|
|
return true;
|
2012-05-11 04:20:25 +08:00
|
|
|
}
|
|
|
|
|
2011-12-13 05:14:40 +08:00
|
|
|
/// isLegalAddressingMode - Return true if the addressing mode represented by
|
|
|
|
/// AM is legal for this target, for a load/store of the specified type.
|
2015-07-09 10:09:40 +08:00
|
|
|
bool HexagonTargetLowering::isLegalAddressingMode(const DataLayout &DL,
|
|
|
|
const AddrMode &AM, Type *Ty,
|
2017-07-21 19:59:37 +08:00
|
|
|
unsigned AS, Instruction *I) const {
|
2016-08-03 23:06:18 +08:00
|
|
|
if (Ty->isSized()) {
|
|
|
|
// When LSR detects uses of the same base address to access different
|
|
|
|
// types (e.g. unions), it will assume a conservative type for these
|
|
|
|
// uses:
|
|
|
|
// LSR Use: Kind=Address of void in addrspace(4294967295), ...
|
|
|
|
// The type Ty passed here would then be "void". Skip the alignment
|
|
|
|
// checks, but do not return false right away, since that confuses
|
|
|
|
// LSR into crashing.
|
2020-07-02 19:28:01 +08:00
|
|
|
Align A = DL.getABITypeAlign(Ty);
|
2016-08-03 23:06:18 +08:00
|
|
|
// The base offset must be a multiple of the alignment.
|
2020-07-02 19:28:01 +08:00
|
|
|
if (!isAligned(A, AM.BaseOffs))
|
2016-08-03 23:06:18 +08:00
|
|
|
return false;
|
|
|
|
// The shifted offset must fit in 11 bits.
|
2020-07-02 19:28:01 +08:00
|
|
|
if (!isInt<11>(AM.BaseOffs >> Log2(A)))
|
2016-08-03 23:06:18 +08:00
|
|
|
return false;
|
|
|
|
}
|
2011-12-13 05:14:40 +08:00
|
|
|
|
|
|
|
// No global is ever allowed as a base.
|
2015-04-23 05:17:00 +08:00
|
|
|
if (AM.BaseGV)
|
2011-12-13 05:14:40 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
int Scale = AM.Scale;
|
2016-08-02 04:31:50 +08:00
|
|
|
if (Scale < 0)
|
|
|
|
Scale = -Scale;
|
2011-12-13 05:14:40 +08:00
|
|
|
switch (Scale) {
|
|
|
|
case 0: // No scale reg, "r+i", "r", or just "i".
|
|
|
|
break;
|
|
|
|
default: // No scaled addressing mode.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2015-12-19 04:19:30 +08:00
|
|
|
/// Return true if folding a constant offset with the given GlobalAddress is
|
|
|
|
/// legal. It is frequently not legal in PIC relocation models.
|
|
|
|
bool HexagonTargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA)
|
|
|
|
const {
|
|
|
|
return HTM.getRelocationModel() == Reloc::Static;
|
|
|
|
}
|
|
|
|
|
2011-12-13 05:14:40 +08:00
|
|
|
/// 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.
|
|
|
|
bool HexagonTargetLowering::isLegalICmpImmediate(int64_t Imm) const {
|
|
|
|
return Imm >= -512 && Imm <= 511;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// IsEligibleForTailCallOptimization - Check whether the call is eligible
|
|
|
|
/// for tail call optimization. Targets which want to do tail call
|
|
|
|
/// optimization should implement this function.
|
|
|
|
bool HexagonTargetLowering::IsEligibleForTailCallOptimization(
|
|
|
|
SDValue Callee,
|
|
|
|
CallingConv::ID CalleeCC,
|
2018-02-13 23:35:07 +08:00
|
|
|
bool IsVarArg,
|
|
|
|
bool IsCalleeStructRet,
|
|
|
|
bool IsCallerStructRet,
|
2011-12-13 05:14:40 +08:00
|
|
|
const SmallVectorImpl<ISD::OutputArg> &Outs,
|
|
|
|
const SmallVectorImpl<SDValue> &OutVals,
|
|
|
|
const SmallVectorImpl<ISD::InputArg> &Ins,
|
|
|
|
SelectionDAG& DAG) const {
|
2017-12-16 06:22:58 +08:00
|
|
|
const Function &CallerF = DAG.getMachineFunction().getFunction();
|
|
|
|
CallingConv::ID CallerCC = CallerF.getCallingConv();
|
2011-12-13 05:14:40 +08:00
|
|
|
bool CCMatch = CallerCC == CalleeCC;
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
|
|
// Look for obvious safe cases to perform tail call optimization that do not
|
|
|
|
// require ABI changes.
|
|
|
|
// ***************************************************************************
|
|
|
|
|
|
|
|
// If this is a tail call via a function pointer, then don't do it!
|
2016-08-02 04:31:50 +08:00
|
|
|
if (!isa<GlobalAddressSDNode>(Callee) &&
|
|
|
|
!isa<ExternalSymbolSDNode>(Callee)) {
|
2011-12-13 05:14:40 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2016-08-19 23:02:18 +08:00
|
|
|
// Do not optimize if the calling conventions do not match and the conventions
|
|
|
|
// used are not C or Fast.
|
|
|
|
if (!CCMatch) {
|
|
|
|
bool R = (CallerCC == CallingConv::C || CallerCC == CallingConv::Fast);
|
|
|
|
bool E = (CalleeCC == CallingConv::C || CalleeCC == CallingConv::Fast);
|
|
|
|
// If R & E, then ok.
|
|
|
|
if (!R || !E)
|
|
|
|
return false;
|
|
|
|
}
|
2011-12-13 05:14:40 +08:00
|
|
|
|
|
|
|
// Do not tail call optimize vararg calls.
|
2018-02-13 23:35:07 +08:00
|
|
|
if (IsVarArg)
|
2011-12-13 05:14:40 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// Also avoid tail call optimization if either caller or callee uses struct
|
|
|
|
// return semantics.
|
2018-02-13 23:35:07 +08:00
|
|
|
if (IsCalleeStructRet || IsCallerStructRet)
|
2011-12-13 05:14:40 +08:00
|
|
|
return false;
|
|
|
|
|
|
|
|
// In addition to the cases above, we also disable Tail Call Optimization if
|
|
|
|
// the calling convention code that at least one outgoing argument needs to
|
|
|
|
// go on the stack. We cannot check that here because at this point that
|
|
|
|
// information is not available.
|
|
|
|
return true;
|
|
|
|
}
|
2014-12-09 05:19:18 +08:00
|
|
|
|
2016-08-03 02:34:31 +08:00
|
|
|
/// Returns the target specific optimal type for load and store operations as
|
|
|
|
/// a result of memset, memcpy, and memmove lowering.
|
|
|
|
///
|
|
|
|
/// If DstAlign is zero that means it's safe to destination alignment can
|
|
|
|
/// satisfy any constraint. Similarly if SrcAlign is zero it means there isn't
|
|
|
|
/// a need to check it against alignment requirement, probably because the
|
|
|
|
/// source does not need to be loaded. If 'IsMemset' is true, that means it's
|
|
|
|
/// expanding a memset. If 'ZeroMemset' is true, that means it's a memset of
|
|
|
|
/// zero. 'MemcpyStrSrc' indicates whether the memcpy source is constant so it
|
|
|
|
/// does not need to be loaded. It returns EVT::Other if the type should be
|
|
|
|
/// determined using generic target-independent logic.
|
[NFC] Introduce a type to model memory operation
Summary: This is a first step before changing the types to llvm::Align and introduce functions to ease client code.
Reviewers: courbet
Subscribers: arsenm, sdardis, nemanjai, jvesely, nhaehnle, hiraditya, kbarton, jrtc27, atanasyan, jsji, kerbowa, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D73785
2020-01-31 22:40:31 +08:00
|
|
|
EVT HexagonTargetLowering::getOptimalMemOpType(
|
|
|
|
const MemOp &Op, const AttributeList &FuncAttributes) const {
|
2020-02-04 22:30:05 +08:00
|
|
|
if (Op.size() >= 8 && Op.isAligned(Align(8)))
|
2016-08-03 02:34:31 +08:00
|
|
|
return MVT::i64;
|
2020-02-04 22:30:05 +08:00
|
|
|
if (Op.size() >= 4 && Op.isAligned(Align(4)))
|
2016-08-03 02:34:31 +08:00
|
|
|
return MVT::i32;
|
2020-02-04 22:30:05 +08:00
|
|
|
if (Op.size() >= 2 && Op.isAligned(Align(2)))
|
2016-08-03 02:34:31 +08:00
|
|
|
return MVT::i16;
|
|
|
|
return MVT::Other;
|
|
|
|
}
|
|
|
|
|
2020-06-30 16:16:59 +08:00
|
|
|
bool HexagonTargetLowering::allowsMemoryAccess(
|
|
|
|
LLVMContext &Context, const DataLayout &DL, EVT VT, unsigned AddrSpace,
|
|
|
|
Align Alignment, MachineMemOperand::Flags Flags, bool *Fast) const {
|
2020-02-26 23:56:12 +08:00
|
|
|
MVT SVT = VT.getSimpleVT();
|
|
|
|
if (Subtarget.isHVXVectorType(SVT, true))
|
2020-06-30 16:16:59 +08:00
|
|
|
return allowsHvxMemoryAccess(SVT, Flags, Fast);
|
2020-02-26 23:56:12 +08:00
|
|
|
return TargetLoweringBase::allowsMemoryAccess(
|
|
|
|
Context, DL, VT, AddrSpace, Alignment, Flags, Fast);
|
|
|
|
}
|
|
|
|
|
2019-06-13 01:14:03 +08:00
|
|
|
bool HexagonTargetLowering::allowsMisalignedMemoryAccesses(
|
2021-02-05 11:22:04 +08:00
|
|
|
EVT VT, unsigned AddrSpace, Align Alignment, MachineMemOperand::Flags Flags,
|
|
|
|
bool *Fast) const {
|
2020-02-26 23:56:12 +08:00
|
|
|
MVT SVT = VT.getSimpleVT();
|
|
|
|
if (Subtarget.isHVXVectorType(SVT, true))
|
2020-06-30 16:16:59 +08:00
|
|
|
return allowsHvxMisalignedMemoryAccesses(SVT, Flags, Fast);
|
2016-03-28 23:43:03 +08:00
|
|
|
if (Fast)
|
|
|
|
*Fast = false;
|
2020-02-26 23:56:12 +08:00
|
|
|
return false;
|
2016-03-28 23:43:03 +08:00
|
|
|
}
|
|
|
|
|
2015-11-27 02:38:27 +08:00
|
|
|
std::pair<const TargetRegisterClass*, uint8_t>
|
|
|
|
HexagonTargetLowering::findRepresentativeClass(const TargetRegisterInfo *TRI,
|
|
|
|
MVT VT) const {
|
2018-02-13 23:35:07 +08:00
|
|
|
if (Subtarget.isHVXVectorType(VT, true)) {
|
|
|
|
unsigned BitWidth = VT.getSizeInBits();
|
|
|
|
unsigned VecWidth = Subtarget.getVectorLength() * 8;
|
2015-11-27 02:38:27 +08:00
|
|
|
|
2018-02-13 23:35:07 +08:00
|
|
|
if (VT.getVectorElementType() == MVT::i1)
|
|
|
|
return std::make_pair(&Hexagon::HvxQRRegClass, 1);
|
|
|
|
if (BitWidth == VecWidth)
|
|
|
|
return std::make_pair(&Hexagon::HvxVRRegClass, 1);
|
|
|
|
assert(BitWidth == 2 * VecWidth);
|
|
|
|
return std::make_pair(&Hexagon::HvxWRRegClass, 1);
|
2015-11-27 02:38:27 +08:00
|
|
|
}
|
2018-02-13 23:35:07 +08:00
|
|
|
|
|
|
|
return TargetLowering::findRepresentativeClass(TRI, VT);
|
2015-11-27 02:38:27 +08:00
|
|
|
}
|
|
|
|
|
2018-11-02 22:17:47 +08:00
|
|
|
bool HexagonTargetLowering::shouldReduceLoadWidth(SDNode *Load,
|
|
|
|
ISD::LoadExtType ExtTy, EVT NewVT) const {
|
[x86] allow vector load narrowing with multi-use values
This is a long-awaited follow-up suggested in D33578. Since then, we've picked up even more
opportunities for vector narrowing from changes like D53784, so there are a lot of test diffs.
Apart from 2-3 strange cases, these are all wins.
I've structured this to be no-functional-change-intended for any target except for x86
because I couldn't tell if AArch64, ARM, and AMDGPU would improve or not. All of those
targets have existing regression tests (4, 4, 10 files respectively) that would be
affected. Also, Hexagon overrides the shouldReduceLoadWidth() hook, but doesn't show
any regression test diffs. The trade-off is deciding if an extra vector load is better
than a single wide load + extract_subvector.
For x86, this is almost always better (on paper at least) because we often can fold
loads into subsequent ops and not increase the official instruction count. There's also
some unknown -- but potentially large -- benefit from using narrower vector ops if wide
ops are implemented with multiple uops and/or frequency throttling is avoided.
Differential Revision: https://reviews.llvm.org/D54073
llvm-svn: 346595
2018-11-11 04:05:31 +08:00
|
|
|
// TODO: This may be worth removing. Check regression tests for diffs.
|
|
|
|
if (!TargetLoweringBase::shouldReduceLoadWidth(Load, ExtTy, NewVT))
|
|
|
|
return false;
|
|
|
|
|
2018-11-02 22:17:47 +08:00
|
|
|
auto *L = cast<LoadSDNode>(Load);
|
|
|
|
std::pair<SDValue,int> BO = getBaseAndOffset(L->getBasePtr());
|
|
|
|
// Small-data object, do not shrink.
|
|
|
|
if (BO.first.getOpcode() == HexagonISD::CONST32_GP)
|
|
|
|
return false;
|
|
|
|
if (GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(BO.first)) {
|
|
|
|
auto &HTM = static_cast<const HexagonTargetMachine&>(getTargetMachine());
|
|
|
|
const auto *GO = dyn_cast_or_null<const GlobalObject>(GA->getGlobal());
|
|
|
|
return !GO || !HTM.getObjFileLowering()->isGlobalInSmallSection(GO, HTM);
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2021-06-06 04:56:19 +08:00
|
|
|
Value *HexagonTargetLowering::emitLoadLinked(IRBuilderBase &Builder,
|
2021-07-02 23:20:41 +08:00
|
|
|
Type *ValueTy, Value *Addr,
|
2021-06-06 04:56:19 +08:00
|
|
|
AtomicOrdering Ord) const {
|
2015-07-09 22:51:21 +08:00
|
|
|
BasicBlock *BB = Builder.GetInsertBlock();
|
|
|
|
Module *M = BB->getParent()->getParent();
|
2021-07-02 23:20:41 +08:00
|
|
|
unsigned SZ = ValueTy->getPrimitiveSizeInBits();
|
2015-07-09 22:51:21 +08:00
|
|
|
assert((SZ == 32 || SZ == 64) && "Only 32/64-bit atomic loads supported");
|
|
|
|
Intrinsic::ID IntID = (SZ == 32) ? Intrinsic::hexagon_L2_loadw_locked
|
|
|
|
: Intrinsic::hexagon_L4_loadd_locked;
|
2019-02-02 04:43:25 +08:00
|
|
|
Function *Fn = Intrinsic::getDeclaration(M, IntID);
|
2019-01-23 02:18:02 +08:00
|
|
|
|
2021-07-02 23:20:41 +08:00
|
|
|
auto PtrTy = cast<PointerType>(Addr->getType());
|
|
|
|
PointerType *NewPtrTy =
|
|
|
|
Builder.getIntNTy(SZ)->getPointerTo(PtrTy->getAddressSpace());
|
2019-01-23 02:18:02 +08:00
|
|
|
Addr = Builder.CreateBitCast(Addr, NewPtrTy);
|
|
|
|
|
|
|
|
Value *Call = Builder.CreateCall(Fn, Addr, "larx");
|
|
|
|
|
2021-07-02 23:20:41 +08:00
|
|
|
return Builder.CreateBitCast(Call, ValueTy);
|
2015-07-09 22:51:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Perform a store-conditional operation to Addr. Return the status of the
|
|
|
|
/// store. This should be 0 if the store succeeded, non-zero otherwise.
|
2021-06-06 04:56:19 +08:00
|
|
|
Value *HexagonTargetLowering::emitStoreConditional(IRBuilderBase &Builder,
|
|
|
|
Value *Val, Value *Addr,
|
|
|
|
AtomicOrdering Ord) const {
|
2015-07-09 22:51:21 +08:00
|
|
|
BasicBlock *BB = Builder.GetInsertBlock();
|
|
|
|
Module *M = BB->getParent()->getParent();
|
|
|
|
Type *Ty = Val->getType();
|
|
|
|
unsigned SZ = Ty->getPrimitiveSizeInBits();
|
2019-01-23 02:18:02 +08:00
|
|
|
|
|
|
|
Type *CastTy = Builder.getIntNTy(SZ);
|
2015-07-09 22:51:21 +08:00
|
|
|
assert((SZ == 32 || SZ == 64) && "Only 32/64-bit atomic stores supported");
|
|
|
|
Intrinsic::ID IntID = (SZ == 32) ? Intrinsic::hexagon_S2_storew_locked
|
|
|
|
: Intrinsic::hexagon_S4_stored_locked;
|
2019-02-02 04:43:25 +08:00
|
|
|
Function *Fn = Intrinsic::getDeclaration(M, IntID);
|
2019-01-23 02:18:02 +08:00
|
|
|
|
|
|
|
unsigned AS = Addr->getType()->getPointerAddressSpace();
|
|
|
|
Addr = Builder.CreateBitCast(Addr, CastTy->getPointerTo(AS));
|
|
|
|
Val = Builder.CreateBitCast(Val, CastTy);
|
|
|
|
|
2015-07-09 22:51:21 +08:00
|
|
|
Value *Call = Builder.CreateCall(Fn, {Addr, Val}, "stcx");
|
|
|
|
Value *Cmp = Builder.CreateICmpEQ(Call, Builder.getInt32(0), "");
|
|
|
|
Value *Ext = Builder.CreateZExt(Cmp, Type::getInt32Ty(M->getContext()));
|
|
|
|
return Ext;
|
|
|
|
}
|
|
|
|
|
2015-09-12 01:08:28 +08:00
|
|
|
TargetLowering::AtomicExpansionKind
|
|
|
|
HexagonTargetLowering::shouldExpandAtomicLoadInIR(LoadInst *LI) const {
|
2015-07-09 22:51:21 +08:00
|
|
|
// Do not expand loads and stores that don't exceed 64 bits.
|
2015-09-12 01:08:28 +08:00
|
|
|
return LI->getType()->getPrimitiveSizeInBits() > 64
|
2015-12-03 02:12:57 +08:00
|
|
|
? AtomicExpansionKind::LLOnly
|
2015-09-12 01:08:28 +08:00
|
|
|
: AtomicExpansionKind::None;
|
2015-07-09 22:51:21 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
bool HexagonTargetLowering::shouldExpandAtomicStoreInIR(StoreInst *SI) const {
|
|
|
|
// Do not expand loads and stores that don't exceed 64 bits.
|
|
|
|
return SI->getValueOperand()->getType()->getPrimitiveSizeInBits() > 64;
|
|
|
|
}
|
2016-06-23 00:07:10 +08:00
|
|
|
|
2018-09-19 22:51:42 +08:00
|
|
|
TargetLowering::AtomicExpansionKind
|
|
|
|
HexagonTargetLowering::shouldExpandAtomicCmpXchgInIR(
|
|
|
|
AtomicCmpXchgInst *AI) const {
|
2020-03-24 01:47:32 +08:00
|
|
|
return AtomicExpansionKind::LLSC;
|
2016-06-23 00:07:10 +08:00
|
|
|
}
|