2016-10-15 06:18:18 +08:00
|
|
|
//===-- llvm/CodeGen/GlobalISel/LegalizerHelper.cpp -----------------------===//
|
2016-07-23 04:03:43 +08:00
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2016-07-23 04:03:43 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
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"
|
2018-12-06 04:14:52 +08:00
|
|
|
#include "llvm/CodeGen/GlobalISel/GISelChangeObserver.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"
|
2018-08-22 01:30:31 +08:00
|
|
|
#include "llvm/CodeGen/TargetInstrInfo.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"
|
2018-08-22 01:30:31 +08:00
|
|
|
#include "llvm/Support/MathExtras.h"
|
2016-07-23 04:03:43 +08:00
|
|
|
#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;
|
2018-01-30 01:37:29 +08:00
|
|
|
using namespace LegalizeActions;
|
2016-07-23 04:03:43 +08:00
|
|
|
|
2018-12-06 04:14:52 +08:00
|
|
|
LegalizerHelper::LegalizerHelper(MachineFunction &MF,
|
2019-01-16 08:40:37 +08:00
|
|
|
GISelChangeObserver &Observer,
|
|
|
|
MachineIRBuilder &Builder)
|
|
|
|
: MIRBuilder(Builder), MRI(MF.getRegInfo()),
|
|
|
|
LI(*MF.getSubtarget().getLegalizerInfo()), Observer(Observer) {
|
2016-07-23 04:03:43 +08:00
|
|
|
MIRBuilder.setMF(MF);
|
2018-12-06 04:14:52 +08:00
|
|
|
MIRBuilder.setChangeObserver(Observer);
|
2016-07-23 04:03:43 +08:00
|
|
|
}
|
|
|
|
|
2018-12-06 04:14:52 +08:00
|
|
|
LegalizerHelper::LegalizerHelper(MachineFunction &MF, const LegalizerInfo &LI,
|
2019-01-16 08:40:37 +08:00
|
|
|
GISelChangeObserver &Observer,
|
|
|
|
MachineIRBuilder &B)
|
|
|
|
: MIRBuilder(B), MRI(MF.getRegInfo()), LI(LI), Observer(Observer) {
|
2018-08-22 01:30:31 +08:00
|
|
|
MIRBuilder.setMF(MF);
|
2018-12-06 04:14:52 +08:00
|
|
|
MIRBuilder.setChangeObserver(Observer);
|
2018-08-22 01:30:31 +08:00
|
|
|
}
|
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) {
|
2018-05-14 20:53:11 +08:00
|
|
|
LLVM_DEBUG(dbgs() << "Legalizing: "; MI.print(dbgs()));
|
2017-04-20 23:46:12 +08:00
|
|
|
|
[globalisel] Introduce LegalityQuery to better encapsulate the legalizer decisions. NFC.
Summary:
`getAction(const InstrAspect &) const` breaks encapsulation by exposing
the smaller components that are used to decide how to legalize an
instruction.
This is a problem because we need to change the implementation of
LegalizerInfo so that it's able to describe particular type combinations
rather than just cartesian products of types.
For example, declaring the following
setAction({..., 0, s32}, Legal)
setAction({..., 0, s64}, Legal)
setAction({..., 1, s32}, Legal)
setAction({..., 1, s64}, Legal)
currently declares these type combinations as legal:
{s32, s32}
{s64, s32}
{s32, s64}
{s64, s64}
but we currently have no means to say that, for example, {s64, s32} is
not legal. Some operations such as G_INSERT/G_EXTRACT/G_MERGE_VALUES/
G_UNMERGE_VALUES has relationships between the types that are currently
described incorrectly.
Additionally, G_LOAD/G_STORE currently have no means to legalize non-atomics
differently to atomics. The necessary information is in the MMO but we have no
way to use this in the legalizer. Similarly, there is currently no way for the
register type and the memory type to differ so there is no way to cleanly
represent extending-load/truncating-store in a way that can't be broken by
optimizers (resulting in illegal MIR).
This patch introduces LegalityQuery which provides all the information
needed by the legalizer to make a decision on whether something is legal
and how to legalize it.
Reviewers: ab, t.p.northover, qcolombet, rovka, aditya_nandakumar, volkan, reames, bogner
Reviewed By: bogner
Subscribers: bogner, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D42244
llvm-svn: 323342
2018-01-25 01:17:46 +08:00
|
|
|
auto Step = LI.getAction(MI, MRI);
|
|
|
|
switch (Step.Action) {
|
2018-01-30 01:37:29 +08:00
|
|
|
case Legal:
|
2018-05-14 20:53:11 +08:00
|
|
|
LLVM_DEBUG(dbgs() << ".. Already legal\n");
|
2016-07-23 04:03:43 +08:00
|
|
|
return AlreadyLegal;
|
2018-01-30 01:37:29 +08:00
|
|
|
case Libcall:
|
2018-05-14 20:53:11 +08:00
|
|
|
LLVM_DEBUG(dbgs() << ".. Convert to libcall\n");
|
2016-08-30 03:07:16 +08:00
|
|
|
return libcall(MI);
|
2018-01-30 01:37:29 +08:00
|
|
|
case NarrowScalar:
|
2018-05-14 20:53:11 +08:00
|
|
|
LLVM_DEBUG(dbgs() << ".. Narrow scalar\n");
|
[globalisel] Introduce LegalityQuery to better encapsulate the legalizer decisions. NFC.
Summary:
`getAction(const InstrAspect &) const` breaks encapsulation by exposing
the smaller components that are used to decide how to legalize an
instruction.
This is a problem because we need to change the implementation of
LegalizerInfo so that it's able to describe particular type combinations
rather than just cartesian products of types.
For example, declaring the following
setAction({..., 0, s32}, Legal)
setAction({..., 0, s64}, Legal)
setAction({..., 1, s32}, Legal)
setAction({..., 1, s64}, Legal)
currently declares these type combinations as legal:
{s32, s32}
{s64, s32}
{s32, s64}
{s64, s64}
but we currently have no means to say that, for example, {s64, s32} is
not legal. Some operations such as G_INSERT/G_EXTRACT/G_MERGE_VALUES/
G_UNMERGE_VALUES has relationships between the types that are currently
described incorrectly.
Additionally, G_LOAD/G_STORE currently have no means to legalize non-atomics
differently to atomics. The necessary information is in the MMO but we have no
way to use this in the legalizer. Similarly, there is currently no way for the
register type and the memory type to differ so there is no way to cleanly
represent extending-load/truncating-store in a way that can't be broken by
optimizers (resulting in illegal MIR).
This patch introduces LegalityQuery which provides all the information
needed by the legalizer to make a decision on whether something is legal
and how to legalize it.
Reviewers: ab, t.p.northover, qcolombet, rovka, aditya_nandakumar, volkan, reames, bogner
Reviewed By: bogner
Subscribers: bogner, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D42244
llvm-svn: 323342
2018-01-25 01:17:46 +08:00
|
|
|
return narrowScalar(MI, Step.TypeIdx, Step.NewType);
|
2018-01-30 01:37:29 +08:00
|
|
|
case WidenScalar:
|
2018-05-14 20:53:11 +08:00
|
|
|
LLVM_DEBUG(dbgs() << ".. Widen scalar\n");
|
[globalisel] Introduce LegalityQuery to better encapsulate the legalizer decisions. NFC.
Summary:
`getAction(const InstrAspect &) const` breaks encapsulation by exposing
the smaller components that are used to decide how to legalize an
instruction.
This is a problem because we need to change the implementation of
LegalizerInfo so that it's able to describe particular type combinations
rather than just cartesian products of types.
For example, declaring the following
setAction({..., 0, s32}, Legal)
setAction({..., 0, s64}, Legal)
setAction({..., 1, s32}, Legal)
setAction({..., 1, s64}, Legal)
currently declares these type combinations as legal:
{s32, s32}
{s64, s32}
{s32, s64}
{s64, s64}
but we currently have no means to say that, for example, {s64, s32} is
not legal. Some operations such as G_INSERT/G_EXTRACT/G_MERGE_VALUES/
G_UNMERGE_VALUES has relationships between the types that are currently
described incorrectly.
Additionally, G_LOAD/G_STORE currently have no means to legalize non-atomics
differently to atomics. The necessary information is in the MMO but we have no
way to use this in the legalizer. Similarly, there is currently no way for the
register type and the memory type to differ so there is no way to cleanly
represent extending-load/truncating-store in a way that can't be broken by
optimizers (resulting in illegal MIR).
This patch introduces LegalityQuery which provides all the information
needed by the legalizer to make a decision on whether something is legal
and how to legalize it.
Reviewers: ab, t.p.northover, qcolombet, rovka, aditya_nandakumar, volkan, reames, bogner
Reviewed By: bogner
Subscribers: bogner, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D42244
llvm-svn: 323342
2018-01-25 01:17:46 +08:00
|
|
|
return widenScalar(MI, Step.TypeIdx, Step.NewType);
|
2018-01-30 01:37:29 +08:00
|
|
|
case Lower:
|
2018-05-14 20:53:11 +08:00
|
|
|
LLVM_DEBUG(dbgs() << ".. Lower\n");
|
[globalisel] Introduce LegalityQuery to better encapsulate the legalizer decisions. NFC.
Summary:
`getAction(const InstrAspect &) const` breaks encapsulation by exposing
the smaller components that are used to decide how to legalize an
instruction.
This is a problem because we need to change the implementation of
LegalizerInfo so that it's able to describe particular type combinations
rather than just cartesian products of types.
For example, declaring the following
setAction({..., 0, s32}, Legal)
setAction({..., 0, s64}, Legal)
setAction({..., 1, s32}, Legal)
setAction({..., 1, s64}, Legal)
currently declares these type combinations as legal:
{s32, s32}
{s64, s32}
{s32, s64}
{s64, s64}
but we currently have no means to say that, for example, {s64, s32} is
not legal. Some operations such as G_INSERT/G_EXTRACT/G_MERGE_VALUES/
G_UNMERGE_VALUES has relationships between the types that are currently
described incorrectly.
Additionally, G_LOAD/G_STORE currently have no means to legalize non-atomics
differently to atomics. The necessary information is in the MMO but we have no
way to use this in the legalizer. Similarly, there is currently no way for the
register type and the memory type to differ so there is no way to cleanly
represent extending-load/truncating-store in a way that can't be broken by
optimizers (resulting in illegal MIR).
This patch introduces LegalityQuery which provides all the information
needed by the legalizer to make a decision on whether something is legal
and how to legalize it.
Reviewers: ab, t.p.northover, qcolombet, rovka, aditya_nandakumar, volkan, reames, bogner
Reviewed By: bogner
Subscribers: bogner, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D42244
llvm-svn: 323342
2018-01-25 01:17:46 +08:00
|
|
|
return lower(MI, Step.TypeIdx, Step.NewType);
|
2018-01-30 01:37:29 +08:00
|
|
|
case FewerElements:
|
2018-05-14 20:53:11 +08:00
|
|
|
LLVM_DEBUG(dbgs() << ".. Reduce number of elements\n");
|
[globalisel] Introduce LegalityQuery to better encapsulate the legalizer decisions. NFC.
Summary:
`getAction(const InstrAspect &) const` breaks encapsulation by exposing
the smaller components that are used to decide how to legalize an
instruction.
This is a problem because we need to change the implementation of
LegalizerInfo so that it's able to describe particular type combinations
rather than just cartesian products of types.
For example, declaring the following
setAction({..., 0, s32}, Legal)
setAction({..., 0, s64}, Legal)
setAction({..., 1, s32}, Legal)
setAction({..., 1, s64}, Legal)
currently declares these type combinations as legal:
{s32, s32}
{s64, s32}
{s32, s64}
{s64, s64}
but we currently have no means to say that, for example, {s64, s32} is
not legal. Some operations such as G_INSERT/G_EXTRACT/G_MERGE_VALUES/
G_UNMERGE_VALUES has relationships between the types that are currently
described incorrectly.
Additionally, G_LOAD/G_STORE currently have no means to legalize non-atomics
differently to atomics. The necessary information is in the MMO but we have no
way to use this in the legalizer. Similarly, there is currently no way for the
register type and the memory type to differ so there is no way to cleanly
represent extending-load/truncating-store in a way that can't be broken by
optimizers (resulting in illegal MIR).
This patch introduces LegalityQuery which provides all the information
needed by the legalizer to make a decision on whether something is legal
and how to legalize it.
Reviewers: ab, t.p.northover, qcolombet, rovka, aditya_nandakumar, volkan, reames, bogner
Reviewed By: bogner
Subscribers: bogner, llvm-commits, kristof.beyls
Differential Revision: https://reviews.llvm.org/D42244
llvm-svn: 323342
2018-01-25 01:17:46 +08:00
|
|
|
return fewerElementsVector(MI, Step.TypeIdx, Step.NewType);
|
2018-01-30 01:37:29 +08:00
|
|
|
case Custom:
|
2018-05-14 20:53:11 +08:00
|
|
|
LLVM_DEBUG(dbgs() << ".. Custom legalization\n");
|
2018-12-06 04:14:52 +08:00
|
|
|
return LI.legalizeCustom(MI, MRI, MIRBuilder, Observer) ? Legalized
|
|
|
|
: UnableToLegalize;
|
2016-07-23 04:03:43 +08:00
|
|
|
default:
|
2018-05-14 20:53:11 +08:00
|
|
|
LLVM_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:
|
2018-12-18 23:59:51 +08:00
|
|
|
assert((Size == 32 || Size == 64) && "Unsupported size");
|
|
|
|
return Size == 64 ? RTLIB::SDIV_I64 : RTLIB::SDIV_I32;
|
2017-04-24 15:22:31 +08:00
|
|
|
case TargetOpcode::G_UDIV:
|
2018-12-18 23:59:51 +08:00
|
|
|
assert((Size == 32 || Size == 64) && "Unsupported size");
|
|
|
|
return Size == 64 ? RTLIB::UDIV_I64 : RTLIB::UDIV_I32;
|
2017-06-15 18:53:31 +08:00
|
|
|
case TargetOpcode::G_SREM:
|
2018-12-18 23:59:51 +08:00
|
|
|
assert((Size == 32 || Size == 64) && "Unsupported size");
|
|
|
|
return Size == 64 ? RTLIB::SREM_I64 : RTLIB::SREM_I32;
|
2017-06-15 18:53:31 +08:00
|
|
|
case TargetOpcode::G_UREM:
|
2018-12-18 23:59:51 +08:00
|
|
|
assert((Size == 32 || Size == 64) && "Unsupported size");
|
|
|
|
return Size == 64 ? RTLIB::UREM_I64 : RTLIB::UREM_I32;
|
2018-11-26 19:07:02 +08:00
|
|
|
case TargetOpcode::G_CTLZ_ZERO_UNDEF:
|
|
|
|
assert(Size == 32 && "Unsupported size");
|
|
|
|
return RTLIB::CTLZ_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;
|
2018-01-12 19:30:45 +08:00
|
|
|
case TargetOpcode::G_FMA:
|
|
|
|
assert((Size == 32 || Size == 64) && "Unsupported size");
|
|
|
|
return Size == 64 ? RTLIB::FMA_F64 : RTLIB::FMA_F32;
|
2019-01-29 02:34:18 +08:00
|
|
|
case TargetOpcode::G_FSIN:
|
|
|
|
assert((Size == 32 || Size == 64 || Size == 128) && "Unsupported size");
|
|
|
|
return Size == 128 ? RTLIB::SIN_F128
|
|
|
|
: Size == 64 ? RTLIB::SIN_F64 : RTLIB::SIN_F32;
|
|
|
|
case TargetOpcode::G_FCOS:
|
|
|
|
assert((Size == 32 || Size == 64 || Size == 128) && "Unsupported size");
|
|
|
|
return Size == 128 ? RTLIB::COS_F128
|
|
|
|
: Size == 64 ? RTLIB::COS_F64 : RTLIB::COS_F32;
|
2017-02-09 07:23:39 +08:00
|
|
|
}
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-01-17 21:34:10 +08:00
|
|
|
// Useful for libcalls where all operands have the same type.
|
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);
|
2018-01-12 19:30:45 +08:00
|
|
|
|
|
|
|
SmallVector<CallLowering::ArgInfo, 3> Args;
|
|
|
|
for (unsigned i = 1; i < MI.getNumOperands(); i++)
|
|
|
|
Args.push_back({MI.getOperand(i).getReg(), OpType});
|
2017-07-05 20:57:24 +08:00
|
|
|
return createLibcall(MIRBuilder, Libcall, {MI.getOperand(0).getReg(), OpType},
|
2018-01-12 19:30:45 +08:00
|
|
|
Args);
|
2017-06-15 18:53:31 +08:00
|
|
|
}
|
|
|
|
|
2018-01-17 21:34:10 +08:00
|
|
|
static RTLIB::Libcall getConvRTLibDesc(unsigned Opcode, Type *ToType,
|
|
|
|
Type *FromType) {
|
|
|
|
auto ToMVT = MVT::getVT(ToType);
|
|
|
|
auto FromMVT = MVT::getVT(FromType);
|
|
|
|
|
|
|
|
switch (Opcode) {
|
|
|
|
case TargetOpcode::G_FPEXT:
|
|
|
|
return RTLIB::getFPEXT(FromMVT, ToMVT);
|
|
|
|
case TargetOpcode::G_FPTRUNC:
|
|
|
|
return RTLIB::getFPROUND(FromMVT, ToMVT);
|
2018-01-30 15:54:52 +08:00
|
|
|
case TargetOpcode::G_FPTOSI:
|
|
|
|
return RTLIB::getFPTOSINT(FromMVT, ToMVT);
|
|
|
|
case TargetOpcode::G_FPTOUI:
|
|
|
|
return RTLIB::getFPTOUINT(FromMVT, ToMVT);
|
2018-01-30 17:15:17 +08:00
|
|
|
case TargetOpcode::G_SITOFP:
|
|
|
|
return RTLIB::getSINTTOFP(FromMVT, ToMVT);
|
|
|
|
case TargetOpcode::G_UITOFP:
|
|
|
|
return RTLIB::getUINTTOFP(FromMVT, ToMVT);
|
2018-01-17 21:34:10 +08:00
|
|
|
}
|
|
|
|
llvm_unreachable("Unsupported libcall function");
|
|
|
|
}
|
|
|
|
|
|
|
|
static LegalizerHelper::LegalizeResult
|
|
|
|
conversionLibcall(MachineInstr &MI, MachineIRBuilder &MIRBuilder, Type *ToType,
|
|
|
|
Type *FromType) {
|
|
|
|
RTLIB::Libcall Libcall = getConvRTLibDesc(MI.getOpcode(), ToType, FromType);
|
|
|
|
return createLibcall(MIRBuilder, Libcall, {MI.getOperand(0).getReg(), ToType},
|
|
|
|
{{MI.getOperand(1).getReg(), FromType}});
|
|
|
|
}
|
|
|
|
|
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-12-16 06:22:58 +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:
|
2018-11-26 19:07:02 +08:00
|
|
|
case TargetOpcode::G_UREM:
|
|
|
|
case TargetOpcode::G_CTLZ_ZERO_UNDEF: {
|
2018-12-18 23:59:51 +08:00
|
|
|
Type *HLTy = IntegerType::get(Ctx, Size);
|
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:
|
2018-01-12 19:30:45 +08:00
|
|
|
case TargetOpcode::G_FMA:
|
2017-02-09 07:23:39 +08:00
|
|
|
case TargetOpcode::G_FPOW:
|
2019-01-29 02:34:18 +08:00
|
|
|
case TargetOpcode::G_FREM:
|
|
|
|
case TargetOpcode::G_FCOS:
|
|
|
|
case TargetOpcode::G_FSIN: {
|
|
|
|
if (Size > 64) {
|
|
|
|
LLVM_DEBUG(dbgs() << "Size " << Size << " too large to legalize.\n");
|
|
|
|
return UnableToLegalize;
|
|
|
|
}
|
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
|
|
|
}
|
2018-01-17 21:34:10 +08:00
|
|
|
case TargetOpcode::G_FPEXT: {
|
|
|
|
// FIXME: Support other floating point types (half, fp128 etc)
|
|
|
|
unsigned FromSize = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
|
|
|
|
unsigned ToSize = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
|
|
|
|
if (ToSize != 64 || FromSize != 32)
|
|
|
|
return UnableToLegalize;
|
|
|
|
LegalizeResult Status = conversionLibcall(
|
|
|
|
MI, MIRBuilder, Type::getDoubleTy(Ctx), Type::getFloatTy(Ctx));
|
|
|
|
if (Status != Legalized)
|
|
|
|
return Status;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case TargetOpcode::G_FPTRUNC: {
|
|
|
|
// FIXME: Support other floating point types (half, fp128 etc)
|
|
|
|
unsigned FromSize = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
|
|
|
|
unsigned ToSize = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
|
|
|
|
if (ToSize != 32 || FromSize != 64)
|
|
|
|
return UnableToLegalize;
|
|
|
|
LegalizeResult Status = conversionLibcall(
|
|
|
|
MI, MIRBuilder, Type::getFloatTy(Ctx), Type::getDoubleTy(Ctx));
|
|
|
|
if (Status != Legalized)
|
|
|
|
return Status;
|
|
|
|
break;
|
|
|
|
}
|
2018-01-30 15:54:52 +08:00
|
|
|
case TargetOpcode::G_FPTOSI:
|
|
|
|
case TargetOpcode::G_FPTOUI: {
|
|
|
|
// FIXME: Support other types
|
|
|
|
unsigned FromSize = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
|
|
|
|
unsigned ToSize = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
|
|
|
|
if (ToSize != 32 || (FromSize != 32 && FromSize != 64))
|
|
|
|
return UnableToLegalize;
|
|
|
|
LegalizeResult Status = conversionLibcall(
|
|
|
|
MI, MIRBuilder, Type::getInt32Ty(Ctx),
|
|
|
|
FromSize == 64 ? Type::getDoubleTy(Ctx) : Type::getFloatTy(Ctx));
|
|
|
|
if (Status != Legalized)
|
|
|
|
return Status;
|
|
|
|
break;
|
|
|
|
}
|
2018-01-30 17:15:17 +08:00
|
|
|
case TargetOpcode::G_SITOFP:
|
|
|
|
case TargetOpcode::G_UITOFP: {
|
|
|
|
// FIXME: Support other types
|
|
|
|
unsigned FromSize = MRI.getType(MI.getOperand(1).getReg()).getSizeInBits();
|
|
|
|
unsigned ToSize = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
|
|
|
|
if (FromSize != 32 || (ToSize != 32 && ToSize != 64))
|
|
|
|
return UnableToLegalize;
|
|
|
|
LegalizeResult Status = conversionLibcall(
|
|
|
|
MI, MIRBuilder,
|
|
|
|
ToSize == 64 ? Type::getDoubleTy(Ctx) : Type::getFloatTy(Ctx),
|
|
|
|
Type::getInt32Ty(Ctx));
|
|
|
|
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) {
|
2017-01-19 01:29:54 +08:00
|
|
|
MIRBuilder.setInstr(MI);
|
|
|
|
|
2018-04-28 03:48:53 +08:00
|
|
|
uint64_t SizeOp0 = MRI.getType(MI.getOperand(0).getReg()).getSizeInBits();
|
|
|
|
uint64_t NarrowSize = NarrowTy.getSizeInBits();
|
[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
|
|
|
|
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;
|
2018-02-15 03:58:36 +08:00
|
|
|
for (int i = 0; i < NumParts; ++i)
|
|
|
|
DstRegs.push_back(
|
|
|
|
MIRBuilder.buildUndef(NarrowTy)->getOperand(0).getReg());
|
2018-12-11 02:44:58 +08:00
|
|
|
|
|
|
|
unsigned DstReg = MI.getOperand(0).getReg();
|
|
|
|
if(MRI.getType(DstReg).isVector())
|
|
|
|
MIRBuilder.buildBuildVector(DstReg, DstRegs);
|
|
|
|
else
|
|
|
|
MIRBuilder.buildMerge(DstReg, DstRegs);
|
2017-07-01 04:27:36 +08:00
|
|
|
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();
|
2018-12-11 02:44:58 +08:00
|
|
|
if(MRI.getType(DstReg).isVector())
|
|
|
|
MIRBuilder.buildBuildVector(DstReg, DstRegs);
|
|
|
|
else
|
|
|
|
MIRBuilder.buildMerge(DstReg, DstRegs);
|
2016-08-05 04:54:13 +08:00
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2019-01-28 20:10:17 +08:00
|
|
|
case TargetOpcode::G_SUB: {
|
|
|
|
// FIXME: add support for when SizeOp0 isn't an exact multiple of
|
|
|
|
// NarrowSize.
|
|
|
|
if (SizeOp0 % NarrowSize != 0)
|
|
|
|
return UnableToLegalize;
|
|
|
|
|
|
|
|
int NumParts = SizeOp0 / NarrowTy.getSizeInBits();
|
|
|
|
|
|
|
|
SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs;
|
|
|
|
extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, Src1Regs);
|
|
|
|
extractParts(MI.getOperand(2).getReg(), NarrowTy, NumParts, Src2Regs);
|
|
|
|
|
|
|
|
unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy);
|
|
|
|
unsigned BorrowOut = MRI.createGenericVirtualRegister(LLT::scalar(1));
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_USUBO, {DstReg, BorrowOut},
|
|
|
|
{Src1Regs[0], Src2Regs[0]});
|
|
|
|
DstRegs.push_back(DstReg);
|
|
|
|
unsigned BorrowIn = BorrowOut;
|
|
|
|
for (int i = 1; i < NumParts; ++i) {
|
|
|
|
DstReg = MRI.createGenericVirtualRegister(NarrowTy);
|
|
|
|
BorrowOut = MRI.createGenericVirtualRegister(LLT::scalar(1));
|
|
|
|
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_USUBE, {DstReg, BorrowOut},
|
|
|
|
{Src1Regs[i], Src2Regs[i], BorrowIn});
|
|
|
|
|
|
|
|
DstRegs.push_back(DstReg);
|
|
|
|
BorrowIn = BorrowOut;
|
|
|
|
}
|
|
|
|
MIRBuilder.buildMerge(MI.getOperand(0).getReg(), DstRegs);
|
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2019-01-27 08:52:51 +08:00
|
|
|
case TargetOpcode::G_MUL:
|
|
|
|
return narrowScalarMul(MI, TypeIdx, NarrowTy);
|
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();
|
2018-04-28 03:48:53 +08:00
|
|
|
uint64_t OpStart = MI.getOperand(2).getImm();
|
|
|
|
uint64_t OpSize = MRI.getType(OpReg).getSizeInBits();
|
2017-06-27 04:34:13 +08:00
|
|
|
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.
|
2018-04-28 03:48:53 +08:00
|
|
|
int64_t ExtractOffset;
|
|
|
|
uint64_t SegSize;
|
2017-06-27 04:34:13 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2018-12-11 02:44:58 +08:00
|
|
|
unsigned DstReg = MI.getOperand(0).getReg();
|
|
|
|
if(MRI.getType(DstReg).isVector())
|
|
|
|
MIRBuilder.buildBuildVector(DstReg, DstRegs);
|
|
|
|
else
|
|
|
|
MIRBuilder.buildMerge(DstReg, DstRegs);
|
2017-06-27 04:34:13 +08:00
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2017-02-07 05:56:47 +08:00
|
|
|
case TargetOpcode::G_INSERT: {
|
2019-01-23 05:42:11 +08:00
|
|
|
// FIXME: Don't know how to handle secondary types yet.
|
|
|
|
if (TypeIdx != 0)
|
|
|
|
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
|
|
|
// 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();
|
2018-04-28 03:48:53 +08:00
|
|
|
uint64_t OpStart = MI.getOperand(3).getImm();
|
|
|
|
uint64_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.
|
2018-04-28 03:48:53 +08:00
|
|
|
int64_t ExtractOffset, InsertOffset;
|
|
|
|
uint64_t SegSize;
|
2017-03-08 05:24:33 +08:00
|
|
|
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");
|
2018-12-11 02:44:58 +08:00
|
|
|
unsigned DstReg = MI.getOperand(0).getReg();
|
|
|
|
if(MRI.getType(DstReg).isVector())
|
|
|
|
MIRBuilder.buildBuildVector(DstReg, DstRegs);
|
|
|
|
else
|
|
|
|
MIRBuilder.buildMerge(DstReg, 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;
|
2018-04-28 03:48:53 +08:00
|
|
|
|
|
|
|
const auto &MMO = **MI.memoperands_begin();
|
|
|
|
// This implementation doesn't work for atomics. Give up instead of doing
|
|
|
|
// something invalid.
|
|
|
|
if (MMO.getOrdering() != AtomicOrdering::NotAtomic ||
|
|
|
|
MMO.getFailureOrdering() != AtomicOrdering::NotAtomic)
|
|
|
|
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;
|
[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;
|
2018-10-26 01:52:19 +08:00
|
|
|
unsigned Alignment = MinAlign(MMO.getAlignment(), Adjustment);
|
[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
|
|
|
|
2018-04-28 03:48:53 +08:00
|
|
|
MachineMemOperand *SplitMMO = MIRBuilder.getMF().getMachineMemOperand(
|
|
|
|
MMO.getPointerInfo().getWithOffset(Adjustment), MMO.getFlags(),
|
2018-10-26 01:52:19 +08:00
|
|
|
NarrowSize / 8, Alignment, MMO.getAAInfo(), MMO.getRanges(),
|
|
|
|
MMO.getSyncScopeID(), MMO.getOrdering(), MMO.getFailureOrdering());
|
2018-04-28 03:48:53 +08:00
|
|
|
|
[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
|
|
|
MIRBuilder.materializeGEP(SrcReg, MI.getOperand(1).getReg(), OffsetTy,
|
|
|
|
Adjustment);
|
2017-01-19 09:05:48 +08:00
|
|
|
|
2018-04-28 03:48:53 +08:00
|
|
|
MIRBuilder.buildLoad(DstReg, SrcReg, *SplitMMO);
|
2017-01-19 09:05:48 +08:00
|
|
|
|
|
|
|
DstRegs.push_back(DstReg);
|
|
|
|
}
|
|
|
|
unsigned DstReg = MI.getOperand(0).getReg();
|
2018-12-11 02:44:58 +08:00
|
|
|
if(MRI.getType(DstReg).isVector())
|
|
|
|
MIRBuilder.buildBuildVector(DstReg, DstRegs);
|
|
|
|
else
|
|
|
|
MIRBuilder.buildMerge(DstReg, DstRegs);
|
2017-01-19 09:05:48 +08:00
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2019-01-23 03:02:10 +08:00
|
|
|
case TargetOpcode::G_ZEXTLOAD:
|
|
|
|
case TargetOpcode::G_SEXTLOAD: {
|
|
|
|
bool ZExt = MI.getOpcode() == TargetOpcode::G_ZEXTLOAD;
|
|
|
|
unsigned DstReg = MI.getOperand(0).getReg();
|
|
|
|
unsigned PtrReg = MI.getOperand(1).getReg();
|
|
|
|
|
|
|
|
unsigned TmpReg = MRI.createGenericVirtualRegister(NarrowTy);
|
|
|
|
auto &MMO = **MI.memoperands_begin();
|
|
|
|
if (MMO.getSize() * 8 == NarrowSize) {
|
|
|
|
MIRBuilder.buildLoad(TmpReg, PtrReg, MMO);
|
|
|
|
} else {
|
|
|
|
unsigned ExtLoad = ZExt ? TargetOpcode::G_ZEXTLOAD
|
|
|
|
: TargetOpcode::G_SEXTLOAD;
|
|
|
|
MIRBuilder.buildInstr(ExtLoad)
|
|
|
|
.addDef(TmpReg)
|
|
|
|
.addUse(PtrReg)
|
|
|
|
.addMemOperand(&MMO);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ZExt)
|
|
|
|
MIRBuilder.buildZExt(DstReg, TmpReg);
|
|
|
|
else
|
|
|
|
MIRBuilder.buildSExt(DstReg, TmpReg);
|
|
|
|
|
|
|
|
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;
|
2018-04-28 03:48:53 +08:00
|
|
|
|
|
|
|
const auto &MMO = **MI.memoperands_begin();
|
|
|
|
// This implementation doesn't work for atomics. Give up instead of doing
|
|
|
|
// something invalid.
|
|
|
|
if (MMO.getOrdering() != AtomicOrdering::NotAtomic ||
|
|
|
|
MMO.getFailureOrdering() != AtomicOrdering::NotAtomic)
|
|
|
|
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;
|
[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;
|
2018-10-26 01:52:19 +08:00
|
|
|
unsigned Alignment = MinAlign(MMO.getAlignment(), Adjustment);
|
[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
|
|
|
|
2018-04-28 03:48:53 +08:00
|
|
|
MachineMemOperand *SplitMMO = MIRBuilder.getMF().getMachineMemOperand(
|
|
|
|
MMO.getPointerInfo().getWithOffset(Adjustment), MMO.getFlags(),
|
2018-10-26 01:52:19 +08:00
|
|
|
NarrowSize / 8, Alignment, MMO.getAAInfo(), MMO.getRanges(),
|
|
|
|
MMO.getSyncScopeID(), MMO.getOrdering(), MMO.getFailureOrdering());
|
2018-04-28 03:48:53 +08:00
|
|
|
|
[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
|
|
|
MIRBuilder.materializeGEP(DstReg, MI.getOperand(1).getReg(), OffsetTy,
|
|
|
|
Adjustment);
|
|
|
|
|
2018-04-28 03:48:53 +08:00
|
|
|
MIRBuilder.buildStore(SrcRegs[i], DstReg, *SplitMMO);
|
2017-01-19 01:29:54 +08:00
|
|
|
}
|
|
|
|
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();
|
2017-12-16 06:22:58 +08:00
|
|
|
LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
|
2017-04-07 22:41:59 +08:00
|
|
|
|
|
|
|
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();
|
2018-12-11 02:44:58 +08:00
|
|
|
if(MRI.getType(DstReg).isVector())
|
|
|
|
MIRBuilder.buildBuildVector(DstReg, DstRegs);
|
|
|
|
else
|
|
|
|
MIRBuilder.buildMerge(DstReg, DstRegs);
|
2017-10-03 12:53:56 +08:00
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2018-12-18 19:36:14 +08:00
|
|
|
case TargetOpcode::G_AND:
|
|
|
|
case TargetOpcode::G_OR:
|
|
|
|
case TargetOpcode::G_XOR: {
|
2017-10-03 12:53:56 +08:00
|
|
|
// 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)
|
2018-12-18 19:36:14 +08:00
|
|
|
MIRBuilder.buildInstr(MI.getOpcode(), {DstRegs[i]},
|
|
|
|
{SrcsReg1[i], SrcsReg2[i]});
|
2017-10-03 12:53:56 +08:00
|
|
|
|
|
|
|
// Gather the destination registers into the final destination.
|
|
|
|
unsigned DstReg = MI.getOperand(0).getReg();
|
2018-12-11 02:44:58 +08:00
|
|
|
if(MRI.getType(DstReg).isVector())
|
|
|
|
MIRBuilder.buildBuildVector(DstReg, DstRegs);
|
|
|
|
else
|
|
|
|
MIRBuilder.buildMerge(DstReg, DstRegs);
|
2017-04-07 22:41:59 +08:00
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2019-01-23 05:42:11 +08:00
|
|
|
case TargetOpcode::G_SHL:
|
|
|
|
case TargetOpcode::G_LSHR:
|
|
|
|
case TargetOpcode::G_ASHR: {
|
|
|
|
if (TypeIdx != 1)
|
|
|
|
return UnableToLegalize; // TODO
|
|
|
|
narrowScalarSrc(MI, NarrowTy, 2);
|
|
|
|
return Legalized;
|
|
|
|
}
|
2016-08-05 04:54:13 +08:00
|
|
|
}
|
2016-07-23 04:03:43 +08:00
|
|
|
}
|
|
|
|
|
2018-05-10 01:28:18 +08:00
|
|
|
void LegalizerHelper::widenScalarSrc(MachineInstr &MI, LLT WideTy,
|
|
|
|
unsigned OpIdx, unsigned ExtOpcode) {
|
|
|
|
MachineOperand &MO = MI.getOperand(OpIdx);
|
[GISel]: Refactor MachineIRBuilder to allow passing additional parameters to build Instrs
https://reviews.llvm.org/D55294
Previously MachineIRBuilder::buildInstr used to accept variadic
arguments for sources (which were either unsigned or
MachineInstrBuilder). While this worked well in common cases, it doesn't
allow us to build instructions that have multiple destinations.
Additionally passing in other optional parameters in the end (such as
flags) is not possible trivially. Also a trivial call such as
B.buildInstr(Opc, Reg1, Reg2, Reg3)
can be interpreted differently based on the opcode (2defs + 1 src for
unmerge vs 1 def + 2srcs).
This patch refactors the buildInstr to
buildInstr(Opc, ArrayRef<DstOps>, ArrayRef<SrcOps>)
where DstOps and SrcOps are typed unions that know how to add itself to
MachineInstrBuilder.
After this patch, most invocations would look like
B.buildInstr(Opc, {s32, DstReg}, {SrcRegs..., SrcMIBs..});
Now all the other calls (such as buildAdd, buildSub etc) forward to
buildInstr. It also makes it possible to build instructions with
multiple defs.
Additionally in a subsequent patch, we should make it possible to add
flags directly while building instructions.
Additionally, the main buildInstr method is now virtual and other
builders now only have to override buildInstr (for say constant
folding/cseing) is straightforward.
Also attached here (https://reviews.llvm.org/F7675680) is a clang-tidy
patch that should upgrade the API calls if necessary.
llvm-svn: 348815
2018-12-11 08:48:50 +08:00
|
|
|
auto ExtB = MIRBuilder.buildInstr(ExtOpcode, {WideTy}, {MO.getReg()});
|
2018-05-10 01:28:18 +08:00
|
|
|
MO.setReg(ExtB->getOperand(0).getReg());
|
|
|
|
}
|
|
|
|
|
2019-01-23 05:42:11 +08:00
|
|
|
void LegalizerHelper::narrowScalarSrc(MachineInstr &MI, LLT NarrowTy,
|
|
|
|
unsigned OpIdx) {
|
|
|
|
MachineOperand &MO = MI.getOperand(OpIdx);
|
|
|
|
auto ExtB = MIRBuilder.buildInstr(TargetOpcode::G_TRUNC, {NarrowTy},
|
|
|
|
{MO.getReg()});
|
|
|
|
MO.setReg(ExtB->getOperand(0).getReg());
|
|
|
|
}
|
|
|
|
|
2018-05-10 01:28:18 +08:00
|
|
|
void LegalizerHelper::widenScalarDst(MachineInstr &MI, LLT WideTy,
|
|
|
|
unsigned OpIdx, unsigned TruncOpcode) {
|
|
|
|
MachineOperand &MO = MI.getOperand(OpIdx);
|
|
|
|
unsigned DstExt = MRI.createGenericVirtualRegister(WideTy);
|
|
|
|
MIRBuilder.setInsertPt(MIRBuilder.getMBB(), ++MIRBuilder.getInsertPt());
|
[GISel]: Refactor MachineIRBuilder to allow passing additional parameters to build Instrs
https://reviews.llvm.org/D55294
Previously MachineIRBuilder::buildInstr used to accept variadic
arguments for sources (which were either unsigned or
MachineInstrBuilder). While this worked well in common cases, it doesn't
allow us to build instructions that have multiple destinations.
Additionally passing in other optional parameters in the end (such as
flags) is not possible trivially. Also a trivial call such as
B.buildInstr(Opc, Reg1, Reg2, Reg3)
can be interpreted differently based on the opcode (2defs + 1 src for
unmerge vs 1 def + 2srcs).
This patch refactors the buildInstr to
buildInstr(Opc, ArrayRef<DstOps>, ArrayRef<SrcOps>)
where DstOps and SrcOps are typed unions that know how to add itself to
MachineInstrBuilder.
After this patch, most invocations would look like
B.buildInstr(Opc, {s32, DstReg}, {SrcRegs..., SrcMIBs..});
Now all the other calls (such as buildAdd, buildSub etc) forward to
buildInstr. It also makes it possible to build instructions with
multiple defs.
Additionally in a subsequent patch, we should make it possible to add
flags directly while building instructions.
Additionally, the main buildInstr method is now virtual and other
builders now only have to override buildInstr (for say constant
folding/cseing) is straightforward.
Also attached here (https://reviews.llvm.org/F7675680) is a clang-tidy
patch that should upgrade the API calls if necessary.
llvm-svn: 348815
2018-12-11 08:48:50 +08:00
|
|
|
MIRBuilder.buildInstr(TruncOpcode, {MO.getReg()}, {DstExt});
|
2018-05-10 01:28:18 +08:00
|
|
|
MO.setReg(DstExt);
|
|
|
|
}
|
|
|
|
|
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;
|
2018-08-29 11:17:08 +08:00
|
|
|
case TargetOpcode::G_UADDO:
|
|
|
|
case TargetOpcode::G_USUBO: {
|
|
|
|
if (TypeIdx == 1)
|
|
|
|
return UnableToLegalize; // TODO
|
[GISel]: Refactor MachineIRBuilder to allow passing additional parameters to build Instrs
https://reviews.llvm.org/D55294
Previously MachineIRBuilder::buildInstr used to accept variadic
arguments for sources (which were either unsigned or
MachineInstrBuilder). While this worked well in common cases, it doesn't
allow us to build instructions that have multiple destinations.
Additionally passing in other optional parameters in the end (such as
flags) is not possible trivially. Also a trivial call such as
B.buildInstr(Opc, Reg1, Reg2, Reg3)
can be interpreted differently based on the opcode (2defs + 1 src for
unmerge vs 1 def + 2srcs).
This patch refactors the buildInstr to
buildInstr(Opc, ArrayRef<DstOps>, ArrayRef<SrcOps>)
where DstOps and SrcOps are typed unions that know how to add itself to
MachineInstrBuilder.
After this patch, most invocations would look like
B.buildInstr(Opc, {s32, DstReg}, {SrcRegs..., SrcMIBs..});
Now all the other calls (such as buildAdd, buildSub etc) forward to
buildInstr. It also makes it possible to build instructions with
multiple defs.
Additionally in a subsequent patch, we should make it possible to add
flags directly while building instructions.
Additionally, the main buildInstr method is now virtual and other
builders now only have to override buildInstr (for say constant
folding/cseing) is straightforward.
Also attached here (https://reviews.llvm.org/F7675680) is a clang-tidy
patch that should upgrade the API calls if necessary.
llvm-svn: 348815
2018-12-11 08:48:50 +08:00
|
|
|
auto LHSZext = MIRBuilder.buildInstr(TargetOpcode::G_ZEXT, {WideTy},
|
|
|
|
{MI.getOperand(2).getReg()});
|
|
|
|
auto RHSZext = MIRBuilder.buildInstr(TargetOpcode::G_ZEXT, {WideTy},
|
|
|
|
{MI.getOperand(3).getReg()});
|
2018-08-29 11:17:08 +08:00
|
|
|
unsigned Opcode = MI.getOpcode() == TargetOpcode::G_UADDO
|
|
|
|
? TargetOpcode::G_ADD
|
|
|
|
: TargetOpcode::G_SUB;
|
|
|
|
// Do the arithmetic in the larger type.
|
[GISel]: Refactor MachineIRBuilder to allow passing additional parameters to build Instrs
https://reviews.llvm.org/D55294
Previously MachineIRBuilder::buildInstr used to accept variadic
arguments for sources (which were either unsigned or
MachineInstrBuilder). While this worked well in common cases, it doesn't
allow us to build instructions that have multiple destinations.
Additionally passing in other optional parameters in the end (such as
flags) is not possible trivially. Also a trivial call such as
B.buildInstr(Opc, Reg1, Reg2, Reg3)
can be interpreted differently based on the opcode (2defs + 1 src for
unmerge vs 1 def + 2srcs).
This patch refactors the buildInstr to
buildInstr(Opc, ArrayRef<DstOps>, ArrayRef<SrcOps>)
where DstOps and SrcOps are typed unions that know how to add itself to
MachineInstrBuilder.
After this patch, most invocations would look like
B.buildInstr(Opc, {s32, DstReg}, {SrcRegs..., SrcMIBs..});
Now all the other calls (such as buildAdd, buildSub etc) forward to
buildInstr. It also makes it possible to build instructions with
multiple defs.
Additionally in a subsequent patch, we should make it possible to add
flags directly while building instructions.
Additionally, the main buildInstr method is now virtual and other
builders now only have to override buildInstr (for say constant
folding/cseing) is straightforward.
Also attached here (https://reviews.llvm.org/F7675680) is a clang-tidy
patch that should upgrade the API calls if necessary.
llvm-svn: 348815
2018-12-11 08:48:50 +08:00
|
|
|
auto NewOp = MIRBuilder.buildInstr(Opcode, {WideTy}, {LHSZext, RHSZext});
|
2018-08-29 11:17:08 +08:00
|
|
|
LLT OrigTy = MRI.getType(MI.getOperand(0).getReg());
|
|
|
|
APInt Mask = APInt::getAllOnesValue(OrigTy.getSizeInBits());
|
|
|
|
auto AndOp = MIRBuilder.buildInstr(
|
[GISel]: Refactor MachineIRBuilder to allow passing additional parameters to build Instrs
https://reviews.llvm.org/D55294
Previously MachineIRBuilder::buildInstr used to accept variadic
arguments for sources (which were either unsigned or
MachineInstrBuilder). While this worked well in common cases, it doesn't
allow us to build instructions that have multiple destinations.
Additionally passing in other optional parameters in the end (such as
flags) is not possible trivially. Also a trivial call such as
B.buildInstr(Opc, Reg1, Reg2, Reg3)
can be interpreted differently based on the opcode (2defs + 1 src for
unmerge vs 1 def + 2srcs).
This patch refactors the buildInstr to
buildInstr(Opc, ArrayRef<DstOps>, ArrayRef<SrcOps>)
where DstOps and SrcOps are typed unions that know how to add itself to
MachineInstrBuilder.
After this patch, most invocations would look like
B.buildInstr(Opc, {s32, DstReg}, {SrcRegs..., SrcMIBs..});
Now all the other calls (such as buildAdd, buildSub etc) forward to
buildInstr. It also makes it possible to build instructions with
multiple defs.
Additionally in a subsequent patch, we should make it possible to add
flags directly while building instructions.
Additionally, the main buildInstr method is now virtual and other
builders now only have to override buildInstr (for say constant
folding/cseing) is straightforward.
Also attached here (https://reviews.llvm.org/F7675680) is a clang-tidy
patch that should upgrade the API calls if necessary.
llvm-svn: 348815
2018-12-11 08:48:50 +08:00
|
|
|
TargetOpcode::G_AND, {WideTy},
|
|
|
|
{NewOp, MIRBuilder.buildConstant(WideTy, Mask.getZExtValue())});
|
2018-08-29 11:17:08 +08:00
|
|
|
// There is no overflow if the AndOp is the same as NewOp.
|
|
|
|
MIRBuilder.buildICmp(CmpInst::ICMP_NE, MI.getOperand(1).getReg(), NewOp,
|
|
|
|
AndOp);
|
|
|
|
// Now trunc the NewOp to the original result.
|
|
|
|
MIRBuilder.buildTrunc(MI.getOperand(0).getReg(), NewOp);
|
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2018-08-23 01:59:18 +08:00
|
|
|
case TargetOpcode::G_CTTZ:
|
|
|
|
case TargetOpcode::G_CTTZ_ZERO_UNDEF:
|
|
|
|
case TargetOpcode::G_CTLZ:
|
|
|
|
case TargetOpcode::G_CTLZ_ZERO_UNDEF:
|
|
|
|
case TargetOpcode::G_CTPOP: {
|
|
|
|
// First ZEXT the input.
|
|
|
|
auto MIBSrc = MIRBuilder.buildZExt(WideTy, MI.getOperand(1).getReg());
|
|
|
|
LLT CurTy = MRI.getType(MI.getOperand(0).getReg());
|
|
|
|
if (MI.getOpcode() == TargetOpcode::G_CTTZ) {
|
|
|
|
// The count is the same in the larger type except if the original
|
|
|
|
// value was zero. This can be handled by setting the bit just off
|
|
|
|
// the top of the original type.
|
|
|
|
auto TopBit =
|
|
|
|
APInt::getOneBitSet(WideTy.getSizeInBits(), CurTy.getSizeInBits());
|
|
|
|
MIBSrc = MIRBuilder.buildInstr(
|
[GISel]: Refactor MachineIRBuilder to allow passing additional parameters to build Instrs
https://reviews.llvm.org/D55294
Previously MachineIRBuilder::buildInstr used to accept variadic
arguments for sources (which were either unsigned or
MachineInstrBuilder). While this worked well in common cases, it doesn't
allow us to build instructions that have multiple destinations.
Additionally passing in other optional parameters in the end (such as
flags) is not possible trivially. Also a trivial call such as
B.buildInstr(Opc, Reg1, Reg2, Reg3)
can be interpreted differently based on the opcode (2defs + 1 src for
unmerge vs 1 def + 2srcs).
This patch refactors the buildInstr to
buildInstr(Opc, ArrayRef<DstOps>, ArrayRef<SrcOps>)
where DstOps and SrcOps are typed unions that know how to add itself to
MachineInstrBuilder.
After this patch, most invocations would look like
B.buildInstr(Opc, {s32, DstReg}, {SrcRegs..., SrcMIBs..});
Now all the other calls (such as buildAdd, buildSub etc) forward to
buildInstr. It also makes it possible to build instructions with
multiple defs.
Additionally in a subsequent patch, we should make it possible to add
flags directly while building instructions.
Additionally, the main buildInstr method is now virtual and other
builders now only have to override buildInstr (for say constant
folding/cseing) is straightforward.
Also attached here (https://reviews.llvm.org/F7675680) is a clang-tidy
patch that should upgrade the API calls if necessary.
llvm-svn: 348815
2018-12-11 08:48:50 +08:00
|
|
|
TargetOpcode::G_OR, {WideTy},
|
|
|
|
{MIBSrc, MIRBuilder.buildConstant(WideTy, TopBit.getSExtValue())});
|
2018-08-23 01:59:18 +08:00
|
|
|
}
|
|
|
|
// Perform the operation at the larger size.
|
[GISel]: Refactor MachineIRBuilder to allow passing additional parameters to build Instrs
https://reviews.llvm.org/D55294
Previously MachineIRBuilder::buildInstr used to accept variadic
arguments for sources (which were either unsigned or
MachineInstrBuilder). While this worked well in common cases, it doesn't
allow us to build instructions that have multiple destinations.
Additionally passing in other optional parameters in the end (such as
flags) is not possible trivially. Also a trivial call such as
B.buildInstr(Opc, Reg1, Reg2, Reg3)
can be interpreted differently based on the opcode (2defs + 1 src for
unmerge vs 1 def + 2srcs).
This patch refactors the buildInstr to
buildInstr(Opc, ArrayRef<DstOps>, ArrayRef<SrcOps>)
where DstOps and SrcOps are typed unions that know how to add itself to
MachineInstrBuilder.
After this patch, most invocations would look like
B.buildInstr(Opc, {s32, DstReg}, {SrcRegs..., SrcMIBs..});
Now all the other calls (such as buildAdd, buildSub etc) forward to
buildInstr. It also makes it possible to build instructions with
multiple defs.
Additionally in a subsequent patch, we should make it possible to add
flags directly while building instructions.
Additionally, the main buildInstr method is now virtual and other
builders now only have to override buildInstr (for say constant
folding/cseing) is straightforward.
Also attached here (https://reviews.llvm.org/F7675680) is a clang-tidy
patch that should upgrade the API calls if necessary.
llvm-svn: 348815
2018-12-11 08:48:50 +08:00
|
|
|
auto MIBNewOp = MIRBuilder.buildInstr(MI.getOpcode(), {WideTy}, {MIBSrc});
|
2018-08-23 01:59:18 +08:00
|
|
|
// This is already the correct result for CTPOP and CTTZs
|
|
|
|
if (MI.getOpcode() == TargetOpcode::G_CTLZ ||
|
|
|
|
MI.getOpcode() == TargetOpcode::G_CTLZ_ZERO_UNDEF) {
|
|
|
|
// The correct result is NewOp - (Difference in widety and current ty).
|
|
|
|
unsigned SizeDiff = WideTy.getSizeInBits() - CurTy.getSizeInBits();
|
[GISel]: Refactor MachineIRBuilder to allow passing additional parameters to build Instrs
https://reviews.llvm.org/D55294
Previously MachineIRBuilder::buildInstr used to accept variadic
arguments for sources (which were either unsigned or
MachineInstrBuilder). While this worked well in common cases, it doesn't
allow us to build instructions that have multiple destinations.
Additionally passing in other optional parameters in the end (such as
flags) is not possible trivially. Also a trivial call such as
B.buildInstr(Opc, Reg1, Reg2, Reg3)
can be interpreted differently based on the opcode (2defs + 1 src for
unmerge vs 1 def + 2srcs).
This patch refactors the buildInstr to
buildInstr(Opc, ArrayRef<DstOps>, ArrayRef<SrcOps>)
where DstOps and SrcOps are typed unions that know how to add itself to
MachineInstrBuilder.
After this patch, most invocations would look like
B.buildInstr(Opc, {s32, DstReg}, {SrcRegs..., SrcMIBs..});
Now all the other calls (such as buildAdd, buildSub etc) forward to
buildInstr. It also makes it possible to build instructions with
multiple defs.
Additionally in a subsequent patch, we should make it possible to add
flags directly while building instructions.
Additionally, the main buildInstr method is now virtual and other
builders now only have to override buildInstr (for say constant
folding/cseing) is straightforward.
Also attached here (https://reviews.llvm.org/F7675680) is a clang-tidy
patch that should upgrade the API calls if necessary.
llvm-svn: 348815
2018-12-11 08:48:50 +08:00
|
|
|
MIBNewOp = MIRBuilder.buildInstr(
|
|
|
|
TargetOpcode::G_SUB, {WideTy},
|
|
|
|
{MIBNewOp, MIRBuilder.buildConstant(WideTy, SizeDiff)});
|
2018-08-23 01:59:18 +08:00
|
|
|
}
|
|
|
|
auto &TII = *MI.getMF()->getSubtarget().getInstrInfo();
|
2018-11-26 19:06:53 +08:00
|
|
|
// Make the original instruction a trunc now, and update its source.
|
2018-12-13 07:48:13 +08:00
|
|
|
Observer.changingInstr(MI);
|
2018-08-23 01:59:18 +08:00
|
|
|
MI.setDesc(TII.get(TargetOpcode::G_TRUNC));
|
|
|
|
MI.getOperand(1).setReg(MIBNewOp->getOperand(0).getReg());
|
2018-12-06 04:14:52 +08:00
|
|
|
Observer.changedInstr(MI);
|
2018-08-23 01:59:18 +08:00
|
|
|
return Legalized;
|
|
|
|
}
|
2018-05-10 01:28:18 +08:00
|
|
|
|
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:
|
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.
|
2018-12-13 07:48:13 +08:00
|
|
|
Observer.changingInstr(MI);
|
2018-05-10 01:28:18 +08:00
|
|
|
widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
|
|
|
|
widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
|
|
|
|
widenScalarDst(MI, WideTy);
|
2018-12-06 04:14:52 +08:00
|
|
|
Observer.changedInstr(MI);
|
2016-08-05 02:35:11 +08:00
|
|
|
return Legalized;
|
2018-05-10 01:28:18 +08:00
|
|
|
|
[GlobalISel][Legalizer] Widening the second src op of shifts bug fix
The second source operand of G_SHL, G_ASHR, and G_LSHR must preserve its
value as a (small) unsigned integer, therefore its incorrect to widen it
in any way but by zero extending it.
G_SHL was using G_ANYEXT and G_ASHR - G_SEXT (which is correct for their
destination and first source operands, but not the "number of bits to
shift" operand).
Generally, shifts aren't as similar to regular binary operations as it
might seem, for instance, they aren't commutative nor associative and
the second source operand usually requires a special treatment.
Reviewers: bogner, javed.absar, aivchenk, rovka
Reviewed By: bogner
Subscribers: igorb, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D46413
llvm-svn: 331926
2018-05-10 05:43:30 +08:00
|
|
|
case TargetOpcode::G_SHL:
|
2019-01-23 05:42:11 +08:00
|
|
|
Observer.changingInstr(MI);
|
|
|
|
|
|
|
|
if (TypeIdx == 0) {
|
|
|
|
widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
|
|
|
|
widenScalarDst(MI, WideTy);
|
|
|
|
} else {
|
|
|
|
assert(TypeIdx == 1);
|
|
|
|
// The "number of bits to shift" operand must preserve its value as an
|
|
|
|
// unsigned integer:
|
|
|
|
widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
|
|
|
|
}
|
|
|
|
|
2018-12-06 04:14:52 +08:00
|
|
|
Observer.changedInstr(MI);
|
[GlobalISel][Legalizer] Widening the second src op of shifts bug fix
The second source operand of G_SHL, G_ASHR, and G_LSHR must preserve its
value as a (small) unsigned integer, therefore its incorrect to widen it
in any way but by zero extending it.
G_SHL was using G_ANYEXT and G_ASHR - G_SEXT (which is correct for their
destination and first source operands, but not the "number of bits to
shift" operand).
Generally, shifts aren't as similar to regular binary operations as it
might seem, for instance, they aren't commutative nor associative and
the second source operand usually requires a special treatment.
Reviewers: bogner, javed.absar, aivchenk, rovka
Reviewed By: bogner
Subscribers: igorb, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D46413
llvm-svn: 331926
2018-05-10 05:43:30 +08:00
|
|
|
return Legalized;
|
|
|
|
|
2016-08-27 01:46:06 +08:00
|
|
|
case TargetOpcode::G_SDIV:
|
2018-05-09 09:43:12 +08:00
|
|
|
case TargetOpcode::G_SREM:
|
2018-12-13 07:48:13 +08:00
|
|
|
Observer.changingInstr(MI);
|
2018-05-10 01:28:18 +08:00
|
|
|
widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
|
|
|
|
widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
|
|
|
|
widenScalarDst(MI, WideTy);
|
2018-12-06 04:14:52 +08:00
|
|
|
Observer.changedInstr(MI);
|
[GlobalISel][Legalizer] More concise and faster widenScalar, NFC
Refactoring LegalizerHelper::widenScalar member function reducing its
size by approximately a factor of 2 and (hopefuly) making it more
straightforward and regular by introducing widenScalarSrc and
widenScalarDst helper methods.
The new widenScalar* methods mutate the instructions in place instead
of recreating them from scratch and removing the originals. The
compile time implications of this were measured on sqlite3
amalgamation, targeting AArch64 in -O0:
LegalizerHelper::widenScalar: > 25% faster
Legalizer::runOnMachineFunction: ~ 4.0 - 4.5% faster
Also adding MachineOperand::setCImm and refactoring out
MachineIRBuilder::recordInsertion methods to make the change possible.
Reviewers: aditya_nandakumar, bogner, javed.absar, t.p.northover, ab, dsanders, arsenm
Reviewed By: aditya_nandakumar
Subscribers: wdng, rovka, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D46414
llvm-svn: 331819
2018-05-09 06:53:09 +08:00
|
|
|
return Legalized;
|
2018-05-10 01:28:18 +08:00
|
|
|
|
[GlobalISel][Legalizer] Widening the second src op of shifts bug fix
The second source operand of G_SHL, G_ASHR, and G_LSHR must preserve its
value as a (small) unsigned integer, therefore its incorrect to widen it
in any way but by zero extending it.
G_SHL was using G_ANYEXT and G_ASHR - G_SEXT (which is correct for their
destination and first source operands, but not the "number of bits to
shift" operand).
Generally, shifts aren't as similar to regular binary operations as it
might seem, for instance, they aren't commutative nor associative and
the second source operand usually requires a special treatment.
Reviewers: bogner, javed.absar, aivchenk, rovka
Reviewed By: bogner
Subscribers: igorb, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D46413
llvm-svn: 331926
2018-05-10 05:43:30 +08:00
|
|
|
case TargetOpcode::G_ASHR:
|
2019-01-23 05:42:11 +08:00
|
|
|
case TargetOpcode::G_LSHR:
|
2018-12-13 07:48:13 +08:00
|
|
|
Observer.changingInstr(MI);
|
2019-01-23 05:42:11 +08:00
|
|
|
|
|
|
|
if (TypeIdx == 0) {
|
|
|
|
unsigned CvtOp = MI.getOpcode() == TargetOpcode::G_ASHR ?
|
|
|
|
TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT;
|
|
|
|
|
|
|
|
widenScalarSrc(MI, WideTy, 1, CvtOp);
|
|
|
|
widenScalarDst(MI, WideTy);
|
|
|
|
} else {
|
|
|
|
assert(TypeIdx == 1);
|
|
|
|
// The "number of bits to shift" operand must preserve its value as an
|
|
|
|
// unsigned integer:
|
|
|
|
widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
|
|
|
|
}
|
|
|
|
|
2018-12-06 04:14:52 +08:00
|
|
|
Observer.changedInstr(MI);
|
[GlobalISel][Legalizer] Widening the second src op of shifts bug fix
The second source operand of G_SHL, G_ASHR, and G_LSHR must preserve its
value as a (small) unsigned integer, therefore its incorrect to widen it
in any way but by zero extending it.
G_SHL was using G_ANYEXT and G_ASHR - G_SEXT (which is correct for their
destination and first source operands, but not the "number of bits to
shift" operand).
Generally, shifts aren't as similar to regular binary operations as it
might seem, for instance, they aren't commutative nor associative and
the second source operand usually requires a special treatment.
Reviewers: bogner, javed.absar, aivchenk, rovka
Reviewed By: bogner
Subscribers: igorb, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D46413
llvm-svn: 331926
2018-05-10 05:43:30 +08:00
|
|
|
return Legalized;
|
2018-05-10 01:28:18 +08:00
|
|
|
case TargetOpcode::G_UDIV:
|
|
|
|
case TargetOpcode::G_UREM:
|
2018-12-13 07:48:13 +08:00
|
|
|
Observer.changingInstr(MI);
|
2018-05-10 01:28:18 +08:00
|
|
|
widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
|
|
|
|
widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ZEXT);
|
|
|
|
widenScalarDst(MI, WideTy);
|
2018-12-06 04:14:52 +08:00
|
|
|
Observer.changedInstr(MI);
|
2018-05-10 01:28:18 +08:00
|
|
|
return Legalized;
|
|
|
|
|
|
|
|
case TargetOpcode::G_SELECT:
|
2018-12-13 07:48:13 +08:00
|
|
|
Observer.changingInstr(MI);
|
2018-12-25 22:42:30 +08:00
|
|
|
if (TypeIdx == 0) {
|
|
|
|
// 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.
|
|
|
|
widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_ANYEXT);
|
|
|
|
widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_ANYEXT);
|
|
|
|
widenScalarDst(MI, WideTy);
|
|
|
|
} else {
|
|
|
|
// Explicit extension is required here since high bits affect the result.
|
|
|
|
widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
|
|
|
|
}
|
2018-12-06 04:14:52 +08:00
|
|
|
Observer.changedInstr(MI);
|
2017-02-07 07:41:27 +08:00
|
|
|
return Legalized;
|
2018-05-10 01:28:18 +08:00
|
|
|
|
2017-01-24 05:10:14 +08:00
|
|
|
case TargetOpcode::G_FPTOSI:
|
2018-05-10 01:28:18 +08:00
|
|
|
case TargetOpcode::G_FPTOUI:
|
2017-01-24 05:10:14 +08:00
|
|
|
if (TypeIdx != 0)
|
|
|
|
return UnableToLegalize;
|
2018-12-13 07:48:13 +08:00
|
|
|
Observer.changingInstr(MI);
|
2018-05-10 01:28:18 +08:00
|
|
|
widenScalarDst(MI, WideTy);
|
2018-12-06 04:14:52 +08:00
|
|
|
Observer.changedInstr(MI);
|
2018-05-09 09:43:12 +08:00
|
|
|
return Legalized;
|
2018-05-10 01:28:18 +08:00
|
|
|
|
2017-01-20 09:37:24 +08:00
|
|
|
case TargetOpcode::G_SITOFP:
|
|
|
|
if (TypeIdx != 1)
|
|
|
|
return UnableToLegalize;
|
2018-12-13 07:48:13 +08:00
|
|
|
Observer.changingInstr(MI);
|
2018-05-10 01:28:18 +08:00
|
|
|
widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_SEXT);
|
2018-12-06 04:14:52 +08:00
|
|
|
Observer.changedInstr(MI);
|
2018-05-10 01:28:18 +08:00
|
|
|
return Legalized;
|
2017-01-20 09:37:24 +08:00
|
|
|
|
2018-05-10 01:28:18 +08:00
|
|
|
case TargetOpcode::G_UITOFP:
|
|
|
|
if (TypeIdx != 1)
|
|
|
|
return UnableToLegalize;
|
2018-12-13 07:48:13 +08:00
|
|
|
Observer.changingInstr(MI);
|
2018-05-10 01:28:18 +08:00
|
|
|
widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ZEXT);
|
2018-12-06 04:14:52 +08:00
|
|
|
Observer.changedInstr(MI);
|
2018-05-09 09:43:12 +08:00
|
|
|
return Legalized;
|
2018-05-10 01:28:18 +08:00
|
|
|
|
|
|
|
case TargetOpcode::G_INSERT:
|
2017-02-07 05:56:47 +08:00
|
|
|
if (TypeIdx != 0)
|
|
|
|
return UnableToLegalize;
|
2018-12-13 07:48:13 +08:00
|
|
|
Observer.changingInstr(MI);
|
2018-05-10 01:28:18 +08:00
|
|
|
widenScalarSrc(MI, WideTy, 1, TargetOpcode::G_ANYEXT);
|
|
|
|
widenScalarDst(MI, WideTy);
|
2018-12-06 04:14:52 +08:00
|
|
|
Observer.changedInstr(MI);
|
2018-05-09 09:43:12 +08:00
|
|
|
return Legalized;
|
2018-05-10 01:28:18 +08:00
|
|
|
|
[globalisel][legalizerinfo] Introduce dedicated extending loads and add lowerings for them
Summary:
Previously, a extending load was represented at (G_*EXT (G_LOAD x)).
This had a few drawbacks:
* G_LOAD had to be legal for all sizes you could extend from, even if
registers didn't naturally hold those sizes.
* All sizes you could extend from had to be allocatable just in case the
extend went missing (e.g. by optimization).
* At minimum, G_*EXT and G_TRUNC had to be legal for these sizes. As we
improve optimization of extends and truncates, this legality requirement
would spread without considerable care w.r.t when certain combines were
permitted.
* The SelectionDAG importer required some ugly and fragile pattern
rewriting to translate patterns into this style.
This patch begins changing the representation to:
* (G_[SZ]EXTLOAD x)
* (G_LOAD x) any-extends when MMO.getSize() * 8 < ResultTy.getSizeInBits()
which resolves these issues by allowing targets to work entirely in their
native register sizes, and by having a more direct translation from
SelectionDAG patterns.
This patch introduces the new generic instructions and new variation on
G_LOAD and adds lowering for them to convert back to the existing
representations.
Depends on D45466
Reviewers: ab, aditya_nandakumar, bogner, rtereshin, volkan, rovka, aemerson, javed.absar
Reviewed By: aemerson
Subscribers: aemerson, kristof.beyls, javed.absar, llvm-commits
Differential Revision: https://reviews.llvm.org/D45540
llvm-svn: 331115
2018-04-29 02:14:50 +08:00
|
|
|
case TargetOpcode::G_LOAD:
|
2018-02-02 04:47:03 +08:00
|
|
|
// For some types like i24, we might try to widen to i32. To properly handle
|
|
|
|
// this we should be using a dedicated extending load, until then avoid
|
|
|
|
// trying to legalize.
|
|
|
|
if (alignTo(MRI.getType(MI.getOperand(0).getReg()).getSizeInBits(), 8) !=
|
|
|
|
WideTy.getSizeInBits())
|
|
|
|
return UnableToLegalize;
|
[globalisel][legalizerinfo] Introduce dedicated extending loads and add lowerings for them
Summary:
Previously, a extending load was represented at (G_*EXT (G_LOAD x)).
This had a few drawbacks:
* G_LOAD had to be legal for all sizes you could extend from, even if
registers didn't naturally hold those sizes.
* All sizes you could extend from had to be allocatable just in case the
extend went missing (e.g. by optimization).
* At minimum, G_*EXT and G_TRUNC had to be legal for these sizes. As we
improve optimization of extends and truncates, this legality requirement
would spread without considerable care w.r.t when certain combines were
permitted.
* The SelectionDAG importer required some ugly and fragile pattern
rewriting to translate patterns into this style.
This patch begins changing the representation to:
* (G_[SZ]EXTLOAD x)
* (G_LOAD x) any-extends when MMO.getSize() * 8 < ResultTy.getSizeInBits()
which resolves these issues by allowing targets to work entirely in their
native register sizes, and by having a more direct translation from
SelectionDAG patterns.
This patch introduces the new generic instructions and new variation on
G_LOAD and adds lowering for them to convert back to the existing
representations.
Depends on D45466
Reviewers: ab, aditya_nandakumar, bogner, rtereshin, volkan, rovka, aemerson, javed.absar
Reviewed By: aemerson
Subscribers: aemerson, kristof.beyls, javed.absar, llvm-commits
Differential Revision: https://reviews.llvm.org/D45540
llvm-svn: 331115
2018-04-29 02:14:50 +08:00
|
|
|
LLVM_FALLTHROUGH;
|
|
|
|
case TargetOpcode::G_SEXTLOAD:
|
2018-05-10 01:28:18 +08:00
|
|
|
case TargetOpcode::G_ZEXTLOAD:
|
2018-12-13 07:48:13 +08:00
|
|
|
Observer.changingInstr(MI);
|
2018-05-10 01:28:18 +08:00
|
|
|
widenScalarDst(MI, WideTy);
|
2018-12-06 04:14:52 +08:00
|
|
|
Observer.changedInstr(MI);
|
2016-08-24 02:20:09 +08:00
|
|
|
return Legalized;
|
2018-05-10 01:28:18 +08:00
|
|
|
|
2016-08-24 02:20:09 +08:00
|
|
|
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;
|
|
|
|
|
2018-12-13 07:48:13 +08:00
|
|
|
Observer.changingInstr(MI);
|
2018-06-01 21:20:32 +08:00
|
|
|
widenScalarSrc(MI, WideTy, 0, TargetOpcode::G_ZEXT);
|
2018-12-06 04:14:52 +08:00
|
|
|
Observer.changedInstr(MI);
|
2016-08-24 02:20:09 +08:00
|
|
|
return Legalized;
|
|
|
|
}
|
2016-08-20 06:40:00 +08:00
|
|
|
case TargetOpcode::G_CONSTANT: {
|
2018-05-10 01:28:18 +08:00
|
|
|
MachineOperand &SrcMO = MI.getOperand(1);
|
|
|
|
LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
|
|
|
|
const APInt &Val = SrcMO.getCImm()->getValue().sext(WideTy.getSizeInBits());
|
2018-12-13 07:48:13 +08:00
|
|
|
Observer.changingInstr(MI);
|
2018-05-10 01:28:18 +08:00
|
|
|
SrcMO.setCImm(ConstantInt::get(Ctx, Val));
|
|
|
|
|
|
|
|
widenScalarDst(MI, WideTy);
|
2018-12-06 04:14:52 +08:00
|
|
|
Observer.changedInstr(MI);
|
2016-08-20 06:40:00 +08:00
|
|
|
return Legalized;
|
|
|
|
}
|
2016-08-20 06:40:08 +08:00
|
|
|
case TargetOpcode::G_FCONSTANT: {
|
2018-05-10 01:28:18 +08:00
|
|
|
MachineOperand &SrcMO = MI.getOperand(1);
|
2018-01-27 15:07:20 +08:00
|
|
|
LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
|
2018-05-10 01:28:18 +08:00
|
|
|
APFloat Val = SrcMO.getFPImm()->getValueAPF();
|
2018-01-27 15:07:20 +08:00
|
|
|
bool LosesInfo;
|
2018-05-10 01:28:18 +08:00
|
|
|
switch (WideTy.getSizeInBits()) {
|
|
|
|
case 32:
|
|
|
|
Val.convert(APFloat::IEEEsingle(), APFloat::rmTowardZero, &LosesInfo);
|
|
|
|
break;
|
|
|
|
case 64:
|
|
|
|
Val.convert(APFloat::IEEEdouble(), APFloat::rmTowardZero, &LosesInfo);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
llvm_unreachable("Unhandled fp widen type");
|
|
|
|
}
|
2018-12-13 07:48:13 +08:00
|
|
|
Observer.changingInstr(MI);
|
2018-05-10 01:28:18 +08:00
|
|
|
SrcMO.setFPImm(ConstantFP::get(Ctx, Val));
|
|
|
|
|
|
|
|
widenScalarDst(MI, WideTy, 0, TargetOpcode::G_FPTRUNC);
|
2018-12-06 04:14:52 +08:00
|
|
|
Observer.changedInstr(MI);
|
2016-08-20 06:40:08 +08:00
|
|
|
return Legalized;
|
|
|
|
}
|
2019-01-09 15:34:14 +08:00
|
|
|
case TargetOpcode::G_IMPLICIT_DEF: {
|
|
|
|
Observer.changingInstr(MI);
|
|
|
|
widenScalarDst(MI, WideTy);
|
|
|
|
Observer.changedInstr(MI);
|
|
|
|
return Legalized;
|
|
|
|
}
|
2018-05-10 01:28:18 +08:00
|
|
|
case TargetOpcode::G_BRCOND:
|
2018-12-13 07:48:13 +08:00
|
|
|
Observer.changingInstr(MI);
|
2018-05-10 01:28:18 +08:00
|
|
|
widenScalarSrc(MI, WideTy, 0, TargetOpcode::G_ANYEXT);
|
2018-12-06 04:14:52 +08:00
|
|
|
Observer.changedInstr(MI);
|
2016-08-24 05:01:20 +08:00
|
|
|
return Legalized;
|
2018-05-10 01:28:18 +08:00
|
|
|
|
|
|
|
case TargetOpcode::G_FCMP:
|
2018-12-13 07:48:13 +08:00
|
|
|
Observer.changingInstr(MI);
|
2017-08-01 01:00:16 +08:00
|
|
|
if (TypeIdx == 0)
|
2018-05-10 01:28:18 +08:00
|
|
|
widenScalarDst(MI, WideTy);
|
|
|
|
else {
|
|
|
|
widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_FPEXT);
|
|
|
|
widenScalarSrc(MI, WideTy, 3, TargetOpcode::G_FPEXT);
|
[GlobalISel][Legalizer] More concise and faster widenScalar, NFC
Refactoring LegalizerHelper::widenScalar member function reducing its
size by approximately a factor of 2 and (hopefuly) making it more
straightforward and regular by introducing widenScalarSrc and
widenScalarDst helper methods.
The new widenScalar* methods mutate the instructions in place instead
of recreating them from scratch and removing the originals. The
compile time implications of this were measured on sqlite3
amalgamation, targeting AArch64 in -O0:
LegalizerHelper::widenScalar: > 25% faster
Legalizer::runOnMachineFunction: ~ 4.0 - 4.5% faster
Also adding MachineOperand::setCImm and refactoring out
MachineIRBuilder::recordInsertion methods to make the change possible.
Reviewers: aditya_nandakumar, bogner, javed.absar, t.p.northover, ab, dsanders, arsenm
Reviewed By: aditya_nandakumar
Subscribers: wdng, rovka, kristof.beyls, llvm-commits
Differential Revision: https://reviews.llvm.org/D46414
llvm-svn: 331819
2018-05-09 06:53:09 +08:00
|
|
|
}
|
2018-12-06 04:14:52 +08:00
|
|
|
Observer.changedInstr(MI);
|
2018-05-10 01:28:18 +08:00
|
|
|
return Legalized;
|
|
|
|
|
|
|
|
case TargetOpcode::G_ICMP:
|
2018-12-13 07:48:13 +08:00
|
|
|
Observer.changingInstr(MI);
|
2018-05-09 09:43:12 +08:00
|
|
|
if (TypeIdx == 0)
|
2018-05-10 01:28:18 +08:00
|
|
|
widenScalarDst(MI, WideTy);
|
|
|
|
else {
|
|
|
|
unsigned ExtOpcode = CmpInst::isSigned(static_cast<CmpInst::Predicate>(
|
|
|
|
MI.getOperand(1).getPredicate()))
|
|
|
|
? TargetOpcode::G_SEXT
|
|
|
|
: TargetOpcode::G_ZEXT;
|
|
|
|
widenScalarSrc(MI, WideTy, 2, ExtOpcode);
|
|
|
|
widenScalarSrc(MI, WideTy, 3, ExtOpcode);
|
|
|
|
}
|
2018-12-06 04:14:52 +08:00
|
|
|
Observer.changedInstr(MI);
|
2016-08-27 01:46:17 +08:00
|
|
|
return Legalized;
|
2018-05-10 01:28:18 +08:00
|
|
|
|
|
|
|
case TargetOpcode::G_GEP:
|
2016-09-15 19:02:19 +08:00
|
|
|
assert(TypeIdx == 1 && "unable to legalize pointer of GEP");
|
2018-12-13 07:48:13 +08:00
|
|
|
Observer.changingInstr(MI);
|
2018-05-10 01:28:18 +08:00
|
|
|
widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
|
2018-12-06 04:14:52 +08:00
|
|
|
Observer.changedInstr(MI);
|
2016-09-15 19:02:19 +08:00
|
|
|
return Legalized;
|
2018-05-10 01:28:18 +08:00
|
|
|
|
2017-08-25 12:57:27 +08:00
|
|
|
case TargetOpcode::G_PHI: {
|
|
|
|
assert(TypeIdx == 0 && "Expecting only Idx 0");
|
2018-05-10 01:28:18 +08:00
|
|
|
|
2018-12-13 07:48:13 +08:00
|
|
|
Observer.changingInstr(MI);
|
2018-05-10 01:28:18 +08:00
|
|
|
for (unsigned I = 1; I < MI.getNumOperands(); I += 2) {
|
|
|
|
MachineBasicBlock &OpMBB = *MI.getOperand(I + 1).getMBB();
|
|
|
|
MIRBuilder.setInsertPt(OpMBB, OpMBB.getFirstTerminator());
|
|
|
|
widenScalarSrc(MI, WideTy, I, TargetOpcode::G_ANYEXT);
|
2017-08-25 12:57:27 +08:00
|
|
|
}
|
2018-05-10 01:28:18 +08:00
|
|
|
|
|
|
|
MachineBasicBlock &MBB = *MI.getParent();
|
|
|
|
MIRBuilder.setInsertPt(MBB, --MBB.getFirstNonPHI());
|
|
|
|
widenScalarDst(MI, WideTy);
|
2018-12-06 04:14:52 +08:00
|
|
|
Observer.changedInstr(MI);
|
2017-08-25 12:57:27 +08:00
|
|
|
return Legalized;
|
|
|
|
}
|
2019-01-23 04:38:15 +08:00
|
|
|
case TargetOpcode::G_EXTRACT_VECTOR_ELT: {
|
|
|
|
if (TypeIdx == 0) {
|
|
|
|
unsigned VecReg = MI.getOperand(1).getReg();
|
|
|
|
LLT VecTy = MRI.getType(VecReg);
|
|
|
|
Observer.changingInstr(MI);
|
|
|
|
|
|
|
|
widenScalarSrc(MI, LLT::vector(VecTy.getNumElements(),
|
|
|
|
WideTy.getSizeInBits()),
|
|
|
|
1, TargetOpcode::G_SEXT);
|
|
|
|
|
|
|
|
widenScalarDst(MI, WideTy, 0);
|
|
|
|
Observer.changedInstr(MI);
|
|
|
|
return Legalized;
|
|
|
|
}
|
|
|
|
|
2018-10-25 22:04:54 +08:00
|
|
|
if (TypeIdx != 2)
|
|
|
|
return UnableToLegalize;
|
2018-12-13 07:48:13 +08:00
|
|
|
Observer.changingInstr(MI);
|
2018-10-25 22:04:54 +08:00
|
|
|
widenScalarSrc(MI, WideTy, 2, TargetOpcode::G_SEXT);
|
2018-12-06 04:14:52 +08:00
|
|
|
Observer.changedInstr(MI);
|
2018-10-25 22:04:54 +08:00
|
|
|
return Legalized;
|
2019-01-23 04:38:15 +08:00
|
|
|
}
|
2019-01-21 03:10:31 +08:00
|
|
|
case TargetOpcode::G_FADD:
|
|
|
|
case TargetOpcode::G_FMUL:
|
|
|
|
case TargetOpcode::G_FSUB:
|
|
|
|
case TargetOpcode::G_FMA:
|
|
|
|
case TargetOpcode::G_FNEG:
|
|
|
|
case TargetOpcode::G_FABS:
|
|
|
|
case TargetOpcode::G_FDIV:
|
|
|
|
case TargetOpcode::G_FREM:
|
2018-12-22 01:05:26 +08:00
|
|
|
case TargetOpcode::G_FCEIL:
|
2019-01-29 02:34:18 +08:00
|
|
|
case TargetOpcode::G_FCOS:
|
|
|
|
case TargetOpcode::G_FSIN:
|
2019-01-21 03:10:31 +08:00
|
|
|
assert(TypeIdx == 0);
|
2018-12-22 01:05:26 +08:00
|
|
|
Observer.changingInstr(MI);
|
2019-01-21 03:10:31 +08:00
|
|
|
|
|
|
|
for (unsigned I = 1, E = MI.getNumOperands(); I != E; ++I)
|
|
|
|
widenScalarSrc(MI, WideTy, I, TargetOpcode::G_FPEXT);
|
|
|
|
|
2018-12-22 01:05:26 +08:00
|
|
|
widenScalarDst(MI, WideTy, 0, TargetOpcode::G_FPTRUNC);
|
|
|
|
Observer.changedInstr(MI);
|
|
|
|
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);
|
2018-01-03 12:56:56 +08:00
|
|
|
|
|
|
|
// For *signed* multiply, overflow is detected by checking:
|
|
|
|
// (hi != (lo >> bitwidth-1))
|
|
|
|
if (Opcode == TargetOpcode::G_SMULH) {
|
|
|
|
unsigned Shifted = MRI.createGenericVirtualRegister(Ty);
|
|
|
|
unsigned ShiftAmt = MRI.createGenericVirtualRegister(Ty);
|
|
|
|
MIRBuilder.buildConstant(ShiftAmt, Ty.getSizeInBits() - 1);
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_ASHR)
|
|
|
|
.addDef(Shifted)
|
|
|
|
.addUse(Res)
|
|
|
|
.addUse(ShiftAmt);
|
|
|
|
MIRBuilder.buildICmp(CmpInst::ICMP_NE, Overflow, HiPart, Shifted);
|
|
|
|
} else {
|
|
|
|
MIRBuilder.buildICmp(CmpInst::ICMP_NE, Overflow, HiPart, Zero);
|
|
|
|
}
|
2017-02-09 05:22:15 +08:00
|
|
|
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;
|
2017-12-16 06:22:58 +08:00
|
|
|
LLVMContext &Ctx = MIRBuilder.getMF().getFunction().getContext();
|
2017-03-09 02:09:14 +08:00
|
|
|
switch (Ty.getSizeInBits()) {
|
|
|
|
case 16:
|
|
|
|
ZeroTy = Type::getHalfTy(Ctx);
|
|
|
|
break;
|
|
|
|
case 32:
|
|
|
|
ZeroTy = Type::getFloatTy(Ctx);
|
|
|
|
break;
|
|
|
|
case 64:
|
|
|
|
ZeroTy = Type::getDoubleTy(Ctx);
|
|
|
|
break;
|
2017-12-20 01:21:35 +08:00
|
|
|
case 128:
|
|
|
|
ZeroTy = Type::getFP128Ty(Ctx);
|
|
|
|
break;
|
2017-03-09 02:09:14 +08:00
|
|
|
default:
|
|
|
|
llvm_unreachable("unexpected floating-point type");
|
|
|
|
}
|
|
|
|
ConstantFP &ZeroForNegation =
|
|
|
|
*cast<ConstantFP>(ConstantFP::getZeroValueForNegation(ZeroTy));
|
2018-02-15 03:58:36 +08:00
|
|
|
auto Zero = MIRBuilder.buildFConstant(Ty, ZeroForNegation);
|
2017-03-09 02:09:14 +08:00
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_FSUB)
|
|
|
|
.addDef(Res)
|
2018-02-15 03:58:36 +08:00
|
|
|
.addUse(Zero->getOperand(0).getReg())
|
2017-03-09 02:09:14 +08:00
|
|
|
.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.
|
2018-01-30 01:37:29 +08:00
|
|
|
if (LI.getAction({G_FNEG, {Ty}}).Action == Lower)
|
[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
|
|
|
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;
|
|
|
|
}
|
[globalisel][legalizerinfo] Introduce dedicated extending loads and add lowerings for them
Summary:
Previously, a extending load was represented at (G_*EXT (G_LOAD x)).
This had a few drawbacks:
* G_LOAD had to be legal for all sizes you could extend from, even if
registers didn't naturally hold those sizes.
* All sizes you could extend from had to be allocatable just in case the
extend went missing (e.g. by optimization).
* At minimum, G_*EXT and G_TRUNC had to be legal for these sizes. As we
improve optimization of extends and truncates, this legality requirement
would spread without considerable care w.r.t when certain combines were
permitted.
* The SelectionDAG importer required some ugly and fragile pattern
rewriting to translate patterns into this style.
This patch begins changing the representation to:
* (G_[SZ]EXTLOAD x)
* (G_LOAD x) any-extends when MMO.getSize() * 8 < ResultTy.getSizeInBits()
which resolves these issues by allowing targets to work entirely in their
native register sizes, and by having a more direct translation from
SelectionDAG patterns.
This patch introduces the new generic instructions and new variation on
G_LOAD and adds lowering for them to convert back to the existing
representations.
Depends on D45466
Reviewers: ab, aditya_nandakumar, bogner, rtereshin, volkan, rovka, aemerson, javed.absar
Reviewed By: aemerson
Subscribers: aemerson, kristof.beyls, javed.absar, llvm-commits
Differential Revision: https://reviews.llvm.org/D45540
llvm-svn: 331115
2018-04-29 02:14:50 +08:00
|
|
|
case TargetOpcode::G_LOAD:
|
|
|
|
case TargetOpcode::G_SEXTLOAD:
|
|
|
|
case TargetOpcode::G_ZEXTLOAD: {
|
|
|
|
// Lower to a memory-width G_LOAD and a G_SEXT/G_ZEXT/G_ANYEXT
|
|
|
|
unsigned DstReg = MI.getOperand(0).getReg();
|
|
|
|
unsigned PtrReg = MI.getOperand(1).getReg();
|
|
|
|
LLT DstTy = MRI.getType(DstReg);
|
|
|
|
auto &MMO = **MI.memoperands_begin();
|
|
|
|
|
|
|
|
if (DstTy.getSizeInBits() == MMO.getSize() /* in bytes */ * 8) {
|
2018-05-01 01:20:01 +08:00
|
|
|
// In the case of G_LOAD, this was a non-extending load already and we're
|
|
|
|
// about to lower to the same instruction.
|
|
|
|
if (MI.getOpcode() == TargetOpcode::G_LOAD)
|
|
|
|
return UnableToLegalize;
|
[globalisel][legalizerinfo] Introduce dedicated extending loads and add lowerings for them
Summary:
Previously, a extending load was represented at (G_*EXT (G_LOAD x)).
This had a few drawbacks:
* G_LOAD had to be legal for all sizes you could extend from, even if
registers didn't naturally hold those sizes.
* All sizes you could extend from had to be allocatable just in case the
extend went missing (e.g. by optimization).
* At minimum, G_*EXT and G_TRUNC had to be legal for these sizes. As we
improve optimization of extends and truncates, this legality requirement
would spread without considerable care w.r.t when certain combines were
permitted.
* The SelectionDAG importer required some ugly and fragile pattern
rewriting to translate patterns into this style.
This patch begins changing the representation to:
* (G_[SZ]EXTLOAD x)
* (G_LOAD x) any-extends when MMO.getSize() * 8 < ResultTy.getSizeInBits()
which resolves these issues by allowing targets to work entirely in their
native register sizes, and by having a more direct translation from
SelectionDAG patterns.
This patch introduces the new generic instructions and new variation on
G_LOAD and adds lowering for them to convert back to the existing
representations.
Depends on D45466
Reviewers: ab, aditya_nandakumar, bogner, rtereshin, volkan, rovka, aemerson, javed.absar
Reviewed By: aemerson
Subscribers: aemerson, kristof.beyls, javed.absar, llvm-commits
Differential Revision: https://reviews.llvm.org/D45540
llvm-svn: 331115
2018-04-29 02:14:50 +08:00
|
|
|
MIRBuilder.buildLoad(DstReg, PtrReg, MMO);
|
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (DstTy.isScalar()) {
|
|
|
|
unsigned TmpReg = MRI.createGenericVirtualRegister(
|
|
|
|
LLT::scalar(MMO.getSize() /* in bytes */ * 8));
|
|
|
|
MIRBuilder.buildLoad(TmpReg, PtrReg, MMO);
|
|
|
|
switch (MI.getOpcode()) {
|
|
|
|
default:
|
|
|
|
llvm_unreachable("Unexpected opcode");
|
|
|
|
case TargetOpcode::G_LOAD:
|
|
|
|
MIRBuilder.buildAnyExt(DstReg, TmpReg);
|
|
|
|
break;
|
|
|
|
case TargetOpcode::G_SEXTLOAD:
|
|
|
|
MIRBuilder.buildSExt(DstReg, TmpReg);
|
|
|
|
break;
|
|
|
|
case TargetOpcode::G_ZEXTLOAD:
|
|
|
|
MIRBuilder.buildZExt(DstReg, TmpReg);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
|
|
|
|
|
|
|
return UnableToLegalize;
|
|
|
|
}
|
2018-08-22 01:30:31 +08:00
|
|
|
case TargetOpcode::G_CTLZ_ZERO_UNDEF:
|
|
|
|
case TargetOpcode::G_CTTZ_ZERO_UNDEF:
|
|
|
|
case TargetOpcode::G_CTLZ:
|
|
|
|
case TargetOpcode::G_CTTZ:
|
|
|
|
case TargetOpcode::G_CTPOP:
|
|
|
|
return lowerBitCount(MI, TypeIdx, Ty);
|
2018-12-17 20:31:07 +08:00
|
|
|
case G_UADDE: {
|
|
|
|
unsigned Res = MI.getOperand(0).getReg();
|
|
|
|
unsigned CarryOut = MI.getOperand(1).getReg();
|
|
|
|
unsigned LHS = MI.getOperand(2).getReg();
|
|
|
|
unsigned RHS = MI.getOperand(3).getReg();
|
|
|
|
unsigned CarryIn = MI.getOperand(4).getReg();
|
|
|
|
|
|
|
|
unsigned TmpRes = MRI.createGenericVirtualRegister(Ty);
|
|
|
|
unsigned ZExtCarryIn = MRI.createGenericVirtualRegister(Ty);
|
|
|
|
|
|
|
|
MIRBuilder.buildAdd(TmpRes, LHS, RHS);
|
|
|
|
MIRBuilder.buildZExt(ZExtCarryIn, CarryIn);
|
|
|
|
MIRBuilder.buildAdd(Res, TmpRes, ZExtCarryIn);
|
|
|
|
MIRBuilder.buildICmp(CmpInst::ICMP_ULT, CarryOut, Res, LHS);
|
|
|
|
|
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2019-01-28 20:10:17 +08:00
|
|
|
case G_USUBO: {
|
|
|
|
unsigned Res = MI.getOperand(0).getReg();
|
|
|
|
unsigned BorrowOut = MI.getOperand(1).getReg();
|
|
|
|
unsigned LHS = MI.getOperand(2).getReg();
|
|
|
|
unsigned RHS = MI.getOperand(3).getReg();
|
|
|
|
|
|
|
|
MIRBuilder.buildSub(Res, LHS, RHS);
|
|
|
|
MIRBuilder.buildICmp(CmpInst::ICMP_ULT, BorrowOut, LHS, RHS);
|
|
|
|
|
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
|
|
|
case G_USUBE: {
|
|
|
|
unsigned Res = MI.getOperand(0).getReg();
|
|
|
|
unsigned BorrowOut = MI.getOperand(1).getReg();
|
|
|
|
unsigned LHS = MI.getOperand(2).getReg();
|
|
|
|
unsigned RHS = MI.getOperand(3).getReg();
|
|
|
|
unsigned BorrowIn = MI.getOperand(4).getReg();
|
|
|
|
|
|
|
|
unsigned TmpRes = MRI.createGenericVirtualRegister(Ty);
|
|
|
|
unsigned ZExtBorrowIn = MRI.createGenericVirtualRegister(Ty);
|
|
|
|
unsigned LHS_EQ_RHS = MRI.createGenericVirtualRegister(LLT::scalar(1));
|
|
|
|
unsigned LHS_ULT_RHS = MRI.createGenericVirtualRegister(LLT::scalar(1));
|
|
|
|
|
|
|
|
MIRBuilder.buildSub(TmpRes, LHS, RHS);
|
|
|
|
MIRBuilder.buildZExt(ZExtBorrowIn, BorrowIn);
|
|
|
|
MIRBuilder.buildSub(Res, TmpRes, ZExtBorrowIn);
|
|
|
|
MIRBuilder.buildICmp(CmpInst::ICMP_EQ, LHS_EQ_RHS, LHS, RHS);
|
|
|
|
MIRBuilder.buildICmp(CmpInst::ICMP_ULT, LHS_ULT_RHS, LHS, RHS);
|
|
|
|
MIRBuilder.buildSelect(BorrowOut, LHS_EQ_RHS, BorrowIn, LHS_ULT_RHS);
|
|
|
|
|
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2016-08-27 01:46:13 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-28 05:53:09 +08:00
|
|
|
LegalizerHelper::LegalizeResult LegalizerHelper::fewerElementsVectorImplicitDef(
|
|
|
|
MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy) {
|
|
|
|
SmallVector<unsigned, 2> DstRegs;
|
|
|
|
|
|
|
|
unsigned NarrowSize = NarrowTy.getSizeInBits();
|
|
|
|
unsigned DstReg = MI.getOperand(0).getReg();
|
|
|
|
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;
|
|
|
|
|
|
|
|
for (int i = 0; i < NumParts; ++i) {
|
|
|
|
unsigned TmpReg = MRI.createGenericVirtualRegister(NarrowTy);
|
|
|
|
MIRBuilder.buildUndef(TmpReg);
|
|
|
|
DstRegs.push_back(TmpReg);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NarrowTy.isVector())
|
|
|
|
MIRBuilder.buildConcatVectors(DstReg, DstRegs);
|
|
|
|
else
|
|
|
|
MIRBuilder.buildBuildVector(DstReg, DstRegs);
|
|
|
|
|
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
|
|
|
|
|
|
|
LegalizerHelper::LegalizeResult
|
|
|
|
LegalizerHelper::fewerElementsVectorBasic(MachineInstr &MI, unsigned TypeIdx,
|
|
|
|
LLT NarrowTy) {
|
|
|
|
unsigned Opc = MI.getOpcode();
|
|
|
|
unsigned NarrowSize = NarrowTy.getSizeInBits();
|
|
|
|
unsigned DstReg = MI.getOperand(0).getReg();
|
|
|
|
unsigned Flags = MI.getFlags();
|
|
|
|
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;
|
|
|
|
|
|
|
|
unsigned NumOps = MI.getNumOperands() - 1;
|
|
|
|
SmallVector<unsigned, 2> DstRegs, Src0Regs, Src1Regs, Src2Regs;
|
|
|
|
|
|
|
|
extractParts(MI.getOperand(1).getReg(), NarrowTy, NumParts, Src0Regs);
|
|
|
|
|
|
|
|
if (NumOps >= 2)
|
|
|
|
extractParts(MI.getOperand(2).getReg(), NarrowTy, NumParts, Src1Regs);
|
|
|
|
|
|
|
|
if (NumOps >= 3)
|
|
|
|
extractParts(MI.getOperand(3).getReg(), NarrowTy, NumParts, Src2Regs);
|
|
|
|
|
|
|
|
for (int i = 0; i < NumParts; ++i) {
|
|
|
|
unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy);
|
|
|
|
|
|
|
|
if (NumOps == 1)
|
|
|
|
MIRBuilder.buildInstr(Opc, {DstReg}, {Src0Regs[i]}, Flags);
|
|
|
|
else if (NumOps == 2) {
|
|
|
|
MIRBuilder.buildInstr(Opc, {DstReg}, {Src0Regs[i], Src1Regs[i]}, Flags);
|
|
|
|
} else if (NumOps == 3) {
|
|
|
|
MIRBuilder.buildInstr(Opc, {DstReg},
|
|
|
|
{Src0Regs[i], Src1Regs[i], Src2Regs[i]}, Flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
DstRegs.push_back(DstReg);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NarrowTy.isVector())
|
|
|
|
MIRBuilder.buildConcatVectors(DstReg, DstRegs);
|
|
|
|
else
|
|
|
|
MIRBuilder.buildBuildVector(DstReg, DstRegs);
|
|
|
|
|
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
|
|
|
|
2019-01-25 10:36:32 +08:00
|
|
|
LegalizerHelper::LegalizeResult
|
|
|
|
LegalizerHelper::fewerElementsVectorCasts(MachineInstr &MI, unsigned TypeIdx,
|
|
|
|
LLT NarrowTy) {
|
|
|
|
if (TypeIdx != 0)
|
|
|
|
return UnableToLegalize;
|
|
|
|
|
|
|
|
unsigned DstReg = MI.getOperand(0).getReg();
|
|
|
|
unsigned SrcReg = MI.getOperand(1).getReg();
|
|
|
|
LLT DstTy = MRI.getType(DstReg);
|
|
|
|
LLT SrcTy = MRI.getType(SrcReg);
|
|
|
|
|
|
|
|
LLT NarrowTy0 = NarrowTy;
|
|
|
|
LLT NarrowTy1;
|
|
|
|
unsigned NumParts;
|
|
|
|
|
|
|
|
if (NarrowTy.isScalar()) {
|
|
|
|
NumParts = DstTy.getNumElements();
|
|
|
|
NarrowTy1 = SrcTy.getElementType();
|
|
|
|
} else {
|
|
|
|
// Uneven breakdown not handled.
|
|
|
|
NumParts = DstTy.getNumElements() / NarrowTy.getNumElements();
|
|
|
|
if (NumParts * NarrowTy.getNumElements() != DstTy.getNumElements())
|
|
|
|
return UnableToLegalize;
|
|
|
|
|
|
|
|
NarrowTy1 = LLT::vector(NumParts, SrcTy.getElementType().getSizeInBits());
|
|
|
|
}
|
|
|
|
|
|
|
|
SmallVector<unsigned, 4> SrcRegs, DstRegs;
|
|
|
|
extractParts(SrcReg, NarrowTy1, NumParts, SrcRegs);
|
|
|
|
|
|
|
|
for (unsigned I = 0; I < NumParts; ++I) {
|
|
|
|
unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy0);
|
|
|
|
MachineInstr *NewInst = MIRBuilder.buildInstr(MI.getOpcode())
|
|
|
|
.addDef(DstReg)
|
|
|
|
.addUse(SrcRegs[I]);
|
|
|
|
|
|
|
|
NewInst->setFlags(MI.getFlags());
|
|
|
|
DstRegs.push_back(DstReg);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (NarrowTy.isVector())
|
2019-01-28 05:53:09 +08:00
|
|
|
MIRBuilder.buildConcatVectors(DstReg, DstRegs);
|
2019-01-25 10:59:34 +08:00
|
|
|
else
|
|
|
|
MIRBuilder.buildBuildVector(DstReg, DstRegs);
|
|
|
|
|
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
|
|
|
|
|
|
|
LegalizerHelper::LegalizeResult
|
|
|
|
LegalizerHelper::fewerElementsVectorCmp(MachineInstr &MI, unsigned TypeIdx,
|
|
|
|
LLT NarrowTy) {
|
|
|
|
unsigned DstReg = MI.getOperand(0).getReg();
|
|
|
|
unsigned Src0Reg = MI.getOperand(2).getReg();
|
|
|
|
LLT DstTy = MRI.getType(DstReg);
|
|
|
|
LLT SrcTy = MRI.getType(Src0Reg);
|
|
|
|
|
|
|
|
unsigned NumParts;
|
|
|
|
LLT NarrowTy0, NarrowTy1;
|
|
|
|
|
|
|
|
if (TypeIdx == 0) {
|
|
|
|
unsigned NewElts = NarrowTy.isVector() ? NarrowTy.getNumElements() : 1;
|
|
|
|
unsigned OldElts = DstTy.getNumElements();
|
|
|
|
|
|
|
|
NarrowTy0 = NarrowTy;
|
|
|
|
NumParts = NarrowTy.isVector() ? (OldElts / NewElts) : DstTy.getNumElements();
|
|
|
|
NarrowTy1 = NarrowTy.isVector() ?
|
|
|
|
LLT::vector(NarrowTy.getNumElements(), SrcTy.getScalarSizeInBits()) :
|
|
|
|
SrcTy.getElementType();
|
|
|
|
|
|
|
|
} else {
|
|
|
|
unsigned NewElts = NarrowTy.isVector() ? NarrowTy.getNumElements() : 1;
|
|
|
|
unsigned OldElts = SrcTy.getNumElements();
|
|
|
|
|
|
|
|
NumParts = NarrowTy.isVector() ? (OldElts / NewElts) :
|
|
|
|
NarrowTy.getNumElements();
|
|
|
|
NarrowTy0 = LLT::vector(NarrowTy.getNumElements(),
|
|
|
|
DstTy.getScalarSizeInBits());
|
|
|
|
NarrowTy1 = NarrowTy;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: Don't know how to handle the situation where the small vectors
|
|
|
|
// aren't all the same size yet.
|
|
|
|
if (NarrowTy1.isVector() &&
|
|
|
|
NarrowTy1.getNumElements() * NumParts != DstTy.getNumElements())
|
|
|
|
return UnableToLegalize;
|
|
|
|
|
|
|
|
CmpInst::Predicate Pred
|
|
|
|
= static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
|
|
|
|
|
|
|
|
SmallVector<unsigned, 2> Src1Regs, Src2Regs, DstRegs;
|
|
|
|
extractParts(MI.getOperand(2).getReg(), NarrowTy1, NumParts, Src1Regs);
|
|
|
|
extractParts(MI.getOperand(3).getReg(), NarrowTy1, NumParts, Src2Regs);
|
|
|
|
|
|
|
|
for (unsigned I = 0; I < NumParts; ++I) {
|
|
|
|
unsigned DstReg = MRI.createGenericVirtualRegister(NarrowTy0);
|
|
|
|
DstRegs.push_back(DstReg);
|
|
|
|
|
|
|
|
if (MI.getOpcode() == TargetOpcode::G_ICMP)
|
|
|
|
MIRBuilder.buildICmp(Pred, DstReg, Src1Regs[I], Src2Regs[I]);
|
|
|
|
else {
|
|
|
|
MachineInstr *NewCmp
|
|
|
|
= MIRBuilder.buildFCmp(Pred, DstReg, Src1Regs[I], Src2Regs[I]);
|
|
|
|
NewCmp->setFlags(MI.getFlags());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-01-28 05:53:09 +08:00
|
|
|
if (NarrowTy1.isVector())
|
2019-01-25 10:36:32 +08:00
|
|
|
MIRBuilder.buildConcatVectors(DstReg, DstRegs);
|
|
|
|
else
|
|
|
|
MIRBuilder.buildBuildVector(DstReg, DstRegs);
|
|
|
|
|
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
|
|
|
|
2016-10-15 06:18:18 +08:00
|
|
|
LegalizerHelper::LegalizeResult
|
2019-01-28 05:53:09 +08:00
|
|
|
LegalizerHelper::fewerElementsVectorLoadStore(MachineInstr &MI, unsigned TypeIdx,
|
|
|
|
LLT NarrowTy) {
|
|
|
|
// FIXME: Don't know how to handle secondary types yet.
|
|
|
|
if (TypeIdx != 0)
|
2016-07-23 04:03:43 +08:00
|
|
|
return UnableToLegalize;
|
2019-01-09 15:51:52 +08:00
|
|
|
|
2019-01-28 06:36:24 +08:00
|
|
|
MachineMemOperand *MMO = *MI.memoperands_begin();
|
|
|
|
|
|
|
|
// This implementation doesn't work for atomics. Give up instead of doing
|
|
|
|
// something invalid.
|
|
|
|
if (MMO->getOrdering() != AtomicOrdering::NotAtomic ||
|
|
|
|
MMO->getFailureOrdering() != AtomicOrdering::NotAtomic)
|
|
|
|
return UnableToLegalize;
|
|
|
|
|
2019-01-28 05:53:09 +08:00
|
|
|
bool IsLoad = MI.getOpcode() == TargetOpcode::G_LOAD;
|
|
|
|
unsigned ValReg = MI.getOperand(0).getReg();
|
|
|
|
unsigned AddrReg = MI.getOperand(1).getReg();
|
|
|
|
unsigned NarrowSize = NarrowTy.getSizeInBits();
|
|
|
|
unsigned Size = MRI.getType(ValReg).getSizeInBits();
|
|
|
|
unsigned NumParts = Size / NarrowSize;
|
|
|
|
|
|
|
|
SmallVector<unsigned, 8> NarrowRegs;
|
|
|
|
if (!IsLoad)
|
|
|
|
extractParts(ValReg, NarrowTy, NumParts, NarrowRegs);
|
|
|
|
|
|
|
|
const LLT OffsetTy =
|
|
|
|
LLT::scalar(MRI.getType(AddrReg).getScalarSizeInBits());
|
|
|
|
MachineFunction &MF = *MI.getMF();
|
2019-01-28 06:36:24 +08:00
|
|
|
|
2019-01-28 05:53:09 +08:00
|
|
|
for (unsigned Idx = 0; Idx < NumParts; ++Idx) {
|
|
|
|
unsigned Adjustment = Idx * NarrowTy.getSizeInBits() / 8;
|
|
|
|
unsigned Alignment = MinAlign(MMO->getAlignment(), Adjustment);
|
|
|
|
unsigned NewAddrReg = 0;
|
|
|
|
MIRBuilder.materializeGEP(NewAddrReg, AddrReg, OffsetTy, Adjustment);
|
|
|
|
MachineMemOperand &NewMMO = *MF.getMachineMemOperand(
|
|
|
|
MMO->getPointerInfo().getWithOffset(Adjustment), MMO->getFlags(),
|
|
|
|
NarrowTy.getSizeInBits() / 8, Alignment);
|
|
|
|
if (IsLoad) {
|
|
|
|
unsigned Dst = MRI.createGenericVirtualRegister(NarrowTy);
|
|
|
|
NarrowRegs.push_back(Dst);
|
|
|
|
MIRBuilder.buildLoad(Dst, NewAddrReg, NewMMO);
|
|
|
|
} else {
|
|
|
|
MIRBuilder.buildStore(NarrowRegs[Idx], NewAddrReg, NewMMO);
|
2019-01-09 15:51:52 +08:00
|
|
|
}
|
|
|
|
}
|
2019-01-28 05:53:09 +08:00
|
|
|
if (IsLoad) {
|
2019-01-23 04:14:29 +08:00
|
|
|
if (NarrowTy.isVector())
|
2019-01-28 05:53:09 +08:00
|
|
|
MIRBuilder.buildConcatVectors(ValReg, NarrowRegs);
|
2019-01-23 04:14:29 +08:00
|
|
|
else
|
2019-01-28 05:53:09 +08:00
|
|
|
MIRBuilder.buildBuildVector(ValReg, NarrowRegs);
|
2016-07-23 04:03:43 +08:00
|
|
|
}
|
2019-01-28 05:53:09 +08:00
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
2019-01-25 10:59:34 +08:00
|
|
|
|
2019-01-28 05:53:09 +08:00
|
|
|
LegalizerHelper::LegalizeResult
|
|
|
|
LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx,
|
|
|
|
LLT NarrowTy) {
|
|
|
|
using namespace TargetOpcode;
|
|
|
|
|
|
|
|
MIRBuilder.setInstr(MI);
|
|
|
|
switch (MI.getOpcode()) {
|
|
|
|
case G_IMPLICIT_DEF:
|
|
|
|
return fewerElementsVectorImplicitDef(MI, TypeIdx, NarrowTy);
|
|
|
|
case G_AND:
|
|
|
|
case G_OR:
|
|
|
|
case G_XOR:
|
|
|
|
case G_ADD:
|
|
|
|
case G_SUB:
|
|
|
|
case G_MUL:
|
|
|
|
case G_SMULH:
|
|
|
|
case G_UMULH:
|
|
|
|
case G_FADD:
|
|
|
|
case G_FMUL:
|
|
|
|
case G_FSUB:
|
|
|
|
case G_FNEG:
|
|
|
|
case G_FABS:
|
|
|
|
case G_FDIV:
|
|
|
|
case G_FREM:
|
|
|
|
case G_FMA:
|
|
|
|
case G_FPOW:
|
|
|
|
case G_FEXP:
|
|
|
|
case G_FEXP2:
|
|
|
|
case G_FLOG:
|
|
|
|
case G_FLOG2:
|
|
|
|
case G_FLOG10:
|
|
|
|
case G_FCEIL:
|
|
|
|
case G_INTRINSIC_ROUND:
|
|
|
|
case G_INTRINSIC_TRUNC:
|
2019-01-29 02:34:18 +08:00
|
|
|
case G_FCOS:
|
|
|
|
case G_FSIN:
|
2019-01-28 05:53:09 +08:00
|
|
|
return fewerElementsVectorBasic(MI, TypeIdx, NarrowTy);
|
|
|
|
case G_ZEXT:
|
|
|
|
case G_SEXT:
|
|
|
|
case G_ANYEXT:
|
|
|
|
case G_FPEXT:
|
|
|
|
case G_FPTRUNC:
|
|
|
|
case G_SITOFP:
|
|
|
|
case G_UITOFP:
|
|
|
|
case G_FPTOSI:
|
|
|
|
case G_FPTOUI:
|
2019-01-25 10:36:32 +08:00
|
|
|
return fewerElementsVectorCasts(MI, TypeIdx, NarrowTy);
|
2019-01-28 05:53:09 +08:00
|
|
|
case G_ICMP:
|
|
|
|
case G_FCMP:
|
|
|
|
return fewerElementsVectorCmp(MI, TypeIdx, NarrowTy);
|
|
|
|
case G_LOAD:
|
|
|
|
case G_STORE:
|
|
|
|
return fewerElementsVectorLoadStore(MI, TypeIdx, NarrowTy);
|
|
|
|
default:
|
|
|
|
return UnableToLegalize;
|
2016-07-23 04:03:43 +08:00
|
|
|
}
|
|
|
|
}
|
2018-08-22 01:30:31 +08:00
|
|
|
|
2019-01-27 08:52:51 +08:00
|
|
|
LegalizerHelper::LegalizeResult
|
|
|
|
LegalizerHelper::narrowScalarMul(MachineInstr &MI, unsigned TypeIdx, LLT NewTy) {
|
|
|
|
unsigned DstReg = MI.getOperand(0).getReg();
|
|
|
|
unsigned Src0 = MI.getOperand(1).getReg();
|
|
|
|
unsigned Src1 = MI.getOperand(2).getReg();
|
|
|
|
LLT Ty = MRI.getType(DstReg);
|
|
|
|
if (Ty.isVector())
|
|
|
|
return UnableToLegalize;
|
|
|
|
|
|
|
|
unsigned Size = Ty.getSizeInBits();
|
|
|
|
unsigned NewSize = Size / 2;
|
|
|
|
if (Size != 2 * NewSize)
|
|
|
|
return UnableToLegalize;
|
|
|
|
|
|
|
|
LLT HalfTy = LLT::scalar(NewSize);
|
|
|
|
// TODO: if HalfTy != NewTy, handle the breakdown all at once?
|
|
|
|
|
|
|
|
unsigned ShiftAmt = MRI.createGenericVirtualRegister(Ty);
|
|
|
|
unsigned Lo = MRI.createGenericVirtualRegister(HalfTy);
|
|
|
|
unsigned Hi = MRI.createGenericVirtualRegister(HalfTy);
|
|
|
|
unsigned ExtLo = MRI.createGenericVirtualRegister(Ty);
|
|
|
|
unsigned ExtHi = MRI.createGenericVirtualRegister(Ty);
|
|
|
|
unsigned ShiftedHi = MRI.createGenericVirtualRegister(Ty);
|
|
|
|
|
|
|
|
SmallVector<unsigned, 2> Src0Parts;
|
|
|
|
SmallVector<unsigned, 2> Src1Parts;
|
|
|
|
|
|
|
|
extractParts(Src0, HalfTy, 2, Src0Parts);
|
|
|
|
extractParts(Src1, HalfTy, 2, Src1Parts);
|
|
|
|
|
|
|
|
MIRBuilder.buildMul(Lo, Src0Parts[0], Src1Parts[0]);
|
|
|
|
|
|
|
|
// TODO: Use smulh or umulh depending on what the target has.
|
|
|
|
MIRBuilder.buildUMulH(Hi, Src0Parts[1], Src1Parts[1]);
|
|
|
|
|
|
|
|
MIRBuilder.buildConstant(ShiftAmt, NewSize);
|
|
|
|
MIRBuilder.buildAnyExt(ExtHi, Hi);
|
|
|
|
MIRBuilder.buildShl(ShiftedHi, ExtHi, ShiftAmt);
|
|
|
|
|
|
|
|
MIRBuilder.buildZExt(ExtLo, Lo);
|
|
|
|
MIRBuilder.buildOr(DstReg, ExtLo, ShiftedHi);
|
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
|
|
|
|
2018-08-22 01:30:31 +08:00
|
|
|
LegalizerHelper::LegalizeResult
|
|
|
|
LegalizerHelper::lowerBitCount(MachineInstr &MI, unsigned TypeIdx, LLT Ty) {
|
|
|
|
unsigned Opc = MI.getOpcode();
|
|
|
|
auto &TII = *MI.getMF()->getSubtarget().getInstrInfo();
|
2018-11-26 19:07:02 +08:00
|
|
|
auto isSupported = [this](const LegalityQuery &Q) {
|
2018-08-22 01:30:31 +08:00
|
|
|
auto QAction = LI.getAction(Q).Action;
|
2018-11-26 19:07:02 +08:00
|
|
|
return QAction == Legal || QAction == Libcall || QAction == Custom;
|
2018-08-22 01:30:31 +08:00
|
|
|
};
|
|
|
|
switch (Opc) {
|
|
|
|
default:
|
|
|
|
return UnableToLegalize;
|
|
|
|
case TargetOpcode::G_CTLZ_ZERO_UNDEF: {
|
|
|
|
// This trivially expands to CTLZ.
|
2018-12-13 07:48:13 +08:00
|
|
|
Observer.changingInstr(MI);
|
2018-08-22 01:30:31 +08:00
|
|
|
MI.setDesc(TII.get(TargetOpcode::G_CTLZ));
|
2018-12-06 04:14:52 +08:00
|
|
|
Observer.changedInstr(MI);
|
2018-08-22 01:30:31 +08:00
|
|
|
return Legalized;
|
|
|
|
}
|
|
|
|
case TargetOpcode::G_CTLZ: {
|
|
|
|
unsigned SrcReg = MI.getOperand(1).getReg();
|
|
|
|
unsigned Len = Ty.getSizeInBits();
|
2018-11-26 19:07:02 +08:00
|
|
|
if (isSupported({TargetOpcode::G_CTLZ_ZERO_UNDEF, {Ty}})) {
|
|
|
|
// If CTLZ_ZERO_UNDEF is supported, emit that and a select for zero.
|
[GISel]: Refactor MachineIRBuilder to allow passing additional parameters to build Instrs
https://reviews.llvm.org/D55294
Previously MachineIRBuilder::buildInstr used to accept variadic
arguments for sources (which were either unsigned or
MachineInstrBuilder). While this worked well in common cases, it doesn't
allow us to build instructions that have multiple destinations.
Additionally passing in other optional parameters in the end (such as
flags) is not possible trivially. Also a trivial call such as
B.buildInstr(Opc, Reg1, Reg2, Reg3)
can be interpreted differently based on the opcode (2defs + 1 src for
unmerge vs 1 def + 2srcs).
This patch refactors the buildInstr to
buildInstr(Opc, ArrayRef<DstOps>, ArrayRef<SrcOps>)
where DstOps and SrcOps are typed unions that know how to add itself to
MachineInstrBuilder.
After this patch, most invocations would look like
B.buildInstr(Opc, {s32, DstReg}, {SrcRegs..., SrcMIBs..});
Now all the other calls (such as buildAdd, buildSub etc) forward to
buildInstr. It also makes it possible to build instructions with
multiple defs.
Additionally in a subsequent patch, we should make it possible to add
flags directly while building instructions.
Additionally, the main buildInstr method is now virtual and other
builders now only have to override buildInstr (for say constant
folding/cseing) is straightforward.
Also attached here (https://reviews.llvm.org/F7675680) is a clang-tidy
patch that should upgrade the API calls if necessary.
llvm-svn: 348815
2018-12-11 08:48:50 +08:00
|
|
|
auto MIBCtlzZU = MIRBuilder.buildInstr(TargetOpcode::G_CTLZ_ZERO_UNDEF,
|
|
|
|
{Ty}, {SrcReg});
|
2018-08-22 01:30:31 +08:00
|
|
|
auto MIBZero = MIRBuilder.buildConstant(Ty, 0);
|
|
|
|
auto MIBLen = MIRBuilder.buildConstant(Ty, Len);
|
|
|
|
auto MIBICmp = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, LLT::scalar(1),
|
|
|
|
SrcReg, MIBZero);
|
|
|
|
MIRBuilder.buildSelect(MI.getOperand(0).getReg(), MIBICmp, MIBLen,
|
|
|
|
MIBCtlzZU);
|
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
|
|
|
// for now, we do this:
|
|
|
|
// NewLen = NextPowerOf2(Len);
|
|
|
|
// x = x | (x >> 1);
|
|
|
|
// x = x | (x >> 2);
|
|
|
|
// ...
|
|
|
|
// x = x | (x >>16);
|
|
|
|
// x = x | (x >>32); // for 64-bit input
|
|
|
|
// Upto NewLen/2
|
|
|
|
// return Len - popcount(x);
|
|
|
|
//
|
|
|
|
// Ref: "Hacker's Delight" by Henry Warren
|
|
|
|
unsigned Op = SrcReg;
|
|
|
|
unsigned NewLen = PowerOf2Ceil(Len);
|
|
|
|
for (unsigned i = 0; (1U << i) <= (NewLen / 2); ++i) {
|
|
|
|
auto MIBShiftAmt = MIRBuilder.buildConstant(Ty, 1ULL << i);
|
|
|
|
auto MIBOp = MIRBuilder.buildInstr(
|
[GISel]: Refactor MachineIRBuilder to allow passing additional parameters to build Instrs
https://reviews.llvm.org/D55294
Previously MachineIRBuilder::buildInstr used to accept variadic
arguments for sources (which were either unsigned or
MachineInstrBuilder). While this worked well in common cases, it doesn't
allow us to build instructions that have multiple destinations.
Additionally passing in other optional parameters in the end (such as
flags) is not possible trivially. Also a trivial call such as
B.buildInstr(Opc, Reg1, Reg2, Reg3)
can be interpreted differently based on the opcode (2defs + 1 src for
unmerge vs 1 def + 2srcs).
This patch refactors the buildInstr to
buildInstr(Opc, ArrayRef<DstOps>, ArrayRef<SrcOps>)
where DstOps and SrcOps are typed unions that know how to add itself to
MachineInstrBuilder.
After this patch, most invocations would look like
B.buildInstr(Opc, {s32, DstReg}, {SrcRegs..., SrcMIBs..});
Now all the other calls (such as buildAdd, buildSub etc) forward to
buildInstr. It also makes it possible to build instructions with
multiple defs.
Additionally in a subsequent patch, we should make it possible to add
flags directly while building instructions.
Additionally, the main buildInstr method is now virtual and other
builders now only have to override buildInstr (for say constant
folding/cseing) is straightforward.
Also attached here (https://reviews.llvm.org/F7675680) is a clang-tidy
patch that should upgrade the API calls if necessary.
llvm-svn: 348815
2018-12-11 08:48:50 +08:00
|
|
|
TargetOpcode::G_OR, {Ty},
|
|
|
|
{Op, MIRBuilder.buildInstr(TargetOpcode::G_LSHR, {Ty},
|
|
|
|
{Op, MIBShiftAmt})});
|
2018-08-22 01:30:31 +08:00
|
|
|
Op = MIBOp->getOperand(0).getReg();
|
|
|
|
}
|
[GISel]: Refactor MachineIRBuilder to allow passing additional parameters to build Instrs
https://reviews.llvm.org/D55294
Previously MachineIRBuilder::buildInstr used to accept variadic
arguments for sources (which were either unsigned or
MachineInstrBuilder). While this worked well in common cases, it doesn't
allow us to build instructions that have multiple destinations.
Additionally passing in other optional parameters in the end (such as
flags) is not possible trivially. Also a trivial call such as
B.buildInstr(Opc, Reg1, Reg2, Reg3)
can be interpreted differently based on the opcode (2defs + 1 src for
unmerge vs 1 def + 2srcs).
This patch refactors the buildInstr to
buildInstr(Opc, ArrayRef<DstOps>, ArrayRef<SrcOps>)
where DstOps and SrcOps are typed unions that know how to add itself to
MachineInstrBuilder.
After this patch, most invocations would look like
B.buildInstr(Opc, {s32, DstReg}, {SrcRegs..., SrcMIBs..});
Now all the other calls (such as buildAdd, buildSub etc) forward to
buildInstr. It also makes it possible to build instructions with
multiple defs.
Additionally in a subsequent patch, we should make it possible to add
flags directly while building instructions.
Additionally, the main buildInstr method is now virtual and other
builders now only have to override buildInstr (for say constant
folding/cseing) is straightforward.
Also attached here (https://reviews.llvm.org/F7675680) is a clang-tidy
patch that should upgrade the API calls if necessary.
llvm-svn: 348815
2018-12-11 08:48:50 +08:00
|
|
|
auto MIBPop = MIRBuilder.buildInstr(TargetOpcode::G_CTPOP, {Ty}, {Op});
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_SUB, {MI.getOperand(0).getReg()},
|
|
|
|
{MIRBuilder.buildConstant(Ty, Len), MIBPop});
|
2018-08-22 01:30:31 +08:00
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
|
|
|
case TargetOpcode::G_CTTZ_ZERO_UNDEF: {
|
|
|
|
// This trivially expands to CTTZ.
|
2018-12-13 07:48:13 +08:00
|
|
|
Observer.changingInstr(MI);
|
2018-08-22 01:30:31 +08:00
|
|
|
MI.setDesc(TII.get(TargetOpcode::G_CTTZ));
|
2018-12-06 04:14:52 +08:00
|
|
|
Observer.changedInstr(MI);
|
2018-08-22 01:30:31 +08:00
|
|
|
return Legalized;
|
|
|
|
}
|
|
|
|
case TargetOpcode::G_CTTZ: {
|
|
|
|
unsigned SrcReg = MI.getOperand(1).getReg();
|
|
|
|
unsigned Len = Ty.getSizeInBits();
|
2018-11-26 19:07:02 +08:00
|
|
|
if (isSupported({TargetOpcode::G_CTTZ_ZERO_UNDEF, {Ty}})) {
|
2018-08-22 01:30:31 +08:00
|
|
|
// If CTTZ_ZERO_UNDEF is legal or custom, emit that and a select with
|
|
|
|
// zero.
|
[GISel]: Refactor MachineIRBuilder to allow passing additional parameters to build Instrs
https://reviews.llvm.org/D55294
Previously MachineIRBuilder::buildInstr used to accept variadic
arguments for sources (which were either unsigned or
MachineInstrBuilder). While this worked well in common cases, it doesn't
allow us to build instructions that have multiple destinations.
Additionally passing in other optional parameters in the end (such as
flags) is not possible trivially. Also a trivial call such as
B.buildInstr(Opc, Reg1, Reg2, Reg3)
can be interpreted differently based on the opcode (2defs + 1 src for
unmerge vs 1 def + 2srcs).
This patch refactors the buildInstr to
buildInstr(Opc, ArrayRef<DstOps>, ArrayRef<SrcOps>)
where DstOps and SrcOps are typed unions that know how to add itself to
MachineInstrBuilder.
After this patch, most invocations would look like
B.buildInstr(Opc, {s32, DstReg}, {SrcRegs..., SrcMIBs..});
Now all the other calls (such as buildAdd, buildSub etc) forward to
buildInstr. It also makes it possible to build instructions with
multiple defs.
Additionally in a subsequent patch, we should make it possible to add
flags directly while building instructions.
Additionally, the main buildInstr method is now virtual and other
builders now only have to override buildInstr (for say constant
folding/cseing) is straightforward.
Also attached here (https://reviews.llvm.org/F7675680) is a clang-tidy
patch that should upgrade the API calls if necessary.
llvm-svn: 348815
2018-12-11 08:48:50 +08:00
|
|
|
auto MIBCttzZU = MIRBuilder.buildInstr(TargetOpcode::G_CTTZ_ZERO_UNDEF,
|
|
|
|
{Ty}, {SrcReg});
|
2018-08-22 01:30:31 +08:00
|
|
|
auto MIBZero = MIRBuilder.buildConstant(Ty, 0);
|
|
|
|
auto MIBLen = MIRBuilder.buildConstant(Ty, Len);
|
|
|
|
auto MIBICmp = MIRBuilder.buildICmp(CmpInst::ICMP_EQ, LLT::scalar(1),
|
|
|
|
SrcReg, MIBZero);
|
|
|
|
MIRBuilder.buildSelect(MI.getOperand(0).getReg(), MIBICmp, MIBLen,
|
|
|
|
MIBCttzZU);
|
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
|
|
|
// for now, we use: { return popcount(~x & (x - 1)); }
|
|
|
|
// unless the target has ctlz but not ctpop, in which case we use:
|
|
|
|
// { return 32 - nlz(~x & (x-1)); }
|
|
|
|
// Ref: "Hacker's Delight" by Henry Warren
|
|
|
|
auto MIBCstNeg1 = MIRBuilder.buildConstant(Ty, -1);
|
|
|
|
auto MIBNot =
|
[GISel]: Refactor MachineIRBuilder to allow passing additional parameters to build Instrs
https://reviews.llvm.org/D55294
Previously MachineIRBuilder::buildInstr used to accept variadic
arguments for sources (which were either unsigned or
MachineInstrBuilder). While this worked well in common cases, it doesn't
allow us to build instructions that have multiple destinations.
Additionally passing in other optional parameters in the end (such as
flags) is not possible trivially. Also a trivial call such as
B.buildInstr(Opc, Reg1, Reg2, Reg3)
can be interpreted differently based on the opcode (2defs + 1 src for
unmerge vs 1 def + 2srcs).
This patch refactors the buildInstr to
buildInstr(Opc, ArrayRef<DstOps>, ArrayRef<SrcOps>)
where DstOps and SrcOps are typed unions that know how to add itself to
MachineInstrBuilder.
After this patch, most invocations would look like
B.buildInstr(Opc, {s32, DstReg}, {SrcRegs..., SrcMIBs..});
Now all the other calls (such as buildAdd, buildSub etc) forward to
buildInstr. It also makes it possible to build instructions with
multiple defs.
Additionally in a subsequent patch, we should make it possible to add
flags directly while building instructions.
Additionally, the main buildInstr method is now virtual and other
builders now only have to override buildInstr (for say constant
folding/cseing) is straightforward.
Also attached here (https://reviews.llvm.org/F7675680) is a clang-tidy
patch that should upgrade the API calls if necessary.
llvm-svn: 348815
2018-12-11 08:48:50 +08:00
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_XOR, {Ty}, {SrcReg, MIBCstNeg1});
|
2018-08-22 01:30:31 +08:00
|
|
|
auto MIBTmp = MIRBuilder.buildInstr(
|
[GISel]: Refactor MachineIRBuilder to allow passing additional parameters to build Instrs
https://reviews.llvm.org/D55294
Previously MachineIRBuilder::buildInstr used to accept variadic
arguments for sources (which were either unsigned or
MachineInstrBuilder). While this worked well in common cases, it doesn't
allow us to build instructions that have multiple destinations.
Additionally passing in other optional parameters in the end (such as
flags) is not possible trivially. Also a trivial call such as
B.buildInstr(Opc, Reg1, Reg2, Reg3)
can be interpreted differently based on the opcode (2defs + 1 src for
unmerge vs 1 def + 2srcs).
This patch refactors the buildInstr to
buildInstr(Opc, ArrayRef<DstOps>, ArrayRef<SrcOps>)
where DstOps and SrcOps are typed unions that know how to add itself to
MachineInstrBuilder.
After this patch, most invocations would look like
B.buildInstr(Opc, {s32, DstReg}, {SrcRegs..., SrcMIBs..});
Now all the other calls (such as buildAdd, buildSub etc) forward to
buildInstr. It also makes it possible to build instructions with
multiple defs.
Additionally in a subsequent patch, we should make it possible to add
flags directly while building instructions.
Additionally, the main buildInstr method is now virtual and other
builders now only have to override buildInstr (for say constant
folding/cseing) is straightforward.
Also attached here (https://reviews.llvm.org/F7675680) is a clang-tidy
patch that should upgrade the API calls if necessary.
llvm-svn: 348815
2018-12-11 08:48:50 +08:00
|
|
|
TargetOpcode::G_AND, {Ty},
|
|
|
|
{MIBNot, MIRBuilder.buildInstr(TargetOpcode::G_ADD, {Ty},
|
|
|
|
{SrcReg, MIBCstNeg1})});
|
2018-11-26 19:07:02 +08:00
|
|
|
if (!isSupported({TargetOpcode::G_CTPOP, {Ty}}) &&
|
|
|
|
isSupported({TargetOpcode::G_CTLZ, {Ty}})) {
|
2018-08-22 01:30:31 +08:00
|
|
|
auto MIBCstLen = MIRBuilder.buildConstant(Ty, Len);
|
|
|
|
MIRBuilder.buildInstr(
|
[GISel]: Refactor MachineIRBuilder to allow passing additional parameters to build Instrs
https://reviews.llvm.org/D55294
Previously MachineIRBuilder::buildInstr used to accept variadic
arguments for sources (which were either unsigned or
MachineInstrBuilder). While this worked well in common cases, it doesn't
allow us to build instructions that have multiple destinations.
Additionally passing in other optional parameters in the end (such as
flags) is not possible trivially. Also a trivial call such as
B.buildInstr(Opc, Reg1, Reg2, Reg3)
can be interpreted differently based on the opcode (2defs + 1 src for
unmerge vs 1 def + 2srcs).
This patch refactors the buildInstr to
buildInstr(Opc, ArrayRef<DstOps>, ArrayRef<SrcOps>)
where DstOps and SrcOps are typed unions that know how to add itself to
MachineInstrBuilder.
After this patch, most invocations would look like
B.buildInstr(Opc, {s32, DstReg}, {SrcRegs..., SrcMIBs..});
Now all the other calls (such as buildAdd, buildSub etc) forward to
buildInstr. It also makes it possible to build instructions with
multiple defs.
Additionally in a subsequent patch, we should make it possible to add
flags directly while building instructions.
Additionally, the main buildInstr method is now virtual and other
builders now only have to override buildInstr (for say constant
folding/cseing) is straightforward.
Also attached here (https://reviews.llvm.org/F7675680) is a clang-tidy
patch that should upgrade the API calls if necessary.
llvm-svn: 348815
2018-12-11 08:48:50 +08:00
|
|
|
TargetOpcode::G_SUB, {MI.getOperand(0).getReg()},
|
|
|
|
{MIBCstLen,
|
|
|
|
MIRBuilder.buildInstr(TargetOpcode::G_CTLZ, {Ty}, {MIBTmp})});
|
2018-08-22 01:30:31 +08:00
|
|
|
MI.eraseFromParent();
|
|
|
|
return Legalized;
|
|
|
|
}
|
|
|
|
MI.setDesc(TII.get(TargetOpcode::G_CTPOP));
|
|
|
|
MI.getOperand(1).setReg(MIBTmp->getOperand(0).getReg());
|
|
|
|
return Legalized;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|