summaryrefslogtreecommitdiff
path: root/llvm/lib/Target/Mips/MipsLegalizerInfo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/Mips/MipsLegalizerInfo.cpp')
-rw-r--r--llvm/lib/Target/Mips/MipsLegalizerInfo.cpp221
1 files changed, 183 insertions, 38 deletions
diff --git a/llvm/lib/Target/Mips/MipsLegalizerInfo.cpp b/llvm/lib/Target/Mips/MipsLegalizerInfo.cpp
index 9645aa24dc058..b489c81377694 100644
--- a/llvm/lib/Target/Mips/MipsLegalizerInfo.cpp
+++ b/llvm/lib/Target/Mips/MipsLegalizerInfo.cpp
@@ -21,22 +21,38 @@ struct TypesAndMemOps {
LLT ValTy;
LLT PtrTy;
unsigned MemSize;
- bool MustBeNaturallyAligned;
+ bool SystemSupportsUnalignedAccess;
};
+// Assumes power of 2 memory size. Subtargets that have only naturally-aligned
+// memory access need to perform additional legalization here.
+static bool isUnalignedMemmoryAccess(uint64_t MemSize, uint64_t AlignInBits) {
+ assert(isPowerOf2_64(MemSize) && "Expected power of 2 memory size");
+ assert(isPowerOf2_64(AlignInBits) && "Expected power of 2 align");
+ if (MemSize > AlignInBits)
+ return true;
+ return false;
+}
+
static bool
CheckTy0Ty1MemSizeAlign(const LegalityQuery &Query,
std::initializer_list<TypesAndMemOps> SupportedValues) {
+ unsigned QueryMemSize = Query.MMODescrs[0].SizeInBits;
+
+ // Non power of two memory access is never legal.
+ if (!isPowerOf2_64(QueryMemSize))
+ return false;
+
for (auto &Val : SupportedValues) {
if (Val.ValTy != Query.Types[0])
continue;
if (Val.PtrTy != Query.Types[1])
continue;
- if (Val.MemSize != Query.MMODescrs[0].SizeInBits)
- continue;
- if (Val.MustBeNaturallyAligned &&
- Query.MMODescrs[0].SizeInBits % Query.MMODescrs[0].AlignInBits != 0)
+ if (Val.MemSize != QueryMemSize)
continue;
+ if (!Val.SystemSupportsUnalignedAccess &&
+ isUnalignedMemmoryAccess(QueryMemSize, Query.MMODescrs[0].AlignInBits))
+ return false;
return true;
}
return false;
@@ -79,20 +95,55 @@ MipsLegalizerInfo::MipsLegalizerInfo(const MipsSubtarget &ST) {
.legalFor({s32})
.maxScalar(0, s32);
+ // MIPS32r6 does not have alignment restrictions for memory access.
+ // For MIPS32r5 and older memory access must be naturally-aligned i.e. aligned
+ // to at least a multiple of its own size. There is however a two instruction
+ // combination that performs 4 byte unaligned access (lwr/lwl and swl/swr)
+ // therefore 4 byte load and store are legal and will use NoAlignRequirements.
+ bool NoAlignRequirements = true;
+
getActionDefinitionsBuilder({G_LOAD, G_STORE})
.legalIf([=, &ST](const LegalityQuery &Query) {
- if (CheckTy0Ty1MemSizeAlign(Query, {{s32, p0, 8, ST.hasMips32r6()},
- {s32, p0, 16, ST.hasMips32r6()},
- {s32, p0, 32, ST.hasMips32r6()},
- {p0, p0, 32, ST.hasMips32r6()},
- {s64, p0, 64, ST.hasMips32r6()}}))
+ if (CheckTy0Ty1MemSizeAlign(
+ Query, {{s32, p0, 8, NoAlignRequirements},
+ {s32, p0, 16, ST.systemSupportsUnalignedAccess()},
+ {s32, p0, 32, NoAlignRequirements},
+ {p0, p0, 32, NoAlignRequirements},
+ {s64, p0, 64, ST.systemSupportsUnalignedAccess()}}))
+ return true;
+ if (ST.hasMSA() && CheckTy0Ty1MemSizeAlign(
+ Query, {{v16s8, p0, 128, NoAlignRequirements},
+ {v8s16, p0, 128, NoAlignRequirements},
+ {v4s32, p0, 128, NoAlignRequirements},
+ {v2s64, p0, 128, NoAlignRequirements}}))
+ return true;
+ return false;
+ })
+ // Custom lower scalar memory access, up to 8 bytes, for:
+ // - non-power-of-2 MemSizes
+ // - unaligned 2 or 8 byte MemSizes for MIPS32r5 and older
+ .customIf([=, &ST](const LegalityQuery &Query) {
+ if (!Query.Types[0].isScalar() || Query.Types[1] != p0 ||
+ Query.Types[0] == s1)
+ return false;
+
+ unsigned Size = Query.Types[0].getSizeInBits();
+ unsigned QueryMemSize = Query.MMODescrs[0].SizeInBits;
+ assert(QueryMemSize <= Size && "Scalar can't hold MemSize");
+
+ if (Size > 64 || QueryMemSize > 64)
+ return false;
+
+ if (!isPowerOf2_64(Query.MMODescrs[0].SizeInBits))
return true;
- if (ST.hasMSA() &&
- CheckTy0Ty1MemSizeAlign(Query, {{v16s8, p0, 128, false},
- {v8s16, p0, 128, false},
- {v4s32, p0, 128, false},
- {v2s64, p0, 128, false}}))
+
+ if (!ST.systemSupportsUnalignedAccess() &&
+ isUnalignedMemmoryAccess(QueryMemSize,
+ Query.MMODescrs[0].AlignInBits)) {
+ assert(QueryMemSize != 32 && "4 byte load and store are legal");
return true;
+ }
+
return false;
})
.minScalar(0, s32);
@@ -111,7 +162,7 @@ MipsLegalizerInfo::MipsLegalizerInfo(const MipsSubtarget &ST) {
{s32, p0, 16, 8}})
.clampScalar(0, s32, s32);
- getActionDefinitionsBuilder({G_ZEXT, G_SEXT})
+ getActionDefinitionsBuilder({G_ZEXT, G_SEXT, G_ANYEXT})
.legalIf([](const LegalityQuery &Query) { return false; })
.maxScalar(0, s32);
@@ -202,6 +253,25 @@ MipsLegalizerInfo::MipsLegalizerInfo(const MipsSubtarget &ST) {
.lowerFor({s32})
.maxScalar(0, s32);
+ getActionDefinitionsBuilder(G_CTLZ)
+ .legalFor({{s32, s32}})
+ .maxScalar(0, s32)
+ .maxScalar(1, s32);
+ getActionDefinitionsBuilder(G_CTLZ_ZERO_UNDEF)
+ .lowerFor({{s32, s32}});
+
+ getActionDefinitionsBuilder(G_CTTZ)
+ .lowerFor({{s32, s32}})
+ .maxScalar(0, s32)
+ .maxScalar(1, s32);
+ getActionDefinitionsBuilder(G_CTTZ_ZERO_UNDEF)
+ .lowerFor({{s32, s32}, {s64, s64}});
+
+ getActionDefinitionsBuilder(G_CTPOP)
+ .lowerFor({{s32, s32}})
+ .clampScalar(0, s32, s32)
+ .clampScalar(1, s32, s32);
+
// FP instructions
getActionDefinitionsBuilder(G_FCONSTANT)
.legalFor({s32, s64});
@@ -256,20 +326,98 @@ MipsLegalizerInfo::MipsLegalizerInfo(const MipsSubtarget &ST) {
verify(*ST.getInstrInfo());
}
-bool MipsLegalizerInfo::legalizeCustom(MachineInstr &MI,
- MachineRegisterInfo &MRI,
- MachineIRBuilder &MIRBuilder,
- GISelChangeObserver &Observer) const {
-
+bool MipsLegalizerInfo::legalizeCustom(LegalizerHelper &Helper,
+ MachineInstr &MI) const {
using namespace TargetOpcode;
- MIRBuilder.setInstr(MI);
- const MipsSubtarget &STI =
- static_cast<const MipsSubtarget &>(MIRBuilder.getMF().getSubtarget());
+ MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
+ MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
+
const LLT s32 = LLT::scalar(32);
const LLT s64 = LLT::scalar(64);
switch (MI.getOpcode()) {
+ case G_LOAD:
+ case G_STORE: {
+ unsigned MemSize = (**MI.memoperands_begin()).getSize();
+ Register Val = MI.getOperand(0).getReg();
+ unsigned Size = MRI.getType(Val).getSizeInBits();
+
+ MachineMemOperand *MMOBase = *MI.memoperands_begin();
+
+ assert(MemSize <= 8 && "MemSize is too large");
+ assert(Size <= 64 && "Scalar size is too large");
+
+ // Split MemSize into two, P2HalfMemSize is largest power of two smaller
+ // then MemSize. e.g. 8 = 4 + 4 , 6 = 4 + 2, 3 = 2 + 1.
+ unsigned P2HalfMemSize, RemMemSize;
+ if (isPowerOf2_64(MemSize)) {
+ P2HalfMemSize = RemMemSize = MemSize / 2;
+ } else {
+ P2HalfMemSize = 1 << Log2_32(MemSize);
+ RemMemSize = MemSize - P2HalfMemSize;
+ }
+
+ Register BaseAddr = MI.getOperand(1).getReg();
+ LLT PtrTy = MRI.getType(BaseAddr);
+ MachineFunction &MF = MIRBuilder.getMF();
+
+ auto P2HalfMemOp = MF.getMachineMemOperand(MMOBase, 0, P2HalfMemSize);
+ auto RemMemOp = MF.getMachineMemOperand(MMOBase, P2HalfMemSize, RemMemSize);
+
+ if (MI.getOpcode() == G_STORE) {
+ // Widen Val to s32 or s64 in order to create legal G_LSHR or G_UNMERGE.
+ if (Size < 32)
+ Val = MIRBuilder.buildAnyExt(s32, Val).getReg(0);
+ if (Size > 32 && Size < 64)
+ Val = MIRBuilder.buildAnyExt(s64, Val).getReg(0);
+
+ auto C_P2HalfMemSize = MIRBuilder.buildConstant(s32, P2HalfMemSize);
+ auto Addr = MIRBuilder.buildPtrAdd(PtrTy, BaseAddr, C_P2HalfMemSize);
+
+ if (MI.getOpcode() == G_STORE && MemSize <= 4) {
+ MIRBuilder.buildStore(Val, BaseAddr, *P2HalfMemOp);
+ auto C_P2Half_InBits = MIRBuilder.buildConstant(s32, P2HalfMemSize * 8);
+ auto Shift = MIRBuilder.buildLShr(s32, Val, C_P2Half_InBits);
+ MIRBuilder.buildStore(Shift, Addr, *RemMemOp);
+ } else {
+ auto Unmerge = MIRBuilder.buildUnmerge(s32, Val);
+ MIRBuilder.buildStore(Unmerge.getReg(0), BaseAddr, *P2HalfMemOp);
+ MIRBuilder.buildStore(Unmerge.getReg(1), Addr, *RemMemOp);
+ }
+ }
+
+ if (MI.getOpcode() == G_LOAD) {
+
+ if (MemSize <= 4) {
+ // This is anyextending load, use 4 byte lwr/lwl.
+ auto *Load4MMO = MF.getMachineMemOperand(MMOBase, 0, 4);
+
+ if (Size == 32)
+ MIRBuilder.buildLoad(Val, BaseAddr, *Load4MMO);
+ else {
+ auto Load = MIRBuilder.buildLoad(s32, BaseAddr, *Load4MMO);
+ MIRBuilder.buildTrunc(Val, Load.getReg(0));
+ }
+
+ } else {
+ auto C_P2HalfMemSize = MIRBuilder.buildConstant(s32, P2HalfMemSize);
+ auto Addr = MIRBuilder.buildPtrAdd(PtrTy, BaseAddr, C_P2HalfMemSize);
+
+ auto Load_P2Half = MIRBuilder.buildLoad(s32, BaseAddr, *P2HalfMemOp);
+ auto Load_Rem = MIRBuilder.buildLoad(s32, Addr, *RemMemOp);
+
+ if (Size == 64)
+ MIRBuilder.buildMerge(Val, {Load_P2Half, Load_Rem});
+ else {
+ auto Merge = MIRBuilder.buildMerge(s64, {Load_P2Half, Load_Rem});
+ MIRBuilder.buildTrunc(Val, Merge);
+ }
+ }
+ }
+ MI.eraseFromParent();
+ break;
+ }
case G_UITOFP: {
Register Dst = MI.getOperand(0).getReg();
Register Src = MI.getOperand(1).getReg();
@@ -288,11 +436,8 @@ bool MipsLegalizerInfo::legalizeCustom(MachineInstr &MI,
// Next, subtract 2^52 * 0x1.0000000000000 i.e. 0x10000000000000.0 from it.
// Done. Trunc double to float if needed.
- MachineInstrBuilder Bitcast = MIRBuilder.buildInstr(
- STI.isFP64bit() ? Mips::BuildPairF64_64 : Mips::BuildPairF64, {s64},
- {Src, MIRBuilder.buildConstant(s32, UINT32_C(0x43300000))});
- Bitcast.constrainAllUses(MIRBuilder.getTII(), *STI.getRegisterInfo(),
- *STI.getRegBankInfo());
+ auto C_HiMask = MIRBuilder.buildConstant(s32, UINT32_C(0x43300000));
+ auto Bitcast = MIRBuilder.buildMerge(s64, {Src, C_HiMask.getReg(0)});
MachineInstrBuilder TwoP52FP = MIRBuilder.buildFConstant(
s64, BitsToDouble(UINT64_C(0x4330000000000000)));
@@ -352,15 +497,15 @@ static bool MSA2OpIntrinsicToGeneric(MachineInstr &MI, unsigned Opcode,
return true;
}
-bool MipsLegalizerInfo::legalizeIntrinsic(MachineInstr &MI,
- MachineRegisterInfo &MRI,
- MachineIRBuilder &MIRBuilder) const {
+bool MipsLegalizerInfo::legalizeIntrinsic(LegalizerHelper &Helper,
+ MachineInstr &MI) const {
+ MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
+ MachineRegisterInfo &MRI = *MIRBuilder.getMRI();
const MipsSubtarget &ST =
static_cast<const MipsSubtarget &>(MI.getMF()->getSubtarget());
const MipsInstrInfo &TII = *ST.getInstrInfo();
const MipsRegisterInfo &TRI = *ST.getRegisterInfo();
const RegisterBankInfo &RBI = *ST.getRegBankInfo();
- MIRBuilder.setInstr(MI);
switch (MI.getIntrinsicID()) {
case Intrinsic::memcpy:
@@ -377,14 +522,14 @@ bool MipsLegalizerInfo::legalizeIntrinsic(MachineInstr &MI,
return constrainSelectedInstRegOperands(*Trap, TII, TRI, RBI);
}
case Intrinsic::vacopy: {
- Register Tmp = MRI.createGenericVirtualRegister(LLT::pointer(0, 32));
MachinePointerInfo MPO;
- MIRBuilder.buildLoad(Tmp, MI.getOperand(2),
- *MI.getMF()->getMachineMemOperand(
- MPO, MachineMemOperand::MOLoad, 4, 4));
+ auto Tmp =
+ MIRBuilder.buildLoad(LLT::pointer(0, 32), MI.getOperand(2),
+ *MI.getMF()->getMachineMemOperand(
+ MPO, MachineMemOperand::MOLoad, 4, Align(4)));
MIRBuilder.buildStore(Tmp, MI.getOperand(1),
*MI.getMF()->getMachineMemOperand(
- MPO, MachineMemOperand::MOStore, 4, 4));
+ MPO, MachineMemOperand::MOStore, 4, Align(4)));
MI.eraseFromParent();
return true;
}