2016-10-15 06:18:18 +08:00
|
|
|
//===-- llvm/CodeGen/GlobalISel/LegalizerHelper.cpp -----------------------===//
|
2016-07-23 04:03:43 +08:00
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
2016-10-15 06:18:18 +08:00
|
|
|
/// \file This file implements the LegalizerHelper class to legalize
|
2016-07-23 04:03:43 +08:00
|
|
|
/// individual instructions and the LegalizeMachineIR wrapper pass for the
|
|
|
|
/// primary legalization.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2016-10-15 06:18:18 +08:00
|
|
|
#include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"
|
2016-08-30 03:07:16 +08:00
|
|
|
#include "llvm/CodeGen/GlobalISel/CallLowering.h"
|
2016-10-15 06:18:18 +08:00
|
|
|
#include "llvm/CodeGen/GlobalISel/LegalizerInfo.h"
|
2016-07-23 04:03:43 +08:00
|
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
2017-11-17 09:07:10 +08:00
|
|
|
#include "llvm/CodeGen/TargetLowering.h"
|
|
|
|
#include "llvm/CodeGen/TargetSubtargetInfo.h"
|
2016-07-23 04:03:43 +08:00
|
|
|
#include "llvm/Support/Debug.h"
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
|
|
|
|
|
|
|
|
2017-04-20 23:46:12 +08:00
|
|
|
#define DEBUG_TYPE "legalizer"
|
2016-07-23 04:03:43 +08:00
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
2016-10-15 06:18:18 +08:00
|
|
|
LegalizerHelper::LegalizerHelper(MachineFunction &MF)
|
[GlobalISel] Make LegalizerInfo accessible in LegalizerHelper
Summary:
We don’t actually use LegalizerInfo in Legalizer pass, it’s just passed
as an argument.
In order to check if an instruction is legal or not, we need to get LegalizerInfo
by calling `MI.getParent()->getParent()->getSubtarget().getLegalizerInfo()`.
Instead, make LegalizerInfo accessible in LegalizerHelper.
Reviewers: qcolombet, aditya_nandakumar, dsanders, ab, t.p.northover, kristof.beyls
Reviewed By: qcolombet
Subscribers: dberris, llvm-commits, rovka
Differential Revision: https://reviews.llvm.org/D30838
llvm-svn: 297491
2017-03-11 02:34:57 +08:00
|
|
|
: MRI(MF.getRegInfo()), LI(*MF.getSubtarget().getLegalizerInfo()) {
|
2016-07-23 04:03:43 +08:00
|
|
|
MIRBuilder.setMF(MF);
|
|
|
|
}
|
|
|
|
|
2016-10-15 06:18:18 +08:00
|
|
|
LegalizerHelper::LegalizeResult
|
[GlobalISel] Make LegalizerInfo accessible in LegalizerHelper
Summary:
We don’t actually use LegalizerInfo in Legalizer pass, it’s just passed
as an argument.
In order to check if an instruction is legal or not, we need to get LegalizerInfo
by calling `MI.getParent()->getParent()->getSubtarget().getLegalizerInfo()`.
Instead, make LegalizerInfo accessible in LegalizerHelper.
Reviewers: qcolombet, aditya_nandakumar, dsanders, ab, t.p.northover, kristof.beyls
Reviewed By: qcolombet
Subscribers: dberris, llvm-commits, rovka
Differential Revision: https://reviews.llvm.org/D30838
llvm-svn: 297491
2017-03-11 02:34:57 +08:00
|
|
|
LegalizerHelper::legalizeInstrStep(MachineInstr &MI) {
|
2017-04-20 23:46:12 +08:00
|
|
|
DEBUG(dbgs() << "Legalizing: "; MI.print(dbgs()));
|
|
|
|
|
[GlobalISel] Make LegalizerInfo accessible in LegalizerHelper
Summary:
We don’t actually use LegalizerInfo in Legalizer pass, it’s just passed
as an argument.
In order to check if an instruction is legal or not, we need to get LegalizerInfo
by calling `MI.getParent()->getParent()->getSubtarget().getLegalizerInfo()`.
Instead, make LegalizerInfo accessible in LegalizerHelper.
Reviewers: qcolombet, aditya_nandakumar, dsanders, ab, t.p.northover, kristof.beyls
Reviewed By: qcolombet
Subscribers: dberris, llvm-commits, rovka
Differential Revision: https://reviews.llvm.org/D30838
llvm-svn: 297491
2017-03-11 02:34:57 +08:00
|
|
|
auto Action = LI.getAction(MI, MRI);
|
2016-08-24 03:30:42 +08:00
|
|
|
switch (std::get<0>(Action)) {
|
2016-10-15 06:18:18 +08:00
|
|
|
case LegalizerInfo::Legal:
|
2017-04-20 23:46:12 +08:00
|
|
|
DEBUG(dbgs() << ".. Already legal\n");
|
2016-07-23 04:03:43 +08:00
|
|
|
return AlreadyLegal;
|
2016-10-15 06:18:18 +08:00
|
|
|
case LegalizerInfo::Libcall:
|
2017-04-20 23:46:12 +08:00
|
|
|
DEBUG(dbgs() << ".. Convert to libcall\n");
|
2016-08-30 03:07:16 +08:00
|
|
|
return libcall(MI);
|
2016-10-15 06:18:18 +08:00
|
|
|
case LegalizerInfo::NarrowScalar:
|
2017-04-20 23:46:12 +08:00
|
|
|
DEBUG(dbgs() << ".. Narrow scalar\n");
|
2016-08-24 03:30:42 +08:00
|
|
|
return narrowScalar(MI, std::get<1>(Action), std::get<2>(Action));
|
2016-10-15 06:18:18 +08:00
|
|
|
case LegalizerInfo::WidenScalar:
|
2017-04-20 23:46:12 +08:00
|
|
|
DEBUG(dbgs() << ".. Widen scalar\n");
|
2016-08-24 03:30:42 +08:00
|
|
|
return widenScalar(MI, std::get<1>(Action), std::get<2>(Action));
|
2016-10-15 06:18:18 +08:00
|
|
|
case LegalizerInfo::Lower:
|
2017-04-20 23:46:12 +08:00
|
|
|
DEBUG(dbgs() << ".. Lower\n");
|
2016-08-27 01:46:13 +08:00
|
|
|
return lower(MI, std::get<1>(Action), std::get<2>(Action));
|
2016-10-15 06:18:18 +08:00
|
|
|
case LegalizerInfo::FewerElements:
|
2017-04-20 23:46:12 +08:00
|
|
|
DEBUG(dbgs() << ".. Reduce number of elements\n");
|
2016-08-24 03:30:42 +08:00
|
|
|
return fewerElementsVector(MI, std::get<1>(Action), std::get<2>(Action));
|
2017-02-16 07:22:50 +08:00
|
|
|
case LegalizerInfo::Custom:
|
2017-04-20 23:46:12 +08:00
|
|
|
DEBUG(dbgs() << ".. Custom legalization\n");
|
[GlobalISel] Make LegalizerInfo accessible in LegalizerHelper
Summary:
We don’t actually use LegalizerInfo in Legalizer pass, it’s just passed
as an argument.
In order to check if an instruction is legal or not, we need to get LegalizerInfo
by calling `MI.getParent()->getParent()->getSubtarget().getLegalizerInfo()`.
Instead, make LegalizerInfo accessible in LegalizerHelper.
Reviewers: qcolombet, aditya_nandakumar, dsanders, ab, t.p.northover, kristof.beyls
Reviewed By: qcolombet
Subscribers: dberris, llvm-commits, rovka
Differential Revision: https://reviews.llvm.org/D30838
llvm-svn: 297491
2017-03-11 02:34:57 +08:00
|
|
|
return LI.legalizeCustom(MI, MRI, MIRBuilder) ? Legalized
|
|
|
|
: UnableToLegalize;
|
2016-07-23 04:03:43 +08:00
|
|
|
default:
|
2017-04-20 23:46:12 +08:00
|
|
|
DEBUG(dbgs() << ".. Unable to legalize\n");
|
2016-07-23 04:03:43 +08:00
|
|
|
return UnableToLegalize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-15 06:18:18 +08:00
|
|
|
void LegalizerHelper::extractParts(unsigned Reg, LLT Ty, int NumParts,
|
|
|
|
SmallVectorImpl<unsigned> &VRegs) {
|
2017-03-04 06:46:09 +08:00
|
|
|
for (int i = 0; i < NumParts; ++i)
|
2016-09-09 19:46:34 +08:00
|
|
|
VRegs.push_back(MRI.createGenericVirtualRegister(Ty));
|
2017-03-04 06:46:09 +08:00
|
|
|
MIRBuilder.buildUnmerge(VRegs, Reg);
|
2016-07-23 04:03:43 +08:00
|
|
|
}
|
|
|
|
|
2017-02-09 07:23:39 +08:00
|
|
|
static RTLIB::Libcall getRTLibDesc(unsigned Opcode, unsigned Size) {
|
|
|
|
switch (Opcode) {
|
2017-04-24 15:22:31 +08:00
|
|
|
case TargetOpcode::G_SDIV:
|
|
|
|
assert(Size == 32 && "Unsupported size");
|
|
|
|
return RTLIB::SDIV_I32;
|
|
|
|
case TargetOpcode::G_UDIV:
|
|
|
|
assert(Size == 32 && "Unsupported size");
|
|
|
|
return RTLIB::UDIV_I32;
|
2017-06-15 18:53:31 +08:00
|
|
|
case TargetOpcode::G_SREM:
|
|
|
|
assert(Size == 32 && "Unsupported size");
|
|
|
|
return RTLIB::SREM_I32;
|
|
|
|
case TargetOpcode::G_UREM:
|
|
|
|
assert(Size == 32 && "Unsupported size");
|
|
|
|
return RTLIB::UREM_I32;
|
2017-04-11 18:52:34 +08:00
|
|
|
case TargetOpcode::G_FADD:
|
|
|
|
assert((Size == 32 || Size == 64) && "Unsupported size");
|
|
|
|
return Size == 64 ? RTLIB::ADD_F64 : RTLIB::ADD_F32;
|
2017-10-30 21:51:56 +08:00
|
|
|
case TargetOpcode::G_FSUB:
|
|
|
|
assert((Size == 32 || Size == 64) && "Unsupported size");
|
|
|
|
return Size == 64 ? RTLIB::SUB_F64 : RTLIB::SUB_F32;
|
2017-11-23 20:44:20 +08:00
|
|
|
case TargetOpcode::G_FMUL:
|
|
|
|
assert((Size == 32 || Size == 64) && "Unsupported size");
|
|
|
|
return Size == 64 ? RTLIB::MUL_F64 : RTLIB::MUL_F32;
|
2017-11-23 21:26:07 +08:00
|
|
|
case TargetOpcode::G_FDIV:
|
|
|
|
assert((Size == 32 || Size == 64) && "Unsupported size");
|
|
|
|
return Size == 64 ? RTLIB::DIV_F64 : RTLIB::DIV_F32;
|
2017-02-09 07:23:39 +08:00
|
|
|
case TargetOpcode::G_FREM:
|
|
|
|
return Size == 64 ? RTLIB::REM_F64 : RTLIB::REM_F32;
|
|
|
|
case TargetOpcode::G_FPOW:
|
|
|
|
return Size == 64 ? RTLIB::POW_F64 : RTLIB::POW_F32;
|
|
|
|
}
|
|
|
|
llvm_unreachable("Unknown libcall function");
|
|
|
|
}
|
|
|
|
|
2017-07-05 20:57:24 +08:00
|
|
|
LegalizerHelper::LegalizeResult
|
|
|
|
llvm::createLibcall(MachineIRBuilder &MIRBuilder, RTLIB::Libcall Libcall,
|
|
|
|
const CallLowering::ArgInfo &Result,
|
|
|
|
ArrayRef<CallLowering::ArgInfo> Args) {
|
2017-04-24 15:22:31 +08:00
|
|
|
auto &CLI = *MIRBuilder.getMF().getSubtarget().getCallLowering();
|
|
|
|
auto &TLI = *MIRBuilder.getMF().getSubtarget().getTargetLowering();
|
|
|
|
const char *Name = TLI.getLibcallName(Libcall);
|
2017-07-06 17:09:33 +08:00
|
|
|
|
2017-04-24 15:22:31 +08:00
|
|
|
MIRBuilder.getMF().getFrameInfo().setHasCalls(true);
|
2017-06-15 18:53:31 +08:00
|
|
|
if (!CLI.lowerCall(MIRBuilder, TLI.getLibcallCallingConv(Libcall),
|
|
|
|
MachineOperand::CreateES(Name), Result, Args))
|
|
|
|
return LegalizerHelper::UnableToLegalize;
|
2017-07-06 17:09:33 +08:00
|
|
|
|
2017-04-24 15:22:31 +08:00
|
|
|
return LegalizerHelper::Legalized;
|
|
|
|
}
|
|
|
|
|
2017-06-15 18:53:31 +08:00
|
|
|
static LegalizerHelper::LegalizeResult
|
|
|
|
simpleLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder, unsigned Size,
|
|
|
|
Type *OpType) {
|
|
|
|
auto Libcall = getRTLibDesc(MI.getOpcode(), Size);
|
2017-07-05 20:57:24 +08:00
|
|
|
return createLibcall(MIRBuilder, Libcall, {MI.getOperand(0).getReg(), OpType},
|
|
|
|
{{MI.getOperand(1).getReg(), OpType},
|
|
|
|
{MI.getOperand(2).getReg(), OpType}});
|
2017-06-15 18:53:31 +08:00
|
|
|
}
|
|
|
|
|
2016-10-15 06:18:18 +08:00
|
|
|
LegalizerHelper::LegalizeResult
|
|
|
|
LegalizerHelper::libcall(MachineInstr &MI) {
|
2017-06-15 18:53:31 +08:00
|
|
|
LLT LLTy = MRI.getType(MI.getOperand(0).getReg());
|
|
|
|
unsigned Size = LLTy.getSizeInBits();
|
2017-04-24 15:22:31 +08:00
|
|
|
auto &Ctx = MIRBuilder.getMF().getFunction()->getContext();
|
2016-08-30 03:07:16 +08:00
|
|
|
|
2017-07-05 20:57:24 +08:00
|
|
|
MIRBuilder.setInstr(MI);
|
|
|
|
|
2016-08-30 03:07:16 +08:00
|
|
|
switch (MI.getOpcode()) {
|
|
|
|
default:
|
|
|
|
return UnableToLegalize;
|
2017-04-24 15:22:31 +08:00
|
|
|
case TargetOpcode::G_SDIV:
|
2017-06-15 18:53:31 +08:00
|
|
|
case TargetOpcode::G_UDIV:
|
|
|
|
case TargetOpcode::G_SREM:
|
|
|
|
case TargetOpcode::G_UREM: {
|
|
|
|
Type *HLTy = Type::getInt32Ty(Ctx);
|
2017-07-05 20:57:24 +08:00
|
|
|
auto Status = simpleLibcall(MI, MIRBuilder, Size, HLTy);
|
|
|
|
if (Status != Legalized)
|
|
|
|
return Status;
|
|
|
|
break;
|
2017-04-24 15:22:31 +08:00
|
|
|
}
|
2017-04-11 18:52:34 +08:00
|
|
|
case TargetOpcode::G_FADD:
|
2017-10-30 21:51:56 +08:00
|
|
|
case TargetOpcode::G_FSUB:
|
2017-11-23 20:44:20 +08:00
|
|
|
case TargetOpcode::G_FMUL:
|
2017-11-23 21:26:07 +08:00
|
|
|
case TargetOpcode::G_FDIV:
|
2017-02-09 07:23:39 +08:00
|
|
|
case TargetOpcode::G_FPOW:
|
2016-08-30 03:07:16 +08:00
|
|
|
case TargetOpcode::G_FREM: {
|
2017-06-15 18:53:31 +08:00
|
|
|
Type *HLTy = Size == 64 ? Type::getDoubleTy(Ctx) : Type::getFloatTy(Ctx);
|
2017-07-05 20:57:24 +08:00
|
|
|
auto Status = simpleLibcall(MI, MIRBuilder, Size, HLTy);
|
|
|
|
if (Status != Legalized)
|
|
|
|
return Status;
|
|
|
|
break;
|
2016-08-30 03:07:16 +08:00
|
|
|
}
|
|
|
|
}
|
2017-07-05 20:57:24 +08:00
|
|
|
|
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
2016-08-30 03:07:16 +08:00
|
|
|
}
|
|
|
|
|
2016-10-15 06:18:18 +08:00
|
|
|
LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI,
|
|
|
|
unsigned TypeIdx,
|
|
|
|
LLT NarrowTy) {
|
2016-08-27 10:38:21 +08:00
|
|
|
// FIXME: Don't know how to handle secondary types yet.
|
2017-06-27 04:34:13 +08:00
|
|
|
if (TypeIdx != 0 && MI.getOpcode() != TargetOpcode::G_EXTRACT)
|
2016-08-27 10:38:21 +08:00
|
|
|
return UnableToLegalize;
|
2017-01-19 01:29:54 +08:00
|
|
|
|
|
|
|
MIRBuilder.setInstr(MI);
|
|
|
|
|
[GlobalISel] Enable legalizing non-power-of-2 sized types.
This changes the interface of how targets describe how to legalize, see
the below description.
1. Interface for targets to describe how to legalize.
In GlobalISel, the API in the LegalizerInfo class is the main interface
for targets to specify which types are legal for which operations, and
what to do to turn illegal type/operation combinations into legal ones.
For each operation the type sizes that can be legalized without having
to change the size of the type are specified with a call to setAction.
This isn't different to how GlobalISel worked before. For example, for a
target that supports 32 and 64 bit adds natively:
for (auto Ty : {s32, s64})
setAction({G_ADD, 0, s32}, Legal);
or for a target that needs a library call for a 32 bit division:
setAction({G_SDIV, s32}, Libcall);
The main conceptual change to the LegalizerInfo API, is in specifying
how to legalize the type sizes for which a change of size is needed. For
example, in the above example, how to specify how all types from i1 to
i8388607 (apart from s32 and s64 which are legal) need to be legalized
and expressed in terms of operations on the available legal sizes
(again, i32 and i64 in this case). Before, the implementation only
allowed specifying power-of-2-sized types (e.g. setAction({G_ADD, 0,
s128}, NarrowScalar). A worse limitation was that if you'd wanted to
specify how to legalize all the sized types as allowed by the LLVM-IR
LangRef, i1 to i8388607, you'd have to call setAction 8388607-3 times
and probably would need a lot of memory to store all of these
specifications.
Instead, the legalization actions that need to change the size of the
type are specified now using a "SizeChangeStrategy". For example:
setLegalizeScalarToDifferentSizeStrategy(
G_ADD, 0, widenToLargerAndNarrowToLargest);
This example indicates that for type sizes for which there is a larger
size that can be legalized towards, do it by Widening the size.
For example, G_ADD on s17 will be legalized by first doing WidenScalar
to make it s32, after which it's legal.
The "NarrowToLargest" indicates what to do if there is no larger size
that can be legalized towards. E.g. G_ADD on s92 will be legalized by
doing NarrowScalar to s64.
Another example, taken from the ARM backend is:
for (unsigned Op : {G_SDIV, G_UDIV}) {
setLegalizeScalarToDifferentSizeStrategy(Op, 0,
widenToLargerTypesUnsupportedOtherwise);
if (ST.hasDivideInARMMode())
setAction({Op, s32}, Legal);
else
setAction({Op, s32}, Libcall);
}
For this example, G_SDIV on s8, on a target without a divide
instruction, would be legalized by first doing action (WidenScalar,
s32), followed by (Libcall, s32).
The same principle is also followed for when the number of vector lanes
on vector data types need to be changed, e.g.:
setAction({G_ADD, LLT::vector(8, 8)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(16, 8)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(4, 16)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(8, 16)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(2, 32)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(4, 32)}, LegalizerInfo::Legal);
setLegalizeVectorElementToDifferentSizeStrategy(
G_ADD, 0, widenToLargerTypesUnsupportedOtherwise);
As currently implemented here, vector types are legalized by first
making the vector element size legal, followed by then making the number
of lanes legal. The strategy to follow in the first step is set by a
call to setLegalizeVectorElementToDifferentSizeStrategy, see example
above. The strategy followed in the second step
"moreToWiderTypesAndLessToWidest" (see code for its definition),
indicating that vectors are widened to more elements so they map to
natively supported vector widths, or when there isn't a legal wider
vector, split the vector to map it to the widest vector supported.
Therefore, for the above specification, some example legalizations are:
* getAction({G_ADD, LLT::vector(3, 3)})
returns {WidenScalar, LLT::vector(3, 8)}
* getAction({G_ADD, LLT::vector(3, 8)})
then returns {MoreElements, LLT::vector(8, 8)}
* getAction({G_ADD, LLT::vector(20, 8)})
returns {FewerElements, LLT::vector(16, 8)}
2. Key implementation aspects.
How to legalize a specific (operation, type index, size) tuple is
represented by mapping intervals of integers representing a range of
size types to an action to take, e.g.:
setScalarAction({G_ADD, LLT:scalar(1)},
{{1, WidenScalar}, // bit sizes [ 1, 31[
{32, Legal}, // bit sizes [32, 33[
{33, WidenScalar}, // bit sizes [33, 64[
{64, Legal}, // bit sizes [64, 65[
{65, NarrowScalar} // bit sizes [65, +inf[
});
Please note that most of the code to do the actual lowering of
non-power-of-2 sized types is currently missing, this is just trying to
make it possible for targets to specify what is legal, and how non-legal
types should be legalized. Probably quite a bit of further work is
needed in the actual legalizing and the other passes in GlobalISel to
support non-power-of-2 sized types.
I hope the documentation in LegalizerInfo.h and the examples provided in the
various {Target}LegalizerInfo.cpp and LegalizerInfoTest.cpp explains well
enough how this is meant to be used.
This drops the need for LLT::{half,double}...Size().
Differential Revision: https://reviews.llvm.org/D30529
llvm-svn: 317560
2017-11-07 18:34:34 +08:00
|
|
|
int64_t SizeOp0 = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
|
|
|
|
int64_t NarrowSize = NarrowTy.getSizeInBits();
|
|
|
|
|
2016-08-05 04:54:13 +08:00
|
|
|
switch (MI.getOpcode()) {
|
|
|
|
default:
|
|
|
|
return UnableToLegalize;
|
2017-07-01 04:27:36 +08:00
|
|
|
case TargetOpcode::G_IMPLICIT_DEF: {
|
[GlobalISel] Enable legalizing non-power-of-2 sized types.
This changes the interface of how targets describe how to legalize, see
the below description.
1. Interface for targets to describe how to legalize.
In GlobalISel, the API in the LegalizerInfo class is the main interface
for targets to specify which types are legal for which operations, and
what to do to turn illegal type/operation combinations into legal ones.
For each operation the type sizes that can be legalized without having
to change the size of the type are specified with a call to setAction.
This isn't different to how GlobalISel worked before. For example, for a
target that supports 32 and 64 bit adds natively:
for (auto Ty : {s32, s64})
setAction({G_ADD, 0, s32}, Legal);
or for a target that needs a library call for a 32 bit division:
setAction({G_SDIV, s32}, Libcall);
The main conceptual change to the LegalizerInfo API, is in specifying
how to legalize the type sizes for which a change of size is needed. For
example, in the above example, how to specify how all types from i1 to
i8388607 (apart from s32 and s64 which are legal) need to be legalized
and expressed in terms of operations on the available legal sizes
(again, i32 and i64 in this case). Before, the implementation only
allowed specifying power-of-2-sized types (e.g. setAction({G_ADD, 0,
s128}, NarrowScalar). A worse limitation was that if you'd wanted to
specify how to legalize all the sized types as allowed by the LLVM-IR
LangRef, i1 to i8388607, you'd have to call setAction 8388607-3 times
and probably would need a lot of memory to store all of these
specifications.
Instead, the legalization actions that need to change the size of the
type are specified now using a "SizeChangeStrategy". For example:
setLegalizeScalarToDifferentSizeStrategy(
G_ADD, 0, widenToLargerAndNarrowToLargest);
This example indicates that for type sizes for which there is a larger
size that can be legalized towards, do it by Widening the size.
For example, G_ADD on s17 will be legalized by first doing WidenScalar
to make it s32, after which it's legal.
The "NarrowToLargest" indicates what to do if there is no larger size
that can be legalized towards. E.g. G_ADD on s92 will be legalized by
doing NarrowScalar to s64.
Another example, taken from the ARM backend is:
for (unsigned Op : {G_SDIV, G_UDIV}) {
setLegalizeScalarToDifferentSizeStrategy(Op, 0,
widenToLargerTypesUnsupportedOtherwise);
if (ST.hasDivideInARMMode())
setAction({Op, s32}, Legal);
else
setAction({Op, s32}, Libcall);
}
For this example, G_SDIV on s8, on a target without a divide
instruction, would be legalized by first doing action (WidenScalar,
s32), followed by (Libcall, s32).
The same principle is also followed for when the number of vector lanes
on vector data types need to be changed, e.g.:
setAction({G_ADD, LLT::vector(8, 8)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(16, 8)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(4, 16)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(8, 16)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(2, 32)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(4, 32)}, LegalizerInfo::Legal);
setLegalizeVectorElementToDifferentSizeStrategy(
G_ADD, 0, widenToLargerTypesUnsupportedOtherwise);
As currently implemented here, vector types are legalized by first
making the vector element size legal, followed by then making the number
of lanes legal. The strategy to follow in the first step is set by a
call to setLegalizeVectorElementToDifferentSizeStrategy, see example
above. The strategy followed in the second step
"moreToWiderTypesAndLessToWidest" (see code for its definition),
indicating that vectors are widened to more elements so they map to
natively supported vector widths, or when there isn't a legal wider
vector, split the vector to map it to the widest vector supported.
Therefore, for the above specification, some example legalizations are:
* getAction({G_ADD, LLT::vector(3, 3)})
returns {WidenScalar, LLT::vector(3, 8)}
* getAction({G_ADD, LLT::vector(3, 8)})
then returns {MoreElements, LLT::vector(8, 8)}
* getAction({G_ADD, LLT::vector(20, 8)})
returns {FewerElements, LLT::vector(16, 8)}
2. Key implementation aspects.
How to legalize a specific (operation, type index, size) tuple is
represented by mapping intervals of integers representing a range of
size types to an action to take, e.g.:
setScalarAction({G_ADD, LLT:scalar(1)},
{{1, WidenScalar}, // bit sizes [ 1, 31[
{32, Legal}, // bit sizes [32, 33[
{33, WidenScalar}, // bit sizes [33, 64[
{64, Legal}, // bit sizes [64, 65[
{65, NarrowScalar} // bit sizes [65, +inf[
});
Please note that most of the code to do the actual lowering of
non-power-of-2 sized types is currently missing, this is just trying to
make it possible for targets to specify what is legal, and how non-legal
types should be legalized. Probably quite a bit of further work is
needed in the actual legalizing and the other passes in GlobalISel to
support non-power-of-2 sized types.
I hope the documentation in LegalizerInfo.h and the examples provided in the
various {Target}LegalizerInfo.cpp and LegalizerInfoTest.cpp explains well
enough how this is meant to be used.
This drops the need for LLT::{half,double}...Size().
Differential Revision: https://reviews.llvm.org/D30529
llvm-svn: 317560
2017-11-07 18:34:34 +08:00
|
|
|
// FIXME: add support for when SizeOp0 isn't an exact multiple of
|
|
|
|
// NarrowSize.
|
|
|
|
if (SizeOp0 % NarrowSize != 0)
|
|
|
|
return UnableToLegalize;
|
|
|
|
int NumParts = SizeOp0 / NarrowSize;
|
2017-07-01 04:27:36 +08:00
|
|
|
|
|
|
|
SmallVector<unsigned, 2> DstRegs;
|
|
|
|
for (int i = 0; i < NumParts; ++i) {
|
|
|
|
unsigned Dst = MRI.createGenericVirtualRegister(NarrowTy);
|
|
|
|
MIRBuilder.buildUndef(Dst);
|
|
|
|
DstRegs.push_back(Dst);
|
|
|
|
}
|
|
|
|
MIRBuilder.buildMerge(MI.getOperand(0).getReg(), DstRegs);
|
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2016-08-05 04:54:13 +08:00
|
|
|
case TargetOpcode::G_ADD: {
|
[GlobalISel] Enable legalizing non-power-of-2 sized types.
This changes the interface of how targets describe how to legalize, see
the below description.
1. Interface for targets to describe how to legalize.
In GlobalISel, the API in the LegalizerInfo class is the main interface
for targets to specify which types are legal for which operations, and
what to do to turn illegal type/operation combinations into legal ones.
For each operation the type sizes that can be legalized without having
to change the size of the type are specified with a call to setAction.
This isn't different to how GlobalISel worked before. For example, for a
target that supports 32 and 64 bit adds natively:
for (auto Ty : {s32, s64})
setAction({G_ADD, 0, s32}, Legal);
or for a target that needs a library call for a 32 bit division:
setAction({G_SDIV, s32}, Libcall);
The main conceptual change to the LegalizerInfo API, is in specifying
how to legalize the type sizes for which a change of size is needed. For
example, in the above example, how to specify how all types from i1 to
i8388607 (apart from s32 and s64 which are legal) need to be legalized
and expressed in terms of operations on the available legal sizes
(again, i32 and i64 in this case). Before, the implementation only
allowed specifying power-of-2-sized types (e.g. setAction({G_ADD, 0,
s128}, NarrowScalar). A worse limitation was that if you'd wanted to
specify how to legalize all the sized types as allowed by the LLVM-IR
LangRef, i1 to i8388607, you'd have to call setAction 8388607-3 times
and probably would need a lot of memory to store all of these
specifications.
Instead, the legalization actions that need to change the size of the
type are specified now using a "SizeChangeStrategy". For example:
setLegalizeScalarToDifferentSizeStrategy(
G_ADD, 0, widenToLargerAndNarrowToLargest);
This example indicates that for type sizes for which there is a larger
size that can be legalized towards, do it by Widening the size.
For example, G_ADD on s17 will be legalized by first doing WidenScalar
to make it s32, after which it's legal.
The "NarrowToLargest" indicates what to do if there is no larger size
that can be legalized towards. E.g. G_ADD on s92 will be legalized by
doing NarrowScalar to s64.
Another example, taken from the ARM backend is:
for (unsigned Op : {G_SDIV, G_UDIV}) {
setLegalizeScalarToDifferentSizeStrategy(Op, 0,
widenToLargerTypesUnsupportedOtherwise);
if (ST.hasDivideInARMMode())
setAction({Op, s32}, Legal);
else
setAction({Op, s32}, Libcall);
}
For this example, G_SDIV on s8, on a target without a divide
instruction, would be legalized by first doing action (WidenScalar,
s32), followed by (Libcall, s32).
The same principle is also followed for when the number of vector lanes
on vector data types need to be changed, e.g.:
setAction({G_ADD, LLT::vector(8, 8)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(16, 8)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(4, 16)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(8, 16)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(2, 32)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(4, 32)}, LegalizerInfo::Legal);
setLegalizeVectorElementToDifferentSizeStrategy(
G_ADD, 0, widenToLargerTypesUnsupportedOtherwise);
As currently implemented here, vector types are legalized by first
making the vector element size legal, followed by then making the number
of lanes legal. The strategy to follow in the first step is set by a
call to setLegalizeVectorElementToDifferentSizeStrategy, see example
above. The strategy followed in the second step
"moreToWiderTypesAndLessToWidest" (see code for its definition),
indicating that vectors are widened to more elements so they map to
natively supported vector widths, or when there isn't a legal wider
vector, split the vector to map it to the widest vector supported.
Therefore, for the above specification, some example legalizations are:
* getAction({G_ADD, LLT::vector(3, 3)})
returns {WidenScalar, LLT::vector(3, 8)}
* getAction({G_ADD, LLT::vector(3, 8)})
then returns {MoreElements, LLT::vector(8, 8)}
* getAction({G_ADD, LLT::vector(20, 8)})
returns {FewerElements, LLT::vector(16, 8)}
2. Key implementation aspects.
How to legalize a specific (operation, type index, size) tuple is
represented by mapping intervals of integers representing a range of
size types to an action to take, e.g.:
setScalarAction({G_ADD, LLT:scalar(1)},
{{1, WidenScalar}, // bit sizes [ 1, 31[
{32, Legal}, // bit sizes [32, 33[
{33, WidenScalar}, // bit sizes [33, 64[
{64, Legal}, // bit sizes [64, 65[
{65, NarrowScalar} // bit sizes [65, +inf[
});
Please note that most of the code to do the actual lowering of
non-power-of-2 sized types is currently missing, this is just trying to
make it possible for targets to specify what is legal, and how non-legal
types should be legalized. Probably quite a bit of further work is
needed in the actual legalizing and the other passes in GlobalISel to
support non-power-of-2 sized types.
I hope the documentation in LegalizerInfo.h and the examples provided in the
various {Target}LegalizerInfo.cpp and LegalizerInfoTest.cpp explains well
enough how this is meant to be used.
This drops the need for LLT::{half,double}...Size().
Differential Revision: https://reviews.llvm.org/D30529
llvm-svn: 317560
2017-11-07 18:34:34 +08:00
|
|
|
// FIXME: add support for when SizeOp0 isn't an exact multiple of
|
|
|
|
// NarrowSize.
|
|
|
|
if (SizeOp0 % NarrowSize != 0)
|
|
|
|
return UnableToLegalize;
|
2016-08-05 04:54:13 +08:00
|
|
|
// Expand in terms of carry-setting/consuming G_ADDE instructions.
|
[GlobalISel] Enable legalizing non-power-of-2 sized types.
This changes the interface of how targets describe how to legalize, see
the below description.
1. Interface for targets to describe how to legalize.
In GlobalISel, the API in the LegalizerInfo class is the main interface
for targets to specify which types are legal for which operations, and
what to do to turn illegal type/operation combinations into legal ones.
For each operation the type sizes that can be legalized without having
to change the size of the type are specified with a call to setAction.
This isn't different to how GlobalISel worked before. For example, for a
target that supports 32 and 64 bit adds natively:
for (auto Ty : {s32, s64})
setAction({G_ADD, 0, s32}, Legal);
or for a target that needs a library call for a 32 bit division:
setAction({G_SDIV, s32}, Libcall);
The main conceptual change to the LegalizerInfo API, is in specifying
how to legalize the type sizes for which a change of size is needed. For
example, in the above example, how to specify how all types from i1 to
i8388607 (apart from s32 and s64 which are legal) need to be legalized
and expressed in terms of operations on the available legal sizes
(again, i32 and i64 in this case). Before, the implementation only
allowed specifying power-of-2-sized types (e.g. setAction({G_ADD, 0,
s128}, NarrowScalar). A worse limitation was that if you'd wanted to
specify how to legalize all the sized types as allowed by the LLVM-IR
LangRef, i1 to i8388607, you'd have to call setAction 8388607-3 times
and probably would need a lot of memory to store all of these
specifications.
Instead, the legalization actions that need to change the size of the
type are specified now using a "SizeChangeStrategy". For example:
setLegalizeScalarToDifferentSizeStrategy(
G_ADD, 0, widenToLargerAndNarrowToLargest);
This example indicates that for type sizes for which there is a larger
size that can be legalized towards, do it by Widening the size.
For example, G_ADD on s17 will be legalized by first doing WidenScalar
to make it s32, after which it's legal.
The "NarrowToLargest" indicates what to do if there is no larger size
that can be legalized towards. E.g. G_ADD on s92 will be legalized by
doing NarrowScalar to s64.
Another example, taken from the ARM backend is:
for (unsigned Op : {G_SDIV, G_UDIV}) {
setLegalizeScalarToDifferentSizeStrategy(Op, 0,
widenToLargerTypesUnsupportedOtherwise);
if (ST.hasDivideInARMMode())
setAction({Op, s32}, Legal);
else
setAction({Op, s32}, Libcall);
}
For this example, G_SDIV on s8, on a target without a divide
instruction, would be legalized by first doing action (WidenScalar,
s32), followed by (Libcall, s32).
The same principle is also followed for when the number of vector lanes
on vector data types need to be changed, e.g.:
setAction({G_ADD, LLT::vector(8, 8)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(16, 8)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(4, 16)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(8, 16)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(2, 32)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(4, 32)}, LegalizerInfo::Legal);
setLegalizeVectorElementToDifferentSizeStrategy(
G_ADD, 0, widenToLargerTypesUnsupportedOtherwise);
As currently implemented here, vector types are legalized by first
making the vector element size legal, followed by then making the number
of lanes legal. The strategy to follow in the first step is set by a
call to setLegalizeVectorElementToDifferentSizeStrategy, see example
above. The strategy followed in the second step
"moreToWiderTypesAndLessToWidest" (see code for its definition),
indicating that vectors are widened to more elements so they map to
natively supported vector widths, or when there isn't a legal wider
vector, split the vector to map it to the widest vector supported.
Therefore, for the above specification, some example legalizations are:
* getAction({G_ADD, LLT::vector(3, 3)})
returns {WidenScalar, LLT::vector(3, 8)}
* getAction({G_ADD, LLT::vector(3, 8)})
then returns {MoreElements, LLT::vector(8, 8)}
* getAction({G_ADD, LLT::vector(20, 8)})
returns {FewerElements, LLT::vector(16, 8)}
2. Key implementation aspects.
How to legalize a specific (operation, type index, size) tuple is
represented by mapping intervals of integers representing a range of
size types to an action to take, e.g.:
setScalarAction({G_ADD, LLT:scalar(1)},
{{1, WidenScalar}, // bit sizes [ 1, 31[
{32, Legal}, // bit sizes [32, 33[
{33, WidenScalar}, // bit sizes [33, 64[
{64, Legal}, // bit sizes [64, 65[
{65, NarrowScalar} // bit sizes [65, +inf[
});
Please note that most of the code to do the actual lowering of
non-power-of-2 sized types is currently missing, this is just trying to
make it possible for targets to specify what is legal, and how non-legal
types should be legalized. Probably quite a bit of further work is
needed in the actual legalizing and the other passes in GlobalISel to
support non-power-of-2 sized types.
I hope the documentation in LegalizerInfo.h and the examples provided in the
various {Target}LegalizerInfo.cpp and LegalizerInfoTest.cpp explains well
enough how this is meant to be used.
This drops the need for LLT::{half,double}...Size().
Differential Revision: https://reviews.llvm.org/D30529
llvm-svn: 317560
2017-11-07 18:34:34 +08:00
|
|
|
int NumParts = SizeOp0 / NarrowTy.getSizeInBits();
|
2016-08-05 04:54:13 +08:00
|
|
|
|
2016-09-20 23:20:36 +08:00
|
|
|
SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs;
|
2016-08-05 04:54:13 +08:00
|
|
|
extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, Src1Regs);
|
|
|
|
extractParts(MI.getOperand(2).getReg(), NarrowTy, NumParts, Src2Regs);
|
|
|
|
|
2016-09-09 19:46:34 +08:00
|
|
|
unsigned CarryIn = MRI.createGenericVirtualRegister(LLT::scalar(1));
|
|
|
|
MIRBuilder.buildConstant(CarryIn, 0);
|
2016-08-05 04:54:13 +08:00
|
|
|
|
|
|
|
for (int i = 0; i < NumParts; ++i) {
|
2016-09-09 19:46:34 +08:00
|
|
|
unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy);
|
|
|
|
unsigned CarryOut = MRI.createGenericVirtualRegister(LLT::scalar(1));
|
2016-08-05 04:54:13 +08:00
|
|
|
|
2016-09-09 19:46:34 +08:00
|
|
|
MIRBuilder.buildUAdde(DstReg, CarryOut, Src1Regs[i],
|
2016-08-20 01:17:06 +08:00
|
|
|
Src2Regs[i], CarryIn);
|
2016-08-05 04:54:13 +08:00
|
|
|
|
|
|
|
DstRegs.push_back(DstReg);
|
|
|
|
CarryIn = CarryOut;
|
|
|
|
}
|
2016-09-09 19:46:34 +08:00
|
|
|
unsigned DstReg = MI.getOperand(0).getReg();
|
2017-03-04 06:46:09 +08:00
|
|
|
MIRBuilder.buildMerge(DstReg, DstRegs);
|
2016-08-05 04:54:13 +08:00
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2017-06-27 04:34:13 +08:00
|
|
|
case TargetOpcode::G_EXTRACT: {
|
|
|
|
if (TypeIdx != 1)
|
|
|
|
return UnableToLegalize;
|
|
|
|
|
[GlobalISel] Enable legalizing non-power-of-2 sized types.
This changes the interface of how targets describe how to legalize, see
the below description.
1. Interface for targets to describe how to legalize.
In GlobalISel, the API in the LegalizerInfo class is the main interface
for targets to specify which types are legal for which operations, and
what to do to turn illegal type/operation combinations into legal ones.
For each operation the type sizes that can be legalized without having
to change the size of the type are specified with a call to setAction.
This isn't different to how GlobalISel worked before. For example, for a
target that supports 32 and 64 bit adds natively:
for (auto Ty : {s32, s64})
setAction({G_ADD, 0, s32}, Legal);
or for a target that needs a library call for a 32 bit division:
setAction({G_SDIV, s32}, Libcall);
The main conceptual change to the LegalizerInfo API, is in specifying
how to legalize the type sizes for which a change of size is needed. For
example, in the above example, how to specify how all types from i1 to
i8388607 (apart from s32 and s64 which are legal) need to be legalized
and expressed in terms of operations on the available legal sizes
(again, i32 and i64 in this case). Before, the implementation only
allowed specifying power-of-2-sized types (e.g. setAction({G_ADD, 0,
s128}, NarrowScalar). A worse limitation was that if you'd wanted to
specify how to legalize all the sized types as allowed by the LLVM-IR
LangRef, i1 to i8388607, you'd have to call setAction 8388607-3 times
and probably would need a lot of memory to store all of these
specifications.
Instead, the legalization actions that need to change the size of the
type are specified now using a "SizeChangeStrategy". For example:
setLegalizeScalarToDifferentSizeStrategy(
G_ADD, 0, widenToLargerAndNarrowToLargest);
This example indicates that for type sizes for which there is a larger
size that can be legalized towards, do it by Widening the size.
For example, G_ADD on s17 will be legalized by first doing WidenScalar
to make it s32, after which it's legal.
The "NarrowToLargest" indicates what to do if there is no larger size
that can be legalized towards. E.g. G_ADD on s92 will be legalized by
doing NarrowScalar to s64.
Another example, taken from the ARM backend is:
for (unsigned Op : {G_SDIV, G_UDIV}) {
setLegalizeScalarToDifferentSizeStrategy(Op, 0,
widenToLargerTypesUnsupportedOtherwise);
if (ST.hasDivideInARMMode())
setAction({Op, s32}, Legal);
else
setAction({Op, s32}, Libcall);
}
For this example, G_SDIV on s8, on a target without a divide
instruction, would be legalized by first doing action (WidenScalar,
s32), followed by (Libcall, s32).
The same principle is also followed for when the number of vector lanes
on vector data types need to be changed, e.g.:
setAction({G_ADD, LLT::vector(8, 8)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(16, 8)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(4, 16)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(8, 16)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(2, 32)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(4, 32)}, LegalizerInfo::Legal);
setLegalizeVectorElementToDifferentSizeStrategy(
G_ADD, 0, widenToLargerTypesUnsupportedOtherwise);
As currently implemented here, vector types are legalized by first
making the vector element size legal, followed by then making the number
of lanes legal. The strategy to follow in the first step is set by a
call to setLegalizeVectorElementToDifferentSizeStrategy, see example
above. The strategy followed in the second step
"moreToWiderTypesAndLessToWidest" (see code for its definition),
indicating that vectors are widened to more elements so they map to
natively supported vector widths, or when there isn't a legal wider
vector, split the vector to map it to the widest vector supported.
Therefore, for the above specification, some example legalizations are:
* getAction({G_ADD, LLT::vector(3, 3)})
returns {WidenScalar, LLT::vector(3, 8)}
* getAction({G_ADD, LLT::vector(3, 8)})
then returns {MoreElements, LLT::vector(8, 8)}
* getAction({G_ADD, LLT::vector(20, 8)})
returns {FewerElements, LLT::vector(16, 8)}
2. Key implementation aspects.
How to legalize a specific (operation, type index, size) tuple is
represented by mapping intervals of integers representing a range of
size types to an action to take, e.g.:
setScalarAction({G_ADD, LLT:scalar(1)},
{{1, WidenScalar}, // bit sizes [ 1, 31[
{32, Legal}, // bit sizes [32, 33[
{33, WidenScalar}, // bit sizes [33, 64[
{64, Legal}, // bit sizes [64, 65[
{65, NarrowScalar} // bit sizes [65, +inf[
});
Please note that most of the code to do the actual lowering of
non-power-of-2 sized types is currently missing, this is just trying to
make it possible for targets to specify what is legal, and how non-legal
types should be legalized. Probably quite a bit of further work is
needed in the actual legalizing and the other passes in GlobalISel to
support non-power-of-2 sized types.
I hope the documentation in LegalizerInfo.h and the examples provided in the
various {Target}LegalizerInfo.cpp and LegalizerInfoTest.cpp explains well
enough how this is meant to be used.
This drops the need for LLT::{half,double}...Size().
Differential Revision: https://reviews.llvm.org/D30529
llvm-svn: 317560
2017-11-07 18:34:34 +08:00
|
|
|
int64_t SizeOp1 = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
|
|
|
|
// FIXME: add support for when SizeOp1 isn't an exact multiple of
|
|
|
|
// NarrowSize.
|
|
|
|
if (SizeOp1 % NarrowSize != 0)
|
|
|
|
return UnableToLegalize;
|
|
|
|
int NumParts = SizeOp1 / NarrowSize;
|
2017-06-27 04:34:13 +08:00
|
|
|
|
|
|
|
SmallVector<unsigned, 2> SrcRegs, DstRegs;
|
|
|
|
SmallVector<uint64_t, 2> Indexes;
|
|
|
|
extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, SrcRegs);
|
|
|
|
|
|
|
|
unsigned OpReg = MI.getOperand(0).getReg();
|
|
|
|
int64_t OpStart = MI.getOperand(2).getImm();
|
|
|
|
int64_t OpSize = MRI.getType(OpReg).getSizeInBits();
|
|
|
|
for (int i = 0; i < NumParts; ++i) {
|
|
|
|
unsigned SrcStart = i * NarrowSize;
|
|
|
|
|
|
|
|
if (SrcStart + NarrowSize <= OpStart || SrcStart >= OpStart + OpSize) {
|
|
|
|
// No part of the extract uses this subregister, ignore it.
|
|
|
|
continue;
|
|
|
|
} else if (SrcStart == OpStart && NarrowTy == MRI.getType(OpReg)) {
|
|
|
|
// The entire subregister is extracted, forward the value.
|
|
|
|
DstRegs.push_back(SrcRegs[i]);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// OpSegStart is where this destination segment would start in OpReg if it
|
|
|
|
// extended infinitely in both directions.
|
|
|
|
int64_t ExtractOffset, SegSize;
|
|
|
|
if (OpStart < SrcStart) {
|
|
|
|
ExtractOffset = 0;
|
|
|
|
SegSize = std::min(NarrowSize, OpStart + OpSize - SrcStart);
|
|
|
|
} else {
|
|
|
|
ExtractOffset = OpStart - SrcStart;
|
|
|
|
SegSize = std::min(SrcStart + NarrowSize - OpStart, OpSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned SegReg = SrcRegs[i];
|
|
|
|
if (ExtractOffset != 0 || SegSize != NarrowSize) {
|
|
|
|
// A genuine extract is needed.
|
|
|
|
SegReg = MRI.createGenericVirtualRegister(LLT::scalar(SegSize));
|
|
|
|
MIRBuilder.buildExtract(SegReg, SrcRegs[i], ExtractOffset);
|
|
|
|
}
|
|
|
|
|
|
|
|
DstRegs.push_back(SegReg);
|
|
|
|
}
|
|
|
|
|
|
|
|
MIRBuilder.buildMerge(MI.getOperand(0).getReg(), DstRegs);
|
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2017-02-07 05:56:47 +08:00
|
|
|
case TargetOpcode::G_INSERT: {
|
[GlobalISel] Enable legalizing non-power-of-2 sized types.
This changes the interface of how targets describe how to legalize, see
the below description.
1. Interface for targets to describe how to legalize.
In GlobalISel, the API in the LegalizerInfo class is the main interface
for targets to specify which types are legal for which operations, and
what to do to turn illegal type/operation combinations into legal ones.
For each operation the type sizes that can be legalized without having
to change the size of the type are specified with a call to setAction.
This isn't different to how GlobalISel worked before. For example, for a
target that supports 32 and 64 bit adds natively:
for (auto Ty : {s32, s64})
setAction({G_ADD, 0, s32}, Legal);
or for a target that needs a library call for a 32 bit division:
setAction({G_SDIV, s32}, Libcall);
The main conceptual change to the LegalizerInfo API, is in specifying
how to legalize the type sizes for which a change of size is needed. For
example, in the above example, how to specify how all types from i1 to
i8388607 (apart from s32 and s64 which are legal) need to be legalized
and expressed in terms of operations on the available legal sizes
(again, i32 and i64 in this case). Before, the implementation only
allowed specifying power-of-2-sized types (e.g. setAction({G_ADD, 0,
s128}, NarrowScalar). A worse limitation was that if you'd wanted to
specify how to legalize all the sized types as allowed by the LLVM-IR
LangRef, i1 to i8388607, you'd have to call setAction 8388607-3 times
and probably would need a lot of memory to store all of these
specifications.
Instead, the legalization actions that need to change the size of the
type are specified now using a "SizeChangeStrategy". For example:
setLegalizeScalarToDifferentSizeStrategy(
G_ADD, 0, widenToLargerAndNarrowToLargest);
This example indicates that for type sizes for which there is a larger
size that can be legalized towards, do it by Widening the size.
For example, G_ADD on s17 will be legalized by first doing WidenScalar
to make it s32, after which it's legal.
The "NarrowToLargest" indicates what to do if there is no larger size
that can be legalized towards. E.g. G_ADD on s92 will be legalized by
doing NarrowScalar to s64.
Another example, taken from the ARM backend is:
for (unsigned Op : {G_SDIV, G_UDIV}) {
setLegalizeScalarToDifferentSizeStrategy(Op, 0,
widenToLargerTypesUnsupportedOtherwise);
if (ST.hasDivideInARMMode())
setAction({Op, s32}, Legal);
else
setAction({Op, s32}, Libcall);
}
For this example, G_SDIV on s8, on a target without a divide
instruction, would be legalized by first doing action (WidenScalar,
s32), followed by (Libcall, s32).
The same principle is also followed for when the number of vector lanes
on vector data types need to be changed, e.g.:
setAction({G_ADD, LLT::vector(8, 8)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(16, 8)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(4, 16)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(8, 16)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(2, 32)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(4, 32)}, LegalizerInfo::Legal);
setLegalizeVectorElementToDifferentSizeStrategy(
G_ADD, 0, widenToLargerTypesUnsupportedOtherwise);
As currently implemented here, vector types are legalized by first
making the vector element size legal, followed by then making the number
of lanes legal. The strategy to follow in the first step is set by a
call to setLegalizeVectorElementToDifferentSizeStrategy, see example
above. The strategy followed in the second step
"moreToWiderTypesAndLessToWidest" (see code for its definition),
indicating that vectors are widened to more elements so they map to
natively supported vector widths, or when there isn't a legal wider
vector, split the vector to map it to the widest vector supported.
Therefore, for the above specification, some example legalizations are:
* getAction({G_ADD, LLT::vector(3, 3)})
returns {WidenScalar, LLT::vector(3, 8)}
* getAction({G_ADD, LLT::vector(3, 8)})
then returns {MoreElements, LLT::vector(8, 8)}
* getAction({G_ADD, LLT::vector(20, 8)})
returns {FewerElements, LLT::vector(16, 8)}
2. Key implementation aspects.
How to legalize a specific (operation, type index, size) tuple is
represented by mapping intervals of integers representing a range of
size types to an action to take, e.g.:
setScalarAction({G_ADD, LLT:scalar(1)},
{{1, WidenScalar}, // bit sizes [ 1, 31[
{32, Legal}, // bit sizes [32, 33[
{33, WidenScalar}, // bit sizes [33, 64[
{64, Legal}, // bit sizes [64, 65[
{65, NarrowScalar} // bit sizes [65, +inf[
});
Please note that most of the code to do the actual lowering of
non-power-of-2 sized types is currently missing, this is just trying to
make it possible for targets to specify what is legal, and how non-legal
types should be legalized. Probably quite a bit of further work is
needed in the actual legalizing and the other passes in GlobalISel to
support non-power-of-2 sized types.
I hope the documentation in LegalizerInfo.h and the examples provided in the
various {Target}LegalizerInfo.cpp and LegalizerInfoTest.cpp explains well
enough how this is meant to be used.
This drops the need for LLT::{half,double}...Size().
Differential Revision: https://reviews.llvm.org/D30529
llvm-svn: 317560
2017-11-07 18:34:34 +08:00
|
|
|
// FIXME: add support for when SizeOp0 isn't an exact multiple of
|
|
|
|
// NarrowSize.
|
|
|
|
if (SizeOp0 % NarrowSize != 0)
|
2017-02-07 05:56:47 +08:00
|
|
|
return UnableToLegalize;
|
|
|
|
|
[GlobalISel] Enable legalizing non-power-of-2 sized types.
This changes the interface of how targets describe how to legalize, see
the below description.
1. Interface for targets to describe how to legalize.
In GlobalISel, the API in the LegalizerInfo class is the main interface
for targets to specify which types are legal for which operations, and
what to do to turn illegal type/operation combinations into legal ones.
For each operation the type sizes that can be legalized without having
to change the size of the type are specified with a call to setAction.
This isn't different to how GlobalISel worked before. For example, for a
target that supports 32 and 64 bit adds natively:
for (auto Ty : {s32, s64})
setAction({G_ADD, 0, s32}, Legal);
or for a target that needs a library call for a 32 bit division:
setAction({G_SDIV, s32}, Libcall);
The main conceptual change to the LegalizerInfo API, is in specifying
how to legalize the type sizes for which a change of size is needed. For
example, in the above example, how to specify how all types from i1 to
i8388607 (apart from s32 and s64 which are legal) need to be legalized
and expressed in terms of operations on the available legal sizes
(again, i32 and i64 in this case). Before, the implementation only
allowed specifying power-of-2-sized types (e.g. setAction({G_ADD, 0,
s128}, NarrowScalar). A worse limitation was that if you'd wanted to
specify how to legalize all the sized types as allowed by the LLVM-IR
LangRef, i1 to i8388607, you'd have to call setAction 8388607-3 times
and probably would need a lot of memory to store all of these
specifications.
Instead, the legalization actions that need to change the size of the
type are specified now using a "SizeChangeStrategy". For example:
setLegalizeScalarToDifferentSizeStrategy(
G_ADD, 0, widenToLargerAndNarrowToLargest);
This example indicates that for type sizes for which there is a larger
size that can be legalized towards, do it by Widening the size.
For example, G_ADD on s17 will be legalized by first doing WidenScalar
to make it s32, after which it's legal.
The "NarrowToLargest" indicates what to do if there is no larger size
that can be legalized towards. E.g. G_ADD on s92 will be legalized by
doing NarrowScalar to s64.
Another example, taken from the ARM backend is:
for (unsigned Op : {G_SDIV, G_UDIV}) {
setLegalizeScalarToDifferentSizeStrategy(Op, 0,
widenToLargerTypesUnsupportedOtherwise);
if (ST.hasDivideInARMMode())
setAction({Op, s32}, Legal);
else
setAction({Op, s32}, Libcall);
}
For this example, G_SDIV on s8, on a target without a divide
instruction, would be legalized by first doing action (WidenScalar,
s32), followed by (Libcall, s32).
The same principle is also followed for when the number of vector lanes
on vector data types need to be changed, e.g.:
setAction({G_ADD, LLT::vector(8, 8)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(16, 8)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(4, 16)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(8, 16)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(2, 32)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(4, 32)}, LegalizerInfo::Legal);
setLegalizeVectorElementToDifferentSizeStrategy(
G_ADD, 0, widenToLargerTypesUnsupportedOtherwise);
As currently implemented here, vector types are legalized by first
making the vector element size legal, followed by then making the number
of lanes legal. The strategy to follow in the first step is set by a
call to setLegalizeVectorElementToDifferentSizeStrategy, see example
above. The strategy followed in the second step
"moreToWiderTypesAndLessToWidest" (see code for its definition),
indicating that vectors are widened to more elements so they map to
natively supported vector widths, or when there isn't a legal wider
vector, split the vector to map it to the widest vector supported.
Therefore, for the above specification, some example legalizations are:
* getAction({G_ADD, LLT::vector(3, 3)})
returns {WidenScalar, LLT::vector(3, 8)}
* getAction({G_ADD, LLT::vector(3, 8)})
then returns {MoreElements, LLT::vector(8, 8)}
* getAction({G_ADD, LLT::vector(20, 8)})
returns {FewerElements, LLT::vector(16, 8)}
2. Key implementation aspects.
How to legalize a specific (operation, type index, size) tuple is
represented by mapping intervals of integers representing a range of
size types to an action to take, e.g.:
setScalarAction({G_ADD, LLT:scalar(1)},
{{1, WidenScalar}, // bit sizes [ 1, 31[
{32, Legal}, // bit sizes [32, 33[
{33, WidenScalar}, // bit sizes [33, 64[
{64, Legal}, // bit sizes [64, 65[
{65, NarrowScalar} // bit sizes [65, +inf[
});
Please note that most of the code to do the actual lowering of
non-power-of-2 sized types is currently missing, this is just trying to
make it possible for targets to specify what is legal, and how non-legal
types should be legalized. Probably quite a bit of further work is
needed in the actual legalizing and the other passes in GlobalISel to
support non-power-of-2 sized types.
I hope the documentation in LegalizerInfo.h and the examples provided in the
various {Target}LegalizerInfo.cpp and LegalizerInfoTest.cpp explains well
enough how this is meant to be used.
This drops the need for LLT::{half,double}...Size().
Differential Revision: https://reviews.llvm.org/D30529
llvm-svn: 317560
2017-11-07 18:34:34 +08:00
|
|
|
int NumParts = SizeOp0 / NarrowSize;
|
2017-02-07 05:56:47 +08:00
|
|
|
|
|
|
|
SmallVector<unsigned, 2> SrcRegs, DstRegs;
|
|
|
|
SmallVector<uint64_t, 2> Indexes;
|
|
|
|
extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, SrcRegs);
|
|
|
|
|
2017-03-07 02:23:04 +08:00
|
|
|
unsigned OpReg = MI.getOperand(2).getReg();
|
|
|
|
int64_t OpStart = MI.getOperand(3).getImm();
|
|
|
|
int64_t OpSize = MRI.getType(OpReg).getSizeInBits();
|
2017-02-07 05:56:47 +08:00
|
|
|
for (int i = 0; i < NumParts; ++i) {
|
|
|
|
unsigned DstStart = i * NarrowSize;
|
|
|
|
|
2017-03-07 02:23:04 +08:00
|
|
|
if (DstStart + NarrowSize <= OpStart || DstStart >= OpStart + OpSize) {
|
2017-02-07 05:56:47 +08:00
|
|
|
// No part of the insert affects this subregister, forward the original.
|
|
|
|
DstRegs.push_back(SrcRegs[i]);
|
|
|
|
continue;
|
2017-03-07 02:23:04 +08:00
|
|
|
} else if (DstStart == OpStart && NarrowTy == MRI.getType(OpReg)) {
|
2017-02-07 05:56:47 +08:00
|
|
|
// The entire subregister is defined by this insert, forward the new
|
|
|
|
// value.
|
2017-03-07 02:23:04 +08:00
|
|
|
DstRegs.push_back(OpReg);
|
2017-02-07 05:56:47 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-03-08 05:24:33 +08:00
|
|
|
// OpSegStart is where this destination segment would start in OpReg if it
|
|
|
|
// extended infinitely in both directions.
|
|
|
|
int64_t ExtractOffset, InsertOffset, SegSize;
|
|
|
|
if (OpStart < DstStart) {
|
|
|
|
InsertOffset = 0;
|
|
|
|
ExtractOffset = DstStart - OpStart;
|
|
|
|
SegSize = std::min(NarrowSize, OpStart + OpSize - DstStart);
|
|
|
|
} else {
|
|
|
|
InsertOffset = OpStart - DstStart;
|
|
|
|
ExtractOffset = 0;
|
|
|
|
SegSize =
|
|
|
|
std::min(NarrowSize - InsertOffset, OpStart + OpSize - DstStart);
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned SegReg = OpReg;
|
|
|
|
if (ExtractOffset != 0 || SegSize != OpSize) {
|
2017-03-07 02:23:04 +08:00
|
|
|
// A genuine extract is needed.
|
2017-03-08 05:24:33 +08:00
|
|
|
SegReg = MRI.createGenericVirtualRegister(LLT::scalar(SegSize));
|
|
|
|
MIRBuilder.buildExtract(SegReg, OpReg, ExtractOffset);
|
2017-02-07 05:56:47 +08:00
|
|
|
}
|
|
|
|
|
2017-03-07 02:23:04 +08:00
|
|
|
unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy);
|
2017-03-08 05:24:33 +08:00
|
|
|
MIRBuilder.buildInsert(DstReg, SrcRegs[i], SegReg, InsertOffset);
|
2017-02-07 05:56:47 +08:00
|
|
|
DstRegs.push_back(DstReg);
|
|
|
|
}
|
|
|
|
|
|
|
|
assert(DstRegs.size() == (unsigned)NumParts && "not all parts covered");
|
2017-03-04 06:46:09 +08:00
|
|
|
MIRBuilder.buildMerge(MI.getOperand(0).getReg(), DstRegs);
|
2017-02-07 05:56:47 +08:00
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2017-01-19 09:05:48 +08:00
|
|
|
case TargetOpcode::G_LOAD: {
|
[GlobalISel] Enable legalizing non-power-of-2 sized types.
This changes the interface of how targets describe how to legalize, see
the below description.
1. Interface for targets to describe how to legalize.
In GlobalISel, the API in the LegalizerInfo class is the main interface
for targets to specify which types are legal for which operations, and
what to do to turn illegal type/operation combinations into legal ones.
For each operation the type sizes that can be legalized without having
to change the size of the type are specified with a call to setAction.
This isn't different to how GlobalISel worked before. For example, for a
target that supports 32 and 64 bit adds natively:
for (auto Ty : {s32, s64})
setAction({G_ADD, 0, s32}, Legal);
or for a target that needs a library call for a 32 bit division:
setAction({G_SDIV, s32}, Libcall);
The main conceptual change to the LegalizerInfo API, is in specifying
how to legalize the type sizes for which a change of size is needed. For
example, in the above example, how to specify how all types from i1 to
i8388607 (apart from s32 and s64 which are legal) need to be legalized
and expressed in terms of operations on the available legal sizes
(again, i32 and i64 in this case). Before, the implementation only
allowed specifying power-of-2-sized types (e.g. setAction({G_ADD, 0,
s128}, NarrowScalar). A worse limitation was that if you'd wanted to
specify how to legalize all the sized types as allowed by the LLVM-IR
LangRef, i1 to i8388607, you'd have to call setAction 8388607-3 times
and probably would need a lot of memory to store all of these
specifications.
Instead, the legalization actions that need to change the size of the
type are specified now using a "SizeChangeStrategy". For example:
setLegalizeScalarToDifferentSizeStrategy(
G_ADD, 0, widenToLargerAndNarrowToLargest);
This example indicates that for type sizes for which there is a larger
size that can be legalized towards, do it by Widening the size.
For example, G_ADD on s17 will be legalized by first doing WidenScalar
to make it s32, after which it's legal.
The "NarrowToLargest" indicates what to do if there is no larger size
that can be legalized towards. E.g. G_ADD on s92 will be legalized by
doing NarrowScalar to s64.
Another example, taken from the ARM backend is:
for (unsigned Op : {G_SDIV, G_UDIV}) {
setLegalizeScalarToDifferentSizeStrategy(Op, 0,
widenToLargerTypesUnsupportedOtherwise);
if (ST.hasDivideInARMMode())
setAction({Op, s32}, Legal);
else
setAction({Op, s32}, Libcall);
}
For this example, G_SDIV on s8, on a target without a divide
instruction, would be legalized by first doing action (WidenScalar,
s32), followed by (Libcall, s32).
The same principle is also followed for when the number of vector lanes
on vector data types need to be changed, e.g.:
setAction({G_ADD, LLT::vector(8, 8)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(16, 8)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(4, 16)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(8, 16)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(2, 32)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(4, 32)}, LegalizerInfo::Legal);
setLegalizeVectorElementToDifferentSizeStrategy(
G_ADD, 0, widenToLargerTypesUnsupportedOtherwise);
As currently implemented here, vector types are legalized by first
making the vector element size legal, followed by then making the number
of lanes legal. The strategy to follow in the first step is set by a
call to setLegalizeVectorElementToDifferentSizeStrategy, see example
above. The strategy followed in the second step
"moreToWiderTypesAndLessToWidest" (see code for its definition),
indicating that vectors are widened to more elements so they map to
natively supported vector widths, or when there isn't a legal wider
vector, split the vector to map it to the widest vector supported.
Therefore, for the above specification, some example legalizations are:
* getAction({G_ADD, LLT::vector(3, 3)})
returns {WidenScalar, LLT::vector(3, 8)}
* getAction({G_ADD, LLT::vector(3, 8)})
then returns {MoreElements, LLT::vector(8, 8)}
* getAction({G_ADD, LLT::vector(20, 8)})
returns {FewerElements, LLT::vector(16, 8)}
2. Key implementation aspects.
How to legalize a specific (operation, type index, size) tuple is
represented by mapping intervals of integers representing a range of
size types to an action to take, e.g.:
setScalarAction({G_ADD, LLT:scalar(1)},
{{1, WidenScalar}, // bit sizes [ 1, 31[
{32, Legal}, // bit sizes [32, 33[
{33, WidenScalar}, // bit sizes [33, 64[
{64, Legal}, // bit sizes [64, 65[
{65, NarrowScalar} // bit sizes [65, +inf[
});
Please note that most of the code to do the actual lowering of
non-power-of-2 sized types is currently missing, this is just trying to
make it possible for targets to specify what is legal, and how non-legal
types should be legalized. Probably quite a bit of further work is
needed in the actual legalizing and the other passes in GlobalISel to
support non-power-of-2 sized types.
I hope the documentation in LegalizerInfo.h and the examples provided in the
various {Target}LegalizerInfo.cpp and LegalizerInfoTest.cpp explains well
enough how this is meant to be used.
This drops the need for LLT::{half,double}...Size().
Differential Revision: https://reviews.llvm.org/D30529
llvm-svn: 317560
2017-11-07 18:34:34 +08:00
|
|
|
// FIXME: add support for when SizeOp0 isn't an exact multiple of
|
|
|
|
// NarrowSize.
|
|
|
|
if (SizeOp0 % NarrowSize != 0)
|
|
|
|
return UnableToLegalize;
|
|
|
|
int NumParts = SizeOp0 / NarrowSize;
|
[globalisel][legalizer] G_LOAD/G_STORE NarrowScalar should not emit G_GEP x, 0.
Summary:
When legalizing G_LOAD/G_STORE using NarrowScalar, we should avoid emitting
%0 = G_CONSTANT ty 0
%1 = G_GEP %x, %0
since it's cheaper to not emit the redundant instructions than it is to fold them
away later.
Reviewers: qcolombet, t.p.northover, ab, rovka, aditya_nandakumar, kristof.beyls
Reviewed By: qcolombet
Subscribers: javed.absar, llvm-commits, igorb
Differential Revision: https://reviews.llvm.org/D32746
llvm-svn: 305340
2017-06-14 07:42:32 +08:00
|
|
|
LLT OffsetTy = LLT::scalar(
|
|
|
|
MRI.getType(MI.getOperand(1).getReg()).getScalarSizeInBits());
|
2017-01-19 09:05:48 +08:00
|
|
|
|
|
|
|
SmallVector<unsigned, 2> DstRegs;
|
|
|
|
for (int i = 0; i < NumParts; ++i) {
|
|
|
|
unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy);
|
[globalisel][legalizer] G_LOAD/G_STORE NarrowScalar should not emit G_GEP x, 0.
Summary:
When legalizing G_LOAD/G_STORE using NarrowScalar, we should avoid emitting
%0 = G_CONSTANT ty 0
%1 = G_GEP %x, %0
since it's cheaper to not emit the redundant instructions than it is to fold them
away later.
Reviewers: qcolombet, t.p.northover, ab, rovka, aditya_nandakumar, kristof.beyls
Reviewed By: qcolombet
Subscribers: javed.absar, llvm-commits, igorb
Differential Revision: https://reviews.llvm.org/D32746
llvm-svn: 305340
2017-06-14 07:42:32 +08:00
|
|
|
unsigned SrcReg = 0;
|
|
|
|
unsigned Adjustment = i * NarrowSize / 8;
|
|
|
|
|
|
|
|
MIRBuilder.materializeGEP(SrcReg, MI.getOperand(1).getReg(), OffsetTy,
|
|
|
|
Adjustment);
|
2017-01-19 09:05:48 +08:00
|
|
|
|
2017-01-20 08:30:17 +08:00
|
|
|
// TODO: This is conservatively correct, but we probably want to split the
|
|
|
|
// memory operands in the future.
|
2017-01-19 09:05:48 +08:00
|
|
|
MIRBuilder.buildLoad(DstReg, SrcReg, **MI.memoperands_begin());
|
|
|
|
|
|
|
|
DstRegs.push_back(DstReg);
|
|
|
|
}
|
|
|
|
unsigned DstReg = MI.getOperand(0).getReg();
|
2017-03-04 06:46:09 +08:00
|
|
|
MIRBuilder.buildMerge(DstReg, DstRegs);
|
2017-01-19 09:05:48 +08:00
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2017-01-19 01:29:54 +08:00
|
|
|
case TargetOpcode::G_STORE: {
|
[GlobalISel] Enable legalizing non-power-of-2 sized types.
This changes the interface of how targets describe how to legalize, see
the below description.
1. Interface for targets to describe how to legalize.
In GlobalISel, the API in the LegalizerInfo class is the main interface
for targets to specify which types are legal for which operations, and
what to do to turn illegal type/operation combinations into legal ones.
For each operation the type sizes that can be legalized without having
to change the size of the type are specified with a call to setAction.
This isn't different to how GlobalISel worked before. For example, for a
target that supports 32 and 64 bit adds natively:
for (auto Ty : {s32, s64})
setAction({G_ADD, 0, s32}, Legal);
or for a target that needs a library call for a 32 bit division:
setAction({G_SDIV, s32}, Libcall);
The main conceptual change to the LegalizerInfo API, is in specifying
how to legalize the type sizes for which a change of size is needed. For
example, in the above example, how to specify how all types from i1 to
i8388607 (apart from s32 and s64 which are legal) need to be legalized
and expressed in terms of operations on the available legal sizes
(again, i32 and i64 in this case). Before, the implementation only
allowed specifying power-of-2-sized types (e.g. setAction({G_ADD, 0,
s128}, NarrowScalar). A worse limitation was that if you'd wanted to
specify how to legalize all the sized types as allowed by the LLVM-IR
LangRef, i1 to i8388607, you'd have to call setAction 8388607-3 times
and probably would need a lot of memory to store all of these
specifications.
Instead, the legalization actions that need to change the size of the
type are specified now using a "SizeChangeStrategy". For example:
setLegalizeScalarToDifferentSizeStrategy(
G_ADD, 0, widenToLargerAndNarrowToLargest);
This example indicates that for type sizes for which there is a larger
size that can be legalized towards, do it by Widening the size.
For example, G_ADD on s17 will be legalized by first doing WidenScalar
to make it s32, after which it's legal.
The "NarrowToLargest" indicates what to do if there is no larger size
that can be legalized towards. E.g. G_ADD on s92 will be legalized by
doing NarrowScalar to s64.
Another example, taken from the ARM backend is:
for (unsigned Op : {G_SDIV, G_UDIV}) {
setLegalizeScalarToDifferentSizeStrategy(Op, 0,
widenToLargerTypesUnsupportedOtherwise);
if (ST.hasDivideInARMMode())
setAction({Op, s32}, Legal);
else
setAction({Op, s32}, Libcall);
}
For this example, G_SDIV on s8, on a target without a divide
instruction, would be legalized by first doing action (WidenScalar,
s32), followed by (Libcall, s32).
The same principle is also followed for when the number of vector lanes
on vector data types need to be changed, e.g.:
setAction({G_ADD, LLT::vector(8, 8)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(16, 8)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(4, 16)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(8, 16)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(2, 32)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(4, 32)}, LegalizerInfo::Legal);
setLegalizeVectorElementToDifferentSizeStrategy(
G_ADD, 0, widenToLargerTypesUnsupportedOtherwise);
As currently implemented here, vector types are legalized by first
making the vector element size legal, followed by then making the number
of lanes legal. The strategy to follow in the first step is set by a
call to setLegalizeVectorElementToDifferentSizeStrategy, see example
above. The strategy followed in the second step
"moreToWiderTypesAndLessToWidest" (see code for its definition),
indicating that vectors are widened to more elements so they map to
natively supported vector widths, or when there isn't a legal wider
vector, split the vector to map it to the widest vector supported.
Therefore, for the above specification, some example legalizations are:
* getAction({G_ADD, LLT::vector(3, 3)})
returns {WidenScalar, LLT::vector(3, 8)}
* getAction({G_ADD, LLT::vector(3, 8)})
then returns {MoreElements, LLT::vector(8, 8)}
* getAction({G_ADD, LLT::vector(20, 8)})
returns {FewerElements, LLT::vector(16, 8)}
2. Key implementation aspects.
How to legalize a specific (operation, type index, size) tuple is
represented by mapping intervals of integers representing a range of
size types to an action to take, e.g.:
setScalarAction({G_ADD, LLT:scalar(1)},
{{1, WidenScalar}, // bit sizes [ 1, 31[
{32, Legal}, // bit sizes [32, 33[
{33, WidenScalar}, // bit sizes [33, 64[
{64, Legal}, // bit sizes [64, 65[
{65, NarrowScalar} // bit sizes [65, +inf[
});
Please note that most of the code to do the actual lowering of
non-power-of-2 sized types is currently missing, this is just trying to
make it possible for targets to specify what is legal, and how non-legal
types should be legalized. Probably quite a bit of further work is
needed in the actual legalizing and the other passes in GlobalISel to
support non-power-of-2 sized types.
I hope the documentation in LegalizerInfo.h and the examples provided in the
various {Target}LegalizerInfo.cpp and LegalizerInfoTest.cpp explains well
enough how this is meant to be used.
This drops the need for LLT::{half,double}...Size().
Differential Revision: https://reviews.llvm.org/D30529
llvm-svn: 317560
2017-11-07 18:34:34 +08:00
|
|
|
// FIXME: add support for when SizeOp0 isn't an exact multiple of
|
|
|
|
// NarrowSize.
|
|
|
|
if (SizeOp0 % NarrowSize != 0)
|
|
|
|
return UnableToLegalize;
|
|
|
|
int NumParts = SizeOp0 / NarrowSize;
|
[globalisel][legalizer] G_LOAD/G_STORE NarrowScalar should not emit G_GEP x, 0.
Summary:
When legalizing G_LOAD/G_STORE using NarrowScalar, we should avoid emitting
%0 = G_CONSTANT ty 0
%1 = G_GEP %x, %0
since it's cheaper to not emit the redundant instructions than it is to fold them
away later.
Reviewers: qcolombet, t.p.northover, ab, rovka, aditya_nandakumar, kristof.beyls
Reviewed By: qcolombet
Subscribers: javed.absar, llvm-commits, igorb
Differential Revision: https://reviews.llvm.org/D32746
llvm-svn: 305340
2017-06-14 07:42:32 +08:00
|
|
|
LLT OffsetTy = LLT::scalar(
|
|
|
|
MRI.getType(MI.getOperand(1).getReg()).getScalarSizeInBits());
|
2017-01-19 01:29:54 +08:00
|
|
|
|
|
|
|
SmallVector<unsigned, 2> SrcRegs;
|
|
|
|
extractParts(MI.getOperand(0).getReg(), NarrowTy, NumParts, SrcRegs);
|
|
|
|
|
|
|
|
for (int i = 0; i < NumParts; ++i) {
|
[globalisel][legalizer] G_LOAD/G_STORE NarrowScalar should not emit G_GEP x, 0.
Summary:
When legalizing G_LOAD/G_STORE using NarrowScalar, we should avoid emitting
%0 = G_CONSTANT ty 0
%1 = G_GEP %x, %0
since it's cheaper to not emit the redundant instructions than it is to fold them
away later.
Reviewers: qcolombet, t.p.northover, ab, rovka, aditya_nandakumar, kristof.beyls
Reviewed By: qcolombet
Subscribers: javed.absar, llvm-commits, igorb
Differential Revision: https://reviews.llvm.org/D32746
llvm-svn: 305340
2017-06-14 07:42:32 +08:00
|
|
|
unsigned DstReg = 0;
|
|
|
|
unsigned Adjustment = i * NarrowSize / 8;
|
|
|
|
|
|
|
|
MIRBuilder.materializeGEP(DstReg, MI.getOperand(1).getReg(), OffsetTy,
|
|
|
|
Adjustment);
|
|
|
|
|
2017-01-20 08:30:17 +08:00
|
|
|
// TODO: This is conservatively correct, but we probably want to split the
|
|
|
|
// memory operands in the future.
|
2017-01-19 01:29:54 +08:00
|
|
|
MIRBuilder.buildStore(SrcRegs[i], DstReg, **MI.memoperands_begin());
|
|
|
|
}
|
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2017-04-07 22:41:59 +08:00
|
|
|
case TargetOpcode::G_CONSTANT: {
|
[GlobalISel] Enable legalizing non-power-of-2 sized types.
This changes the interface of how targets describe how to legalize, see
the below description.
1. Interface for targets to describe how to legalize.
In GlobalISel, the API in the LegalizerInfo class is the main interface
for targets to specify which types are legal for which operations, and
what to do to turn illegal type/operation combinations into legal ones.
For each operation the type sizes that can be legalized without having
to change the size of the type are specified with a call to setAction.
This isn't different to how GlobalISel worked before. For example, for a
target that supports 32 and 64 bit adds natively:
for (auto Ty : {s32, s64})
setAction({G_ADD, 0, s32}, Legal);
or for a target that needs a library call for a 32 bit division:
setAction({G_SDIV, s32}, Libcall);
The main conceptual change to the LegalizerInfo API, is in specifying
how to legalize the type sizes for which a change of size is needed. For
example, in the above example, how to specify how all types from i1 to
i8388607 (apart from s32 and s64 which are legal) need to be legalized
and expressed in terms of operations on the available legal sizes
(again, i32 and i64 in this case). Before, the implementation only
allowed specifying power-of-2-sized types (e.g. setAction({G_ADD, 0,
s128}, NarrowScalar). A worse limitation was that if you'd wanted to
specify how to legalize all the sized types as allowed by the LLVM-IR
LangRef, i1 to i8388607, you'd have to call setAction 8388607-3 times
and probably would need a lot of memory to store all of these
specifications.
Instead, the legalization actions that need to change the size of the
type are specified now using a "SizeChangeStrategy". For example:
setLegalizeScalarToDifferentSizeStrategy(
G_ADD, 0, widenToLargerAndNarrowToLargest);
This example indicates that for type sizes for which there is a larger
size that can be legalized towards, do it by Widening the size.
For example, G_ADD on s17 will be legalized by first doing WidenScalar
to make it s32, after which it's legal.
The "NarrowToLargest" indicates what to do if there is no larger size
that can be legalized towards. E.g. G_ADD on s92 will be legalized by
doing NarrowScalar to s64.
Another example, taken from the ARM backend is:
for (unsigned Op : {G_SDIV, G_UDIV}) {
setLegalizeScalarToDifferentSizeStrategy(Op, 0,
widenToLargerTypesUnsupportedOtherwise);
if (ST.hasDivideInARMMode())
setAction({Op, s32}, Legal);
else
setAction({Op, s32}, Libcall);
}
For this example, G_SDIV on s8, on a target without a divide
instruction, would be legalized by first doing action (WidenScalar,
s32), followed by (Libcall, s32).
The same principle is also followed for when the number of vector lanes
on vector data types need to be changed, e.g.:
setAction({G_ADD, LLT::vector(8, 8)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(16, 8)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(4, 16)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(8, 16)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(2, 32)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(4, 32)}, LegalizerInfo::Legal);
setLegalizeVectorElementToDifferentSizeStrategy(
G_ADD, 0, widenToLargerTypesUnsupportedOtherwise);
As currently implemented here, vector types are legalized by first
making the vector element size legal, followed by then making the number
of lanes legal. The strategy to follow in the first step is set by a
call to setLegalizeVectorElementToDifferentSizeStrategy, see example
above. The strategy followed in the second step
"moreToWiderTypesAndLessToWidest" (see code for its definition),
indicating that vectors are widened to more elements so they map to
natively supported vector widths, or when there isn't a legal wider
vector, split the vector to map it to the widest vector supported.
Therefore, for the above specification, some example legalizations are:
* getAction({G_ADD, LLT::vector(3, 3)})
returns {WidenScalar, LLT::vector(3, 8)}
* getAction({G_ADD, LLT::vector(3, 8)})
then returns {MoreElements, LLT::vector(8, 8)}
* getAction({G_ADD, LLT::vector(20, 8)})
returns {FewerElements, LLT::vector(16, 8)}
2. Key implementation aspects.
How to legalize a specific (operation, type index, size) tuple is
represented by mapping intervals of integers representing a range of
size types to an action to take, e.g.:
setScalarAction({G_ADD, LLT:scalar(1)},
{{1, WidenScalar}, // bit sizes [ 1, 31[
{32, Legal}, // bit sizes [32, 33[
{33, WidenScalar}, // bit sizes [33, 64[
{64, Legal}, // bit sizes [64, 65[
{65, NarrowScalar} // bit sizes [65, +inf[
});
Please note that most of the code to do the actual lowering of
non-power-of-2 sized types is currently missing, this is just trying to
make it possible for targets to specify what is legal, and how non-legal
types should be legalized. Probably quite a bit of further work is
needed in the actual legalizing and the other passes in GlobalISel to
support non-power-of-2 sized types.
I hope the documentation in LegalizerInfo.h and the examples provided in the
various {Target}LegalizerInfo.cpp and LegalizerInfoTest.cpp explains well
enough how this is meant to be used.
This drops the need for LLT::{half,double}...Size().
Differential Revision: https://reviews.llvm.org/D30529
llvm-svn: 317560
2017-11-07 18:34:34 +08:00
|
|
|
// FIXME: add support for when SizeOp0 isn't an exact multiple of
|
|
|
|
// NarrowSize.
|
|
|
|
if (SizeOp0 % NarrowSize != 0)
|
|
|
|
return UnableToLegalize;
|
|
|
|
int NumParts = SizeOp0 / NarrowSize;
|
2017-04-07 22:41:59 +08:00
|
|
|
const APInt &Cst = MI.getOperand(1).getCImm()->getValue();
|
|
|
|
LLVMContext &Ctx = MIRBuilder.getMF().getFunction()->getContext();
|
|
|
|
|
|
|
|
SmallVector<unsigned, 2> DstRegs;
|
|
|
|
for (int i = 0; i < NumParts; ++i) {
|
|
|
|
unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy);
|
|
|
|
ConstantInt *CI =
|
|
|
|
ConstantInt::get(Ctx, Cst.lshr(NarrowSize * i).trunc(NarrowSize));
|
|
|
|
MIRBuilder.buildConstant(DstReg, *CI);
|
|
|
|
DstRegs.push_back(DstReg);
|
|
|
|
}
|
|
|
|
unsigned DstReg = MI.getOperand(0).getReg();
|
|
|
|
MIRBuilder.buildMerge(DstReg, DstRegs);
|
2017-10-03 12:53:56 +08:00
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
|
|
|
case TargetOpcode::G_OR: {
|
|
|
|
// Legalize bitwise operation:
|
|
|
|
// A = BinOp<Ty> B, C
|
|
|
|
// into:
|
|
|
|
// B1, ..., BN = G_UNMERGE_VALUES B
|
|
|
|
// C1, ..., CN = G_UNMERGE_VALUES C
|
|
|
|
// A1 = BinOp<Ty/N> B1, C2
|
|
|
|
// ...
|
|
|
|
// AN = BinOp<Ty/N> BN, CN
|
|
|
|
// A = G_MERGE_VALUES A1, ..., AN
|
[GlobalISel] Enable legalizing non-power-of-2 sized types.
This changes the interface of how targets describe how to legalize, see
the below description.
1. Interface for targets to describe how to legalize.
In GlobalISel, the API in the LegalizerInfo class is the main interface
for targets to specify which types are legal for which operations, and
what to do to turn illegal type/operation combinations into legal ones.
For each operation the type sizes that can be legalized without having
to change the size of the type are specified with a call to setAction.
This isn't different to how GlobalISel worked before. For example, for a
target that supports 32 and 64 bit adds natively:
for (auto Ty : {s32, s64})
setAction({G_ADD, 0, s32}, Legal);
or for a target that needs a library call for a 32 bit division:
setAction({G_SDIV, s32}, Libcall);
The main conceptual change to the LegalizerInfo API, is in specifying
how to legalize the type sizes for which a change of size is needed. For
example, in the above example, how to specify how all types from i1 to
i8388607 (apart from s32 and s64 which are legal) need to be legalized
and expressed in terms of operations on the available legal sizes
(again, i32 and i64 in this case). Before, the implementation only
allowed specifying power-of-2-sized types (e.g. setAction({G_ADD, 0,
s128}, NarrowScalar). A worse limitation was that if you'd wanted to
specify how to legalize all the sized types as allowed by the LLVM-IR
LangRef, i1 to i8388607, you'd have to call setAction 8388607-3 times
and probably would need a lot of memory to store all of these
specifications.
Instead, the legalization actions that need to change the size of the
type are specified now using a "SizeChangeStrategy". For example:
setLegalizeScalarToDifferentSizeStrategy(
G_ADD, 0, widenToLargerAndNarrowToLargest);
This example indicates that for type sizes for which there is a larger
size that can be legalized towards, do it by Widening the size.
For example, G_ADD on s17 will be legalized by first doing WidenScalar
to make it s32, after which it's legal.
The "NarrowToLargest" indicates what to do if there is no larger size
that can be legalized towards. E.g. G_ADD on s92 will be legalized by
doing NarrowScalar to s64.
Another example, taken from the ARM backend is:
for (unsigned Op : {G_SDIV, G_UDIV}) {
setLegalizeScalarToDifferentSizeStrategy(Op, 0,
widenToLargerTypesUnsupportedOtherwise);
if (ST.hasDivideInARMMode())
setAction({Op, s32}, Legal);
else
setAction({Op, s32}, Libcall);
}
For this example, G_SDIV on s8, on a target without a divide
instruction, would be legalized by first doing action (WidenScalar,
s32), followed by (Libcall, s32).
The same principle is also followed for when the number of vector lanes
on vector data types need to be changed, e.g.:
setAction({G_ADD, LLT::vector(8, 8)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(16, 8)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(4, 16)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(8, 16)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(2, 32)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(4, 32)}, LegalizerInfo::Legal);
setLegalizeVectorElementToDifferentSizeStrategy(
G_ADD, 0, widenToLargerTypesUnsupportedOtherwise);
As currently implemented here, vector types are legalized by first
making the vector element size legal, followed by then making the number
of lanes legal. The strategy to follow in the first step is set by a
call to setLegalizeVectorElementToDifferentSizeStrategy, see example
above. The strategy followed in the second step
"moreToWiderTypesAndLessToWidest" (see code for its definition),
indicating that vectors are widened to more elements so they map to
natively supported vector widths, or when there isn't a legal wider
vector, split the vector to map it to the widest vector supported.
Therefore, for the above specification, some example legalizations are:
* getAction({G_ADD, LLT::vector(3, 3)})
returns {WidenScalar, LLT::vector(3, 8)}
* getAction({G_ADD, LLT::vector(3, 8)})
then returns {MoreElements, LLT::vector(8, 8)}
* getAction({G_ADD, LLT::vector(20, 8)})
returns {FewerElements, LLT::vector(16, 8)}
2. Key implementation aspects.
How to legalize a specific (operation, type index, size) tuple is
represented by mapping intervals of integers representing a range of
size types to an action to take, e.g.:
setScalarAction({G_ADD, LLT:scalar(1)},
{{1, WidenScalar}, // bit sizes [ 1, 31[
{32, Legal}, // bit sizes [32, 33[
{33, WidenScalar}, // bit sizes [33, 64[
{64, Legal}, // bit sizes [64, 65[
{65, NarrowScalar} // bit sizes [65, +inf[
});
Please note that most of the code to do the actual lowering of
non-power-of-2 sized types is currently missing, this is just trying to
make it possible for targets to specify what is legal, and how non-legal
types should be legalized. Probably quite a bit of further work is
needed in the actual legalizing and the other passes in GlobalISel to
support non-power-of-2 sized types.
I hope the documentation in LegalizerInfo.h and the examples provided in the
various {Target}LegalizerInfo.cpp and LegalizerInfoTest.cpp explains well
enough how this is meant to be used.
This drops the need for LLT::{half,double}...Size().
Differential Revision: https://reviews.llvm.org/D30529
llvm-svn: 317560
2017-11-07 18:34:34 +08:00
|
|
|
|
|
|
|
// FIXME: add support for when SizeOp0 isn't an exact multiple of
|
|
|
|
// NarrowSize.
|
|
|
|
if (SizeOp0 % NarrowSize != 0)
|
|
|
|
return UnableToLegalize;
|
|
|
|
int NumParts = SizeOp0 / NarrowSize;
|
2017-10-03 12:53:56 +08:00
|
|
|
|
|
|
|
// List the registers where the destination will be scattered.
|
|
|
|
SmallVector<unsigned, 2> DstRegs;
|
|
|
|
// List the registers where the first argument will be split.
|
|
|
|
SmallVector<unsigned, 2> SrcsReg1;
|
|
|
|
// List the registers where the second argument will be split.
|
|
|
|
SmallVector<unsigned, 2> SrcsReg2;
|
|
|
|
// Create all the temporary registers.
|
|
|
|
for (int i = 0; i < NumParts; ++i) {
|
|
|
|
unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy);
|
|
|
|
unsigned SrcReg1 = MRI.createGenericVirtualRegister(NarrowTy);
|
|
|
|
unsigned SrcReg2 = MRI.createGenericVirtualRegister(NarrowTy);
|
|
|
|
|
|
|
|
DstRegs.push_back(DstReg);
|
|
|
|
SrcsReg1.push_back(SrcReg1);
|
|
|
|
SrcsReg2.push_back(SrcReg2);
|
|
|
|
}
|
|
|
|
// Explode the big arguments into smaller chunks.
|
|
|
|
MIRBuilder.buildUnmerge(SrcsReg1, MI.getOperand(1).getReg());
|
|
|
|
MIRBuilder.buildUnmerge(SrcsReg2, MI.getOperand(2).getReg());
|
|
|
|
|
|
|
|
// Do the operation on each small part.
|
|
|
|
for (int i = 0; i < NumParts; ++i)
|
|
|
|
MIRBuilder.buildOr(DstRegs[i], SrcsReg1[i], SrcsReg2[i]);
|
|
|
|
|
|
|
|
// Gather the destination registers into the final destination.
|
|
|
|
unsigned DstReg = MI.getOperand(0).getReg();
|
|
|
|
MIRBuilder.buildMerge(DstReg, DstRegs);
|
2017-04-07 22:41:59 +08:00
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2016-08-05 04:54:13 +08:00
|
|
|
}
|
2016-07-23 04:03:43 +08:00
|
|
|
}
|
|
|
|
|
2016-10-15 06:18:18 +08:00
|
|
|
LegalizerHelper::LegalizeResult
|
|
|
|
LegalizerHelper::widenScalar(MachineInstr &MI, unsigned TypeIdx, LLT WideTy) {
|
2016-08-24 02:20:09 +08:00
|
|
|
MIRBuilder.setInstr(MI);
|
|
|
|
|
2016-08-05 02:35:11 +08:00
|
|
|
switch (MI.getOpcode()) {
|
|
|
|
default:
|
|
|
|
return UnableToLegalize;
|
2016-08-05 05:39:49 +08:00
|
|
|
case TargetOpcode::G_ADD:
|
|
|
|
case TargetOpcode::G_AND:
|
|
|
|
case TargetOpcode::G_MUL:
|
|
|
|
case TargetOpcode::G_OR:
|
|
|
|
case TargetOpcode::G_XOR:
|
2017-01-19 15:51:17 +08:00
|
|
|
case TargetOpcode::G_SUB:
|
|
|
|
case TargetOpcode::G_SHL: {
|
2016-08-05 02:35:11 +08:00
|
|
|
// Perform operation at larger width (any extension is fine here, high bits
|
|
|
|
// don't affect the result) and then truncate the result back to the
|
|
|
|
// original type.
|
2016-09-09 19:46:34 +08:00
|
|
|
unsigned Src1Ext = MRI.createGenericVirtualRegister(WideTy);
|
|
|
|
unsigned Src2Ext = MRI.createGenericVirtualRegister(WideTy);
|
|
|
|
MIRBuilder.buildAnyExt(Src1Ext, MI.getOperand(1).getReg());
|
|
|
|
MIRBuilder.buildAnyExt(Src2Ext, MI.getOperand(2).getReg());
|
|
|
|
|
|
|
|
unsigned DstExt = MRI.createGenericVirtualRegister(WideTy);
|
|
|
|
MIRBuilder.buildInstr(MI.getOpcode())
|
|
|
|
.addDef(DstExt)
|
|
|
|
.addUse(Src1Ext)
|
|
|
|
.addUse(Src2Ext);
|
|
|
|
|
|
|
|
MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt);
|
2016-08-05 02:35:11 +08:00
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2016-08-27 01:46:06 +08:00
|
|
|
case TargetOpcode::G_SDIV:
|
2017-01-19 15:51:17 +08:00
|
|
|
case TargetOpcode::G_UDIV:
|
2017-07-18 17:08:47 +08:00
|
|
|
case TargetOpcode::G_SREM:
|
|
|
|
case TargetOpcode::G_UREM:
|
2017-01-19 15:51:17 +08:00
|
|
|
case TargetOpcode::G_ASHR:
|
|
|
|
case TargetOpcode::G_LSHR: {
|
|
|
|
unsigned ExtOp = MI.getOpcode() == TargetOpcode::G_SDIV ||
|
2017-07-18 17:08:47 +08:00
|
|
|
MI.getOpcode() == TargetOpcode::G_SREM ||
|
2017-01-19 15:51:17 +08:00
|
|
|
MI.getOpcode() == TargetOpcode::G_ASHR
|
|
|
|
? TargetOpcode::G_SEXT
|
|
|
|
: TargetOpcode::G_ZEXT;
|
2016-08-27 01:46:06 +08:00
|
|
|
|
2016-09-09 19:46:34 +08:00
|
|
|
unsigned LHSExt = MRI.createGenericVirtualRegister(WideTy);
|
|
|
|
MIRBuilder.buildInstr(ExtOp).addDef(LHSExt).addUse(
|
|
|
|
MI.getOperand(1).getReg());
|
2016-08-27 01:46:06 +08:00
|
|
|
|
2016-09-09 19:46:34 +08:00
|
|
|
unsigned RHSExt = MRI.createGenericVirtualRegister(WideTy);
|
|
|
|
MIRBuilder.buildInstr(ExtOp).addDef(RHSExt).addUse(
|
|
|
|
MI.getOperand(2).getReg());
|
2016-08-27 01:46:06 +08:00
|
|
|
|
2016-09-09 19:46:34 +08:00
|
|
|
unsigned ResExt = MRI.createGenericVirtualRegister(WideTy);
|
|
|
|
MIRBuilder.buildInstr(MI.getOpcode())
|
2016-08-27 01:46:06 +08:00
|
|
|
.addDef(ResExt)
|
|
|
|
.addUse(LHSExt)
|
|
|
|
.addUse(RHSExt);
|
|
|
|
|
2016-09-09 19:46:34 +08:00
|
|
|
MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), ResExt);
|
2016-08-27 01:46:06 +08:00
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2017-02-07 07:41:27 +08:00
|
|
|
case TargetOpcode::G_SELECT: {
|
|
|
|
if (TypeIdx != 0)
|
|
|
|
return UnableToLegalize;
|
|
|
|
|
|
|
|
// Perform operation at larger width (any extension is fine here, high bits
|
|
|
|
// don't affect the result) and then truncate the result back to the
|
|
|
|
// original type.
|
|
|
|
unsigned Src1Ext = MRI.createGenericVirtualRegister(WideTy);
|
|
|
|
unsigned Src2Ext = MRI.createGenericVirtualRegister(WideTy);
|
|
|
|
MIRBuilder.buildAnyExt(Src1Ext, MI.getOperand(2).getReg());
|
|
|
|
MIRBuilder.buildAnyExt(Src2Ext, MI.getOperand(3).getReg());
|
|
|
|
|
|
|
|
unsigned DstExt = MRI.createGenericVirtualRegister(WideTy);
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_SELECT)
|
|
|
|
.addDef(DstExt)
|
|
|
|
.addReg(MI.getOperand(1).getReg())
|
|
|
|
.addUse(Src1Ext)
|
|
|
|
.addUse(Src2Ext);
|
|
|
|
|
|
|
|
MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt);
|
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2017-01-24 05:10:14 +08:00
|
|
|
case TargetOpcode::G_FPTOSI:
|
|
|
|
case TargetOpcode::G_FPTOUI: {
|
|
|
|
if (TypeIdx != 0)
|
|
|
|
return UnableToLegalize;
|
|
|
|
|
|
|
|
unsigned DstExt = MRI.createGenericVirtualRegister(WideTy);
|
|
|
|
MIRBuilder.buildInstr(MI.getOpcode())
|
|
|
|
.addDef(DstExt)
|
|
|
|
.addUse(MI.getOperand(1).getReg());
|
|
|
|
|
|
|
|
MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt);
|
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2017-01-20 09:37:24 +08:00
|
|
|
case TargetOpcode::G_SITOFP:
|
|
|
|
case TargetOpcode::G_UITOFP: {
|
|
|
|
if (TypeIdx != 1)
|
|
|
|
return UnableToLegalize;
|
|
|
|
|
|
|
|
unsigned Src = MI.getOperand(1).getReg();
|
|
|
|
unsigned SrcExt = MRI.createGenericVirtualRegister(WideTy);
|
|
|
|
|
|
|
|
if (MI.getOpcode() == TargetOpcode::G_SITOFP) {
|
|
|
|
MIRBuilder.buildSExt(SrcExt, Src);
|
|
|
|
} else {
|
|
|
|
assert(MI.getOpcode() == TargetOpcode::G_UITOFP && "Unexpected conv op");
|
|
|
|
MIRBuilder.buildZExt(SrcExt, Src);
|
|
|
|
}
|
|
|
|
|
|
|
|
MIRBuilder.buildInstr(MI.getOpcode())
|
|
|
|
.addDef(MI.getOperand(0).getReg())
|
|
|
|
.addUse(SrcExt);
|
|
|
|
|
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2017-02-07 05:56:47 +08:00
|
|
|
case TargetOpcode::G_INSERT: {
|
|
|
|
if (TypeIdx != 0)
|
|
|
|
return UnableToLegalize;
|
|
|
|
|
|
|
|
unsigned Src = MI.getOperand(1).getReg();
|
|
|
|
unsigned SrcExt = MRI.createGenericVirtualRegister(WideTy);
|
|
|
|
MIRBuilder.buildAnyExt(SrcExt, Src);
|
|
|
|
|
|
|
|
unsigned DstExt = MRI.createGenericVirtualRegister(WideTy);
|
|
|
|
auto MIB = MIRBuilder.buildInsert(DstExt, SrcExt, MI.getOperand(2).getReg(),
|
|
|
|
MI.getOperand(3).getImm());
|
|
|
|
for (unsigned OpNum = 4; OpNum < MI.getNumOperands(); OpNum += 2) {
|
|
|
|
MIB.addReg(MI.getOperand(OpNum).getReg());
|
|
|
|
MIB.addImm(MI.getOperand(OpNum + 1).getImm());
|
|
|
|
}
|
|
|
|
|
|
|
|
MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt);
|
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2016-08-24 02:20:09 +08:00
|
|
|
case TargetOpcode::G_LOAD: {
|
2016-09-10 02:37:08 +08:00
|
|
|
assert(alignTo(MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(), 8) ==
|
|
|
|
WideTy.getSizeInBits() &&
|
2016-08-24 02:20:09 +08:00
|
|
|
"illegal to increase number of bytes loaded");
|
|
|
|
|
2016-09-09 19:46:34 +08:00
|
|
|
unsigned DstExt = MRI.createGenericVirtualRegister(WideTy);
|
|
|
|
MIRBuilder.buildLoad(DstExt, MI.getOperand(1).getReg(),
|
|
|
|
**MI.memoperands_begin());
|
|
|
|
MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt);
|
2016-08-24 02:20:09 +08:00
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
|
|
|
case TargetOpcode::G_STORE: {
|
2017-03-22 06:22:05 +08:00
|
|
|
if (MRI.getType(MI.getOperand(0).getReg()) != LLT::scalar(1) ||
|
|
|
|
WideTy != LLT::scalar(8))
|
|
|
|
return UnableToLegalize;
|
|
|
|
|
|
|
|
auto &TLI = *MIRBuilder.getMF().getSubtarget().getTargetLowering();
|
|
|
|
auto Content = TLI.getBooleanContents(false, false);
|
|
|
|
|
|
|
|
unsigned ExtOp = TargetOpcode::G_ANYEXT;
|
|
|
|
if (Content == TargetLoweringBase::ZeroOrOneBooleanContent)
|
|
|
|
ExtOp = TargetOpcode::G_ZEXT;
|
|
|
|
else if (Content == TargetLoweringBase::ZeroOrNegativeOneBooleanContent)
|
|
|
|
ExtOp = TargetOpcode::G_SEXT;
|
|
|
|
else
|
|
|
|
ExtOp = TargetOpcode::G_ANYEXT;
|
2016-08-24 02:20:09 +08:00
|
|
|
|
2016-09-09 19:46:34 +08:00
|
|
|
unsigned SrcExt = MRI.createGenericVirtualRegister(WideTy);
|
2017-03-22 06:22:05 +08:00
|
|
|
MIRBuilder.buildInstr(ExtOp).addDef(SrcExt).addUse(
|
|
|
|
MI.getOperand(0).getReg());
|
2016-09-09 19:46:34 +08:00
|
|
|
MIRBuilder.buildStore(SrcExt, MI.getOperand(1).getReg(),
|
|
|
|
**MI.memoperands_begin());
|
2016-08-24 02:20:09 +08:00
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2016-08-20 06:40:00 +08:00
|
|
|
case TargetOpcode::G_CONSTANT: {
|
2016-09-09 19:46:34 +08:00
|
|
|
unsigned DstExt = MRI.createGenericVirtualRegister(WideTy);
|
2016-12-06 05:47:07 +08:00
|
|
|
MIRBuilder.buildConstant(DstExt, *MI.getOperand(1).getCImm());
|
2016-09-09 19:46:34 +08:00
|
|
|
MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), DstExt);
|
2016-08-20 06:40:00 +08:00
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2016-08-20 06:40:08 +08:00
|
|
|
case TargetOpcode::G_FCONSTANT: {
|
2016-09-09 19:46:34 +08:00
|
|
|
unsigned DstExt = MRI.createGenericVirtualRegister(WideTy);
|
|
|
|
MIRBuilder.buildFConstant(DstExt, *MI.getOperand(1).getFPImm());
|
|
|
|
MIRBuilder.buildFPTrunc(MI.getOperand(0).getReg(), DstExt);
|
2016-08-20 06:40:08 +08:00
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2016-08-24 05:01:20 +08:00
|
|
|
case TargetOpcode::G_BRCOND: {
|
2016-09-09 19:46:34 +08:00
|
|
|
unsigned TstExt = MRI.createGenericVirtualRegister(WideTy);
|
|
|
|
MIRBuilder.buildAnyExt(TstExt, MI.getOperand(0).getReg());
|
|
|
|
MIRBuilder.buildBrCond(TstExt, *MI.getOperand(1).getMBB());
|
2016-08-24 05:01:20 +08:00
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2017-08-01 01:00:16 +08:00
|
|
|
case TargetOpcode::G_FCMP: {
|
|
|
|
unsigned Op0Ext, Op1Ext, DstReg;
|
|
|
|
unsigned Cmp1 = MI.getOperand(2).getReg();
|
|
|
|
unsigned Cmp2 = MI.getOperand(3).getReg();
|
|
|
|
if (TypeIdx == 0) {
|
|
|
|
Op0Ext = Cmp1;
|
|
|
|
Op1Ext = Cmp2;
|
|
|
|
DstReg = MRI.createGenericVirtualRegister(WideTy);
|
|
|
|
} else {
|
|
|
|
Op0Ext = MRI.createGenericVirtualRegister(WideTy);
|
|
|
|
Op1Ext = MRI.createGenericVirtualRegister(WideTy);
|
|
|
|
DstReg = MI.getOperand(0).getReg();
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_FPEXT, Op0Ext, Cmp1);
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_FPEXT, Op1Ext, Cmp2);
|
|
|
|
}
|
|
|
|
MIRBuilder.buildFCmp(
|
|
|
|
static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate()),
|
|
|
|
DstReg, Op0Ext, Op1Ext);
|
|
|
|
if (TypeIdx == 0)
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_TRUNC, MI.getOperand(0).getReg(),
|
|
|
|
DstReg);
|
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2016-08-24 05:01:26 +08:00
|
|
|
case TargetOpcode::G_ICMP: {
|
2016-08-27 01:46:17 +08:00
|
|
|
bool IsSigned = CmpInst::isSigned(
|
|
|
|
static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate()));
|
2017-08-01 01:00:16 +08:00
|
|
|
unsigned Cmp1 = MI.getOperand(2).getReg();
|
|
|
|
unsigned Cmp2 = MI.getOperand(3).getReg();
|
|
|
|
unsigned Op0Ext, Op1Ext, DstReg;
|
|
|
|
if (TypeIdx == 0) {
|
|
|
|
Op0Ext = Cmp1;
|
|
|
|
Op1Ext = Cmp2;
|
|
|
|
DstReg = MRI.createGenericVirtualRegister(WideTy);
|
2016-08-24 05:01:26 +08:00
|
|
|
} else {
|
2017-08-01 01:00:16 +08:00
|
|
|
Op0Ext = MRI.createGenericVirtualRegister(WideTy);
|
|
|
|
Op1Ext = MRI.createGenericVirtualRegister(WideTy);
|
|
|
|
DstReg = MI.getOperand(0).getReg();
|
|
|
|
if (IsSigned) {
|
|
|
|
MIRBuilder.buildSExt(Op0Ext, Cmp1);
|
|
|
|
MIRBuilder.buildSExt(Op1Ext, Cmp2);
|
|
|
|
} else {
|
|
|
|
MIRBuilder.buildZExt(Op0Ext, Cmp1);
|
|
|
|
MIRBuilder.buildZExt(Op1Ext, Cmp2);
|
|
|
|
}
|
2016-08-24 05:01:26 +08:00
|
|
|
}
|
2016-08-27 01:46:17 +08:00
|
|
|
MIRBuilder.buildICmp(
|
|
|
|
static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate()),
|
2017-08-01 01:00:16 +08:00
|
|
|
DstReg, Op0Ext, Op1Ext);
|
|
|
|
if (TypeIdx == 0)
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_TRUNC, MI.getOperand(0).getReg(),
|
|
|
|
DstReg);
|
2016-08-27 01:46:17 +08:00
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
2016-08-24 05:01:26 +08:00
|
|
|
}
|
2016-09-15 19:02:19 +08:00
|
|
|
case TargetOpcode::G_GEP: {
|
|
|
|
assert(TypeIdx == 1 && "unable to legalize pointer of GEP");
|
|
|
|
unsigned OffsetExt = MRI.createGenericVirtualRegister(WideTy);
|
|
|
|
MIRBuilder.buildSExt(OffsetExt, MI.getOperand(2).getReg());
|
|
|
|
MI.getOperand(2).setReg(OffsetExt);
|
|
|
|
return Legalized;
|
|
|
|
}
|
2017-08-25 12:57:27 +08:00
|
|
|
case TargetOpcode::G_PHI: {
|
|
|
|
assert(TypeIdx == 0 && "Expecting only Idx 0");
|
2017-08-26 00:46:07 +08:00
|
|
|
auto getExtendedReg = [&](unsigned Reg, MachineBasicBlock &MBB) {
|
2017-08-25 12:57:27 +08:00
|
|
|
auto FirstTermIt = MBB.getFirstTerminator();
|
|
|
|
MIRBuilder.setInsertPt(MBB, FirstTermIt);
|
|
|
|
MachineInstr *DefMI = MRI.getVRegDef(Reg);
|
|
|
|
MachineInstrBuilder MIB;
|
|
|
|
if (DefMI->getOpcode() == TargetOpcode::G_TRUNC)
|
|
|
|
MIB = MIRBuilder.buildAnyExtOrTrunc(WideTy,
|
|
|
|
DefMI->getOperand(1).getReg());
|
|
|
|
else
|
|
|
|
MIB = MIRBuilder.buildAnyExt(WideTy, Reg);
|
|
|
|
return MIB->getOperand(0).getReg();
|
|
|
|
};
|
|
|
|
auto MIB = MIRBuilder.buildInstr(TargetOpcode::G_PHI, WideTy);
|
|
|
|
for (auto OpIt = MI.operands_begin() + 1, OpE = MI.operands_end();
|
|
|
|
OpIt != OpE;) {
|
|
|
|
unsigned Reg = OpIt++->getReg();
|
|
|
|
MachineBasicBlock *OpMBB = OpIt++->getMBB();
|
|
|
|
MIB.addReg(getExtendedReg(Reg, *OpMBB));
|
|
|
|
MIB.addMBB(OpMBB);
|
|
|
|
}
|
|
|
|
auto *MBB = MI.getParent();
|
|
|
|
MIRBuilder.setInsertPt(*MBB, MBB->getFirstNonPHI());
|
|
|
|
MIRBuilder.buildTrunc(MI.getOperand(0).getReg(),
|
|
|
|
MIB->getOperand(0).getReg());
|
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2016-08-05 02:35:11 +08:00
|
|
|
}
|
2016-07-23 04:03:43 +08:00
|
|
|
}
|
|
|
|
|
2016-10-15 06:18:18 +08:00
|
|
|
LegalizerHelper::LegalizeResult
|
|
|
|
LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT Ty) {
|
2016-08-27 01:46:13 +08:00
|
|
|
using namespace TargetOpcode;
|
|
|
|
MIRBuilder.setInstr(MI);
|
|
|
|
|
|
|
|
switch(MI.getOpcode()) {
|
|
|
|
default:
|
|
|
|
return UnableToLegalize;
|
|
|
|
case TargetOpcode::G_SREM:
|
|
|
|
case TargetOpcode::G_UREM: {
|
2016-09-09 19:46:34 +08:00
|
|
|
unsigned QuotReg = MRI.createGenericVirtualRegister(Ty);
|
|
|
|
MIRBuilder.buildInstr(MI.getOpcode() == G_SREM ? G_SDIV : G_UDIV)
|
2016-08-27 01:46:13 +08:00
|
|
|
.addDef(QuotReg)
|
|
|
|
.addUse(MI.getOperand(1).getReg())
|
|
|
|
.addUse(MI.getOperand(2).getReg());
|
|
|
|
|
2016-09-09 19:46:34 +08:00
|
|
|
unsigned ProdReg = MRI.createGenericVirtualRegister(Ty);
|
|
|
|
MIRBuilder.buildMul(ProdReg, QuotReg, MI.getOperand(2).getReg());
|
|
|
|
MIRBuilder.buildSub(MI.getOperand(0).getReg(), MI.getOperand(1).getReg(),
|
|
|
|
ProdReg);
|
2016-08-27 01:46:13 +08:00
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2017-02-09 05:22:15 +08:00
|
|
|
case TargetOpcode::G_SMULO:
|
|
|
|
case TargetOpcode::G_UMULO: {
|
|
|
|
// Generate G_UMULH/G_SMULH to check for overflow and a normal G_MUL for the
|
|
|
|
// result.
|
|
|
|
unsigned Res = MI.getOperand(0).getReg();
|
|
|
|
unsigned Overflow = MI.getOperand(1).getReg();
|
|
|
|
unsigned LHS = MI.getOperand(2).getReg();
|
|
|
|
unsigned RHS = MI.getOperand(3).getReg();
|
|
|
|
|
|
|
|
MIRBuilder.buildMul(Res, LHS, RHS);
|
|
|
|
|
|
|
|
unsigned Opcode = MI.getOpcode() == TargetOpcode::G_SMULO
|
|
|
|
? TargetOpcode::G_SMULH
|
|
|
|
: TargetOpcode::G_UMULH;
|
|
|
|
|
|
|
|
unsigned HiPart = MRI.createGenericVirtualRegister(Ty);
|
|
|
|
MIRBuilder.buildInstr(Opcode)
|
|
|
|
.addDef(HiPart)
|
|
|
|
.addUse(LHS)
|
|
|
|
.addUse(RHS);
|
|
|
|
|
|
|
|
unsigned Zero = MRI.createGenericVirtualRegister(Ty);
|
|
|
|
MIRBuilder.buildConstant(Zero, 0);
|
|
|
|
MIRBuilder.buildICmp(CmpInst::ICMP_NE, Overflow, HiPart, Zero);
|
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2017-03-09 02:09:14 +08:00
|
|
|
case TargetOpcode::G_FNEG: {
|
|
|
|
// TODO: Handle vector types once we are able to
|
|
|
|
// represent them.
|
|
|
|
if (Ty.isVector())
|
|
|
|
return UnableToLegalize;
|
|
|
|
unsigned Res = MI.getOperand(0).getReg();
|
|
|
|
Type *ZeroTy;
|
|
|
|
LLVMContext &Ctx = MIRBuilder.getMF().getFunction()->getContext();
|
|
|
|
switch (Ty.getSizeInBits()) {
|
|
|
|
case 16:
|
|
|
|
ZeroTy = Type::getHalfTy(Ctx);
|
|
|
|
break;
|
|
|
|
case 32:
|
|
|
|
ZeroTy = Type::getFloatTy(Ctx);
|
|
|
|
break;
|
|
|
|
case 64:
|
|
|
|
ZeroTy = Type::getDoubleTy(Ctx);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
llvm_unreachable("unexpected floating-point type");
|
|
|
|
}
|
|
|
|
ConstantFP &ZeroForNegation =
|
|
|
|
*cast<ConstantFP>(ConstantFP::getZeroValueForNegation(ZeroTy));
|
|
|
|
unsigned Zero = MRI.createGenericVirtualRegister(Ty);
|
|
|
|
MIRBuilder.buildFConstant(Zero, ZeroForNegation);
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_FSUB)
|
|
|
|
.addDef(Res)
|
|
|
|
.addUse(Zero)
|
|
|
|
.addUse(MI.getOperand(1).getReg());
|
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
[GlobalISel] LegalizerHelper: Lower (G_FSUB X, Y) to (G_FADD X, (G_FNEG Y))
Summary: No test case as none of the in-tree targets with GlobalISel support has this condition.
Reviewers: qcolombet, aditya_nandakumar, dsanders, t.p.northover, ab
Reviewed By: qcolombet
Subscribers: dberris, rovka, kristof.beyls, llvm-commits, igorb
Differential Revision: https://reviews.llvm.org/D30786
llvm-svn: 297512
2017-03-11 05:25:09 +08:00
|
|
|
case TargetOpcode::G_FSUB: {
|
|
|
|
// Lower (G_FSUB LHS, RHS) to (G_FADD LHS, (G_FNEG RHS)).
|
|
|
|
// First, check if G_FNEG is marked as Lower. If so, we may
|
|
|
|
// end up with an infinite loop as G_FSUB is used to legalize G_FNEG.
|
|
|
|
if (LI.getAction({G_FNEG, Ty}).first == LegalizerInfo::Lower)
|
|
|
|
return UnableToLegalize;
|
|
|
|
unsigned Res = MI.getOperand(0).getReg();
|
|
|
|
unsigned LHS = MI.getOperand(1).getReg();
|
|
|
|
unsigned RHS = MI.getOperand(2).getReg();
|
|
|
|
unsigned Neg = MRI.createGenericVirtualRegister(Ty);
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_FNEG).addDef(Neg).addUse(RHS);
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_FADD)
|
|
|
|
.addDef(Res)
|
|
|
|
.addUse(LHS)
|
|
|
|
.addUse(Neg);
|
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2017-12-01 04:11:42 +08:00
|
|
|
case TargetOpcode::G_ATOMIC_CMPXCHG_WITH_SUCCESS: {
|
|
|
|
unsigned OldValRes = MI.getOperand(0).getReg();
|
|
|
|
unsigned SuccessRes = MI.getOperand(1).getReg();
|
|
|
|
unsigned Addr = MI.getOperand(2).getReg();
|
|
|
|
unsigned CmpVal = MI.getOperand(3).getReg();
|
|
|
|
unsigned NewVal = MI.getOperand(4).getReg();
|
|
|
|
MIRBuilder.buildAtomicCmpXchg(OldValRes, Addr, CmpVal, NewVal,
|
|
|
|
**MI.memoperands_begin());
|
|
|
|
MIRBuilder.buildICmp(CmpInst::ICMP_EQ, SuccessRes, OldValRes, CmpVal);
|
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2016-08-27 01:46:13 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-10-15 06:18:18 +08:00
|
|
|
LegalizerHelper::LegalizeResult
|
|
|
|
LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx,
|
|
|
|
LLT NarrowTy) {
|
2016-08-27 10:38:21 +08:00
|
|
|
// FIXME: Don't know how to handle secondary types yet.
|
|
|
|
if (TypeIdx != 0)
|
|
|
|
return UnableToLegalize;
|
2016-07-23 04:03:43 +08:00
|
|
|
switch (MI.getOpcode()) {
|
|
|
|
default:
|
|
|
|
return UnableToLegalize;
|
|
|
|
case TargetOpcode::G_ADD: {
|
|
|
|
unsigned NarrowSize = NarrowTy.getSizeInBits();
|
2016-09-09 19:46:34 +08:00
|
|
|
unsigned DstReg = MI.getOperand(0).getReg();
|
[GlobalISel] Enable legalizing non-power-of-2 sized types.
This changes the interface of how targets describe how to legalize, see
the below description.
1. Interface for targets to describe how to legalize.
In GlobalISel, the API in the LegalizerInfo class is the main interface
for targets to specify which types are legal for which operations, and
what to do to turn illegal type/operation combinations into legal ones.
For each operation the type sizes that can be legalized without having
to change the size of the type are specified with a call to setAction.
This isn't different to how GlobalISel worked before. For example, for a
target that supports 32 and 64 bit adds natively:
for (auto Ty : {s32, s64})
setAction({G_ADD, 0, s32}, Legal);
or for a target that needs a library call for a 32 bit division:
setAction({G_SDIV, s32}, Libcall);
The main conceptual change to the LegalizerInfo API, is in specifying
how to legalize the type sizes for which a change of size is needed. For
example, in the above example, how to specify how all types from i1 to
i8388607 (apart from s32 and s64 which are legal) need to be legalized
and expressed in terms of operations on the available legal sizes
(again, i32 and i64 in this case). Before, the implementation only
allowed specifying power-of-2-sized types (e.g. setAction({G_ADD, 0,
s128}, NarrowScalar). A worse limitation was that if you'd wanted to
specify how to legalize all the sized types as allowed by the LLVM-IR
LangRef, i1 to i8388607, you'd have to call setAction 8388607-3 times
and probably would need a lot of memory to store all of these
specifications.
Instead, the legalization actions that need to change the size of the
type are specified now using a "SizeChangeStrategy". For example:
setLegalizeScalarToDifferentSizeStrategy(
G_ADD, 0, widenToLargerAndNarrowToLargest);
This example indicates that for type sizes for which there is a larger
size that can be legalized towards, do it by Widening the size.
For example, G_ADD on s17 will be legalized by first doing WidenScalar
to make it s32, after which it's legal.
The "NarrowToLargest" indicates what to do if there is no larger size
that can be legalized towards. E.g. G_ADD on s92 will be legalized by
doing NarrowScalar to s64.
Another example, taken from the ARM backend is:
for (unsigned Op : {G_SDIV, G_UDIV}) {
setLegalizeScalarToDifferentSizeStrategy(Op, 0,
widenToLargerTypesUnsupportedOtherwise);
if (ST.hasDivideInARMMode())
setAction({Op, s32}, Legal);
else
setAction({Op, s32}, Libcall);
}
For this example, G_SDIV on s8, on a target without a divide
instruction, would be legalized by first doing action (WidenScalar,
s32), followed by (Libcall, s32).
The same principle is also followed for when the number of vector lanes
on vector data types need to be changed, e.g.:
setAction({G_ADD, LLT::vector(8, 8)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(16, 8)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(4, 16)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(8, 16)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(2, 32)}, LegalizerInfo::Legal);
setAction({G_ADD, LLT::vector(4, 32)}, LegalizerInfo::Legal);
setLegalizeVectorElementToDifferentSizeStrategy(
G_ADD, 0, widenToLargerTypesUnsupportedOtherwise);
As currently implemented here, vector types are legalized by first
making the vector element size legal, followed by then making the number
of lanes legal. The strategy to follow in the first step is set by a
call to setLegalizeVectorElementToDifferentSizeStrategy, see example
above. The strategy followed in the second step
"moreToWiderTypesAndLessToWidest" (see code for its definition),
indicating that vectors are widened to more elements so they map to
natively supported vector widths, or when there isn't a legal wider
vector, split the vector to map it to the widest vector supported.
Therefore, for the above specification, some example legalizations are:
* getAction({G_ADD, LLT::vector(3, 3)})
returns {WidenScalar, LLT::vector(3, 8)}
* getAction({G_ADD, LLT::vector(3, 8)})
then returns {MoreElements, LLT::vector(8, 8)}
* getAction({G_ADD, LLT::vector(20, 8)})
returns {FewerElements, LLT::vector(16, 8)}
2. Key implementation aspects.
How to legalize a specific (operation, type index, size) tuple is
represented by mapping intervals of integers representing a range of
size types to an action to take, e.g.:
setScalarAction({G_ADD, LLT:scalar(1)},
{{1, WidenScalar}, // bit sizes [ 1, 31[
{32, Legal}, // bit sizes [32, 33[
{33, WidenScalar}, // bit sizes [33, 64[
{64, Legal}, // bit sizes [64, 65[
{65, NarrowScalar} // bit sizes [65, +inf[
});
Please note that most of the code to do the actual lowering of
non-power-of-2 sized types is currently missing, this is just trying to
make it possible for targets to specify what is legal, and how non-legal
types should be legalized. Probably quite a bit of further work is
needed in the actual legalizing and the other passes in GlobalISel to
support non-power-of-2 sized types.
I hope the documentation in LegalizerInfo.h and the examples provided in the
various {Target}LegalizerInfo.cpp and LegalizerInfoTest.cpp explains well
enough how this is meant to be used.
This drops the need for LLT::{half,double}...Size().
Differential Revision: https://reviews.llvm.org/D30529
llvm-svn: 317560
2017-11-07 18:34:34 +08:00
|
|
|
unsigned Size = MRI.getType(DstReg).getSizeInBits();
|
|
|
|
int NumParts = Size / NarrowSize;
|
|
|
|
// FIXME: Don't know how to handle the situation where the small vectors
|
|
|
|
// aren't all the same size yet.
|
|
|
|
if (Size % NarrowSize != 0)
|
|
|
|
return UnableToLegalize;
|
2016-07-23 04:03:43 +08:00
|
|
|
|
|
|
|
MIRBuilder.setInstr(MI);
|
|
|
|
|
2016-09-20 23:20:36 +08:00
|
|
|
SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs;
|
2016-07-23 04:03:43 +08:00
|
|
|
extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, Src1Regs);
|
|
|
|
extractParts(MI.getOperand(2).getReg(), NarrowTy, NumParts, Src2Regs);
|
|
|
|
|
|
|
|
for (int i = 0; i < NumParts; ++i) {
|
2016-09-09 19:46:34 +08:00
|
|
|
unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy);
|
|
|
|
MIRBuilder.buildAdd(DstReg, Src1Regs[i], Src2Regs[i]);
|
2016-07-23 04:03:43 +08:00
|
|
|
DstRegs.push_back(DstReg);
|
|
|
|
}
|
|
|
|
|
2017-03-04 06:46:09 +08:00
|
|
|
MIRBuilder.buildMerge(DstReg, DstRegs);
|
2016-07-23 04:03:43 +08:00
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|