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

[GlobalISel] Make multi-step legalization work.

In r301116, a custom lowering needed to be introduced to be able to
legalize 8 and 16-bit divisions on ARM targets without a division
instruction, since 2-step legalization (WidenScalar from 8 bit to 32
bit, then Libcall the 32-bit division) doesn't work.

This fixes this and makes this kind of multi-step legalization, where
first the size of the type needs to be changed and then some action is
needed that doesn't require changing the size of the type,
straighforward to specify.

Differential Revision: https://reviews.llvm.org/D32529

llvm-svn: 306806
This commit is contained in:
Kristof Beyls 2017-06-30 08:26:20 +00:00
parent fbea2e7ae6
commit fe183150a4
4 changed files with 52 additions and 54 deletions

View File

@ -107,6 +107,19 @@ public:
/// before any query is made or incorrect results may be returned. /// before any query is made or incorrect results may be returned.
void computeTables(); void computeTables();
static bool needsLegalizingToDifferentSize(const LegalizeAction Action) {
switch (Action) {
case NarrowScalar:
case WidenScalar:
case FewerElements:
case MoreElements:
case Unsupported:
return true;
default:
return false;
}
}
/// More friendly way to set an action for common types that have an LLT /// More friendly way to set an action for common types that have an LLT
/// representation. /// representation.
void setAction(const InstrAspect &Aspect, LegalizeAction Action) { void setAction(const InstrAspect &Aspect, LegalizeAction Action) {
@ -147,8 +160,8 @@ public:
/// Iterate the given function (typically something like doubling the width) /// Iterate the given function (typically something like doubling the width)
/// on Ty until we find a legal type for this operation. /// on Ty until we find a legal type for this operation.
Optional<LLT> findLegalType(const InstrAspect &Aspect, Optional<LLT> findLegalizableSize(const InstrAspect &Aspect,
function_ref<LLT(LLT)> NextType) const { function_ref<LLT(LLT)> NextType) const {
LegalizeAction Action; LegalizeAction Action;
const TypeMap &Map = Actions[Aspect.Opcode - FirstOp][Aspect.Idx]; const TypeMap &Map = Actions[Aspect.Opcode - FirstOp][Aspect.Idx];
LLT Ty = Aspect.Type; LLT Ty = Aspect.Type;
@ -160,10 +173,9 @@ public:
if (DefaultIt == DefaultActions.end()) if (DefaultIt == DefaultActions.end())
return None; return None;
Action = DefaultIt->second; Action = DefaultIt->second;
} } else
else
Action = ActionIt->second; Action = ActionIt->second;
} while(Action != Legal); } while (needsLegalizingToDifferentSize(Action));
return Ty; return Ty;
} }

View File

@ -178,19 +178,23 @@ Optional<LLT> LegalizerInfo::findLegalType(const InstrAspect &Aspect,
case Libcall: case Libcall:
case Custom: case Custom:
return Aspect.Type; return Aspect.Type;
case NarrowScalar: case NarrowScalar: {
return findLegalType(Aspect, return findLegalizableSize(
[](LLT Ty) -> LLT { return Ty.halfScalarSize(); }); Aspect, [&](LLT Ty) -> LLT { return Ty.halfScalarSize(); });
case WidenScalar: }
return findLegalType(Aspect, [](LLT Ty) -> LLT { case WidenScalar: {
return findLegalizableSize(Aspect, [&](LLT Ty) -> LLT {
return Ty.getSizeInBits() < 8 ? LLT::scalar(8) : Ty.doubleScalarSize(); return Ty.getSizeInBits() < 8 ? LLT::scalar(8) : Ty.doubleScalarSize();
}); });
case FewerElements: }
return findLegalType(Aspect, case FewerElements: {
[](LLT Ty) -> LLT { return Ty.halfElements(); }); return findLegalizableSize(
case MoreElements: Aspect, [&](LLT Ty) -> LLT { return Ty.halfElements(); });
return findLegalType(Aspect, }
[](LLT Ty) -> LLT { return Ty.doubleElements(); }); case MoreElements: {
return findLegalizableSize(
Aspect, [&](LLT Ty) -> LLT { return Ty.doubleElements(); });
}
} }
} }

View File

@ -55,10 +55,7 @@ ARMLegalizerInfo::ARMLegalizerInfo(const ARMSubtarget &ST) {
for (unsigned Op : {G_SDIV, G_UDIV}) { for (unsigned Op : {G_SDIV, G_UDIV}) {
for (auto Ty : {s8, s16}) for (auto Ty : {s8, s16})
// FIXME: We need WidenScalar here, but in the case of targets with setAction({Op, Ty}, WidenScalar);
// software division we'll also need Libcall afterwards. Treat as Custom
// until we have better support for chaining legalization actions.
setAction({Op, Ty}, Custom);
if (ST.hasDivideInARMMode()) if (ST.hasDivideInARMMode())
setAction({Op, s32}, Legal); setAction({Op, s32}, Legal);
else else
@ -122,40 +119,6 @@ bool ARMLegalizerInfo::legalizeCustom(MachineInstr &MI,
switch (MI.getOpcode()) { switch (MI.getOpcode()) {
default: default:
return false; return false;
case G_SDIV:
case G_UDIV: {
LLT Ty = MRI.getType(MI.getOperand(0).getReg());
if (Ty != LLT::scalar(16) && Ty != LLT::scalar(8))
return false;
// We need to widen to 32 bits and then maybe, if the target requires,
// transform into a libcall.
LegalizerHelper Helper(MIRBuilder.getMF());
MachineInstr *NewMI = nullptr;
Helper.MIRBuilder.recordInsertions([&](MachineInstr *MI) {
// Store the new, 32-bit div instruction.
if (MI->getOpcode() == G_SDIV || MI->getOpcode() == G_UDIV)
NewMI = MI;
});
auto Result = Helper.widenScalar(MI, 0, LLT::scalar(32));
Helper.MIRBuilder.stopRecordingInsertions();
if (Result == LegalizerHelper::UnableToLegalize) {
return false;
}
assert(NewMI && "Couldn't find widened instruction");
assert((NewMI->getOpcode() == G_SDIV || NewMI->getOpcode() == G_UDIV) &&
"Unexpected widened instruction");
assert(MRI.getType(NewMI->getOperand(0).getReg()).getSizeInBits() == 32 &&
"Unexpected type for the widened instruction");
Result = Helper.legalizeInstrStep(*NewMI);
if (Result == LegalizerHelper::UnableToLegalize) {
return false;
}
return true;
}
case G_SREM: case G_SREM:
case G_UREM: { case G_UREM: {
unsigned OriginalResult = MI.getOperand(0).getReg(); unsigned OriginalResult = MI.getOperand(0).getReg();

View File

@ -117,4 +117,23 @@ TEST(LegalizerInfoTest, MultipleTypes) {
ASSERT_EQ(L.getAction({G_PTRTOINT, 1, p0}), ASSERT_EQ(L.getAction({G_PTRTOINT, 1, p0}),
std::make_pair(LegalizerInfo::Legal, p0)); std::make_pair(LegalizerInfo::Legal, p0));
} }
TEST(LegalizerInfoTest, MultipleSteps) {
using namespace TargetOpcode;
LegalizerInfo L;
LLT s16 = LLT::scalar(16);
LLT s32 = LLT::scalar(32);
LLT s64 = LLT::scalar(64);
L.setAction({G_UREM, 0, s16}, LegalizerInfo::WidenScalar);
L.setAction({G_UREM, 0, s32}, LegalizerInfo::Lower);
L.setAction({G_UREM, 0, s64}, LegalizerInfo::Lower);
L.computeTables();
ASSERT_EQ(L.getAction({G_UREM, LLT::scalar(16)}),
std::make_pair(LegalizerInfo::WidenScalar, LLT::scalar(32)));
ASSERT_EQ(L.getAction({G_UREM, LLT::scalar(32)}),
std::make_pair(LegalizerInfo::Lower, LLT::scalar(32)));
}
} }