diff options
Diffstat (limited to 'llvm/lib/Target/Mips/MipsLegalizerInfo.cpp')
-rw-r--r-- | llvm/lib/Target/Mips/MipsLegalizerInfo.cpp | 221 |
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; } |