Index: llvm/lib/Target/Mips/MipsInstructionSelector.cpp =================================================================== --- llvm/lib/Target/Mips/MipsInstructionSelector.cpp +++ llvm/lib/Target/Mips/MipsInstructionSelector.cpp @@ -49,6 +49,12 @@ getRegClassForTypeOnBank(Register Reg, MachineRegisterInfo &MRI) const; unsigned selectLoadStoreOpCode(MachineInstr &I, MachineRegisterInfo &MRI) const; + bool buildUnalignedStore(MachineInstr &I, unsigned Opc, + MachineOperand &BaseAddr, unsigned Offset, + MachineMemOperand *MMO) const; + bool buildUnalignedLoad(MachineInstr &I, unsigned Opc, Register Dest, + MachineOperand &BaseAddr, unsigned Offset, + Register TiedDest, MachineMemOperand *MMO) const; const MipsTargetMachine &TM; const MipsSubtarget &STI; @@ -248,6 +254,35 @@ return Opc; } +bool MipsInstructionSelector::buildUnalignedStore( + MachineInstr &I, unsigned Opc, MachineOperand &BaseAddr, unsigned Offset, + MachineMemOperand *MMO) const { + MachineInstr *NewInst = + BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opc)) + .add(I.getOperand(0)) + .add(BaseAddr) + .addImm(Offset) + .addMemOperand(MMO); + if (!constrainSelectedInstRegOperands(*NewInst, TII, TRI, RBI)) + return false; + return true; +} + +bool MipsInstructionSelector::buildUnalignedLoad( + MachineInstr &I, unsigned Opc, Register Dest, MachineOperand &BaseAddr, + unsigned Offset, Register TiedDest, MachineMemOperand *MMO) const { + MachineInstr *NewInst = + BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(Opc)) + .addDef(Dest) + .add(BaseAddr) + .addImm(Offset) + .addUse(TiedDest) + .addMemOperand(*I.memoperands_begin()); + if (!constrainSelectedInstRegOperands(*NewInst, TII, TRI, RBI)) + return false; + return true; +} + bool MipsInstructionSelector::select(MachineInstr &I) { MachineBasicBlock &MBB = *I.getParent(); @@ -404,10 +439,7 @@ case G_LOAD: case G_ZEXTLOAD: case G_SEXTLOAD: { - const unsigned NewOpc = selectLoadStoreOpCode(I, MRI); - if (NewOpc == I.getOpcode()) - return false; - + auto MMO = *I.memoperands_begin(); MachineOperand BaseAddr = I.getOperand(1); int64_t SignedOffset = 0; // Try to fold load/store + G_PTR_ADD + G_CONSTANT @@ -429,11 +461,48 @@ } } + // Unaligned memory access + if (MMO->getSize() > MMO->getAlignment() && + !STI.systemSupportsUnalignedAccess()) { + if (MMO->getSize() != 4) + return false; + + if (I.getOpcode() == G_STORE) { + if (!buildUnalignedStore(I, Mips::SWL, BaseAddr, SignedOffset + 3, MMO)) + return false; + if (!buildUnalignedStore(I, Mips::SWR, BaseAddr, SignedOffset, MMO)) + return false; + I.eraseFromParent(); + return true; + } + + if (I.getOpcode() == G_LOAD) { + Register ImplDef = MRI.createVirtualRegister(&Mips::GPR32RegClass); + BuildMI(MBB, I, I.getDebugLoc(), TII.get(Mips::IMPLICIT_DEF)) + .addDef(ImplDef); + Register Tmp = MRI.createVirtualRegister(&Mips::GPR32RegClass); + if (!buildUnalignedLoad(I, Mips::LWL, Tmp, BaseAddr, SignedOffset + 3, + ImplDef, MMO)) + return false; + if (!buildUnalignedLoad(I, Mips::LWR, I.getOperand(0).getReg(), + BaseAddr, SignedOffset, Tmp, MMO)) + return false; + I.eraseFromParent(); + return true; + } + + return false; + } + + const unsigned NewOpc = selectLoadStoreOpCode(I, MRI); + if (NewOpc == I.getOpcode()) + return false; + MI = BuildMI(MBB, I, I.getDebugLoc(), TII.get(NewOpc)) .add(I.getOperand(0)) .add(BaseAddr) .addImm(SignedOffset) - .addMemOperand(*I.memoperands_begin()); + .addMemOperand(MMO); break; } case G_UDIV: Index: llvm/lib/Target/Mips/MipsLegalizerInfo.cpp =================================================================== --- llvm/lib/Target/Mips/MipsLegalizerInfo.cpp +++ llvm/lib/Target/Mips/MipsLegalizerInfo.cpp @@ -21,22 +21,38 @@ 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. +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 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,19 +95,27 @@ .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, false}, - {v8s16, p0, 128, false}, - {v4s32, p0, 128, false}, - {v2s64, p0, 128, false}})) + 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; }) Index: llvm/lib/Target/Mips/MipsRegisterBankInfo.cpp =================================================================== --- llvm/lib/Target/Mips/MipsRegisterBankInfo.cpp +++ llvm/lib/Target/Mips/MipsRegisterBankInfo.cpp @@ -150,6 +150,19 @@ } } +static bool isGprbTwoInstrUnalignedLoadOrStore(const MachineInstr *MI) { + if (MI->getOpcode() == TargetOpcode::G_LOAD || + MI->getOpcode() == TargetOpcode::G_STORE) { + auto MMO = *MI->memoperands_begin(); + const MipsSubtarget &STI = + static_cast(MI->getMF()->getSubtarget()); + if (MMO->getSize() == 4 && (!STI.systemSupportsUnalignedAccess() && + MMO->getSize() > MMO->getAlignment())) + return true; + } + return false; +} + static bool isAmbiguous(unsigned Opc) { switch (Opc) { case TargetOpcode::G_LOAD: @@ -261,6 +274,11 @@ startVisit(MI); AmbiguousRegDefUseContainer DefUseContainer(MI); + if (isGprbTwoInstrUnalignedLoadOrStore(MI)) { + setTypes(MI, Integer); + return true; + } + if (AmbiguousTy == InstType::Ambiguous && (MI->getOpcode() == TargetOpcode::G_MERGE_VALUES || MI->getOpcode() == TargetOpcode::G_UNMERGE_VALUES)) Index: llvm/test/CodeGen/Mips/GlobalISel/llvm-ir/load_4_unaligned.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/Mips/GlobalISel/llvm-ir/load_4_unaligned.ll @@ -0,0 +1,182 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -O0 -mtriple=mipsel-linux-gnu -global-isel -verify-machineinstrs %s -o -| FileCheck %s -check-prefixes=MIPS32 +; RUN: llc -O0 -mtriple=mipsel-linux-gnu -global-isel -mcpu=mips32r6 -verify-machineinstrs %s -o -| FileCheck %s -check-prefixes=MIPS32R6 + +@float_align1 = common global float 0.000000e+00, align 1 +@float_align2 = common global float 0.000000e+00, align 2 +@float_align4 = common global float 0.000000e+00, align 4 +@float_align8 = common global float 0.000000e+00, align 8 +@i32_align1 = common global i32 0, align 1 +@i32_align2 = common global i32 0, align 2 +@i32_align4 = common global i32 0, align 4 +@i32_align8 = common global i32 0, align 8 + +define float @load_float_align1() { +; MIPS32-LABEL: load_float_align1: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: lui $1, %hi(float_align1) +; MIPS32-NEXT: addiu $1, $1, %lo(float_align1) +; MIPS32-NEXT: # implicit-def: $v0 +; MIPS32-NEXT: lwl $2, 3($1) +; MIPS32-NEXT: lwr $2, 0($1) +; MIPS32-NEXT: mtc1 $2, $f0 +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +; +; MIPS32R6-LABEL: load_float_align1: +; MIPS32R6: # %bb.0: # %entry +; MIPS32R6-NEXT: lui $1, %hi(float_align1) +; MIPS32R6-NEXT: addiu $1, $1, %lo(float_align1) +; MIPS32R6-NEXT: lwc1 $f0, 0($1) +; MIPS32R6-NEXT: jrc $ra +entry: + %0 = load float, float* @float_align1, align 1 + ret float %0 +} + +define float @load_float_align2() { +; MIPS32-LABEL: load_float_align2: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: lui $1, %hi(float_align2) +; MIPS32-NEXT: addiu $1, $1, %lo(float_align2) +; MIPS32-NEXT: # implicit-def: $v0 +; MIPS32-NEXT: lwl $2, 3($1) +; MIPS32-NEXT: lwr $2, 0($1) +; MIPS32-NEXT: mtc1 $2, $f0 +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +; +; MIPS32R6-LABEL: load_float_align2: +; MIPS32R6: # %bb.0: # %entry +; MIPS32R6-NEXT: lui $1, %hi(float_align2) +; MIPS32R6-NEXT: addiu $1, $1, %lo(float_align2) +; MIPS32R6-NEXT: lwc1 $f0, 0($1) +; MIPS32R6-NEXT: jrc $ra +entry: + %0 = load float, float* @float_align2, align 2 + ret float %0 +} + +define float @load_float_align4() { +; MIPS32-LABEL: load_float_align4: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: lui $1, %hi(float_align4) +; MIPS32-NEXT: addiu $1, $1, %lo(float_align4) +; MIPS32-NEXT: lwc1 $f0, 0($1) +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +; +; MIPS32R6-LABEL: load_float_align4: +; MIPS32R6: # %bb.0: # %entry +; MIPS32R6-NEXT: lui $1, %hi(float_align4) +; MIPS32R6-NEXT: addiu $1, $1, %lo(float_align4) +; MIPS32R6-NEXT: lwc1 $f0, 0($1) +; MIPS32R6-NEXT: jrc $ra +entry: + %0 = load float, float* @float_align4, align 4 + ret float %0 +} + +define float @load_float_align8() { +; MIPS32-LABEL: load_float_align8: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: lui $1, %hi(float_align8) +; MIPS32-NEXT: addiu $1, $1, %lo(float_align8) +; MIPS32-NEXT: lwc1 $f0, 0($1) +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +; +; MIPS32R6-LABEL: load_float_align8: +; MIPS32R6: # %bb.0: # %entry +; MIPS32R6-NEXT: lui $1, %hi(float_align8) +; MIPS32R6-NEXT: addiu $1, $1, %lo(float_align8) +; MIPS32R6-NEXT: lwc1 $f0, 0($1) +; MIPS32R6-NEXT: jrc $ra +entry: + %0 = load float, float* @float_align8, align 8 + ret float %0 +} + +define i32 @load_i32_align1() { +; MIPS32-LABEL: load_i32_align1: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: lui $1, %hi(i32_align1) +; MIPS32-NEXT: addiu $1, $1, %lo(i32_align1) +; MIPS32-NEXT: # implicit-def: $v0 +; MIPS32-NEXT: lwl $2, 3($1) +; MIPS32-NEXT: lwr $2, 0($1) +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +; +; MIPS32R6-LABEL: load_i32_align1: +; MIPS32R6: # %bb.0: # %entry +; MIPS32R6-NEXT: lui $1, %hi(i32_align1) +; MIPS32R6-NEXT: addiu $1, $1, %lo(i32_align1) +; MIPS32R6-NEXT: lw $2, 0($1) +; MIPS32R6-NEXT: jrc $ra +entry: + %0 = load i32, i32* @i32_align1, align 1 + ret i32 %0 +} + +define i32 @load_i32_align2() { +; MIPS32-LABEL: load_i32_align2: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: lui $1, %hi(i32_align2) +; MIPS32-NEXT: addiu $1, $1, %lo(i32_align2) +; MIPS32-NEXT: # implicit-def: $v0 +; MIPS32-NEXT: lwl $2, 3($1) +; MIPS32-NEXT: lwr $2, 0($1) +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +; +; MIPS32R6-LABEL: load_i32_align2: +; MIPS32R6: # %bb.0: # %entry +; MIPS32R6-NEXT: lui $1, %hi(i32_align2) +; MIPS32R6-NEXT: addiu $1, $1, %lo(i32_align2) +; MIPS32R6-NEXT: lw $2, 0($1) +; MIPS32R6-NEXT: jrc $ra +entry: + %0 = load i32, i32* @i32_align2, align 2 + ret i32 %0 +} + +define i32 @load_i32_align4() { +; MIPS32-LABEL: load_i32_align4: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: lui $1, %hi(i32_align4) +; MIPS32-NEXT: addiu $1, $1, %lo(i32_align4) +; MIPS32-NEXT: lw $2, 0($1) +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +; +; MIPS32R6-LABEL: load_i32_align4: +; MIPS32R6: # %bb.0: # %entry +; MIPS32R6-NEXT: lui $1, %hi(i32_align4) +; MIPS32R6-NEXT: addiu $1, $1, %lo(i32_align4) +; MIPS32R6-NEXT: lw $2, 0($1) +; MIPS32R6-NEXT: jrc $ra +entry: + %0 = load i32, i32* @i32_align4, align 4 + ret i32 %0 +} + +define i32 @load_i32_align8() { +; MIPS32-LABEL: load_i32_align8: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: lui $1, %hi(i32_align8) +; MIPS32-NEXT: addiu $1, $1, %lo(i32_align8) +; MIPS32-NEXT: lw $2, 0($1) +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +; +; MIPS32R6-LABEL: load_i32_align8: +; MIPS32R6: # %bb.0: # %entry +; MIPS32R6-NEXT: lui $1, %hi(i32_align8) +; MIPS32R6-NEXT: addiu $1, $1, %lo(i32_align8) +; MIPS32R6-NEXT: lw $2, 0($1) +; MIPS32R6-NEXT: jrc $ra +entry: + %0 = load i32, i32* @i32_align8, align 8 + ret i32 %0 +} Index: llvm/test/CodeGen/Mips/GlobalISel/llvm-ir/phi.ll =================================================================== --- llvm/test/CodeGen/Mips/GlobalISel/llvm-ir/phi.ll +++ llvm/test/CodeGen/Mips/GlobalISel/llvm-ir/phi.ll @@ -249,8 +249,8 @@ ; MIPS32-NEXT: jr $ra ; MIPS32-NEXT: nop entry: - %0 = load i64, i64* %i64_ptr_a, align 4 - %1 = load i64, i64* %i64_ptr_b, align 4 + %0 = load i64, i64* %i64_ptr_a, align 8 + %1 = load i64, i64* %i64_ptr_b, align 8 br i1 %cnd, label %cond.true, label %cond.false cond.true: @@ -261,7 +261,7 @@ cond.end: %cond = phi i64 [ %0, %cond.true ], [ %1, %cond.false ] - store i64 %cond, i64* %i64_ptr_c, align 4 + store i64 %cond, i64* %i64_ptr_c, align 8 ret void } Index: llvm/test/CodeGen/Mips/GlobalISel/llvm-ir/store_4_unaligned.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/Mips/GlobalISel/llvm-ir/store_4_unaligned.ll @@ -0,0 +1,178 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc -O0 -mtriple=mipsel-linux-gnu -global-isel -verify-machineinstrs %s -o -| FileCheck %s -check-prefixes=MIPS32 +; RUN: llc -O0 -mtriple=mipsel-linux-gnu -global-isel -mcpu=mips32r6 -verify-machineinstrs %s -o -| FileCheck %s -check-prefixes=MIPS32R6 + +@float_align1 = common global float 0.000000e+00, align 1 +@float_align2 = common global float 0.000000e+00, align 2 +@float_align4 = common global float 0.000000e+00, align 4 +@float_align8 = common global float 0.000000e+00, align 8 +@i32_align1 = common global i32 0, align 1 +@i32_align2 = common global i32 0, align 2 +@i32_align4 = common global i32 0, align 4 +@i32_align8 = common global i32 0, align 8 + +define void @store_float_align1(float %a) { +; MIPS32-LABEL: store_float_align1: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: lui $1, %hi(float_align1) +; MIPS32-NEXT: addiu $1, $1, %lo(float_align1) +; MIPS32-NEXT: mfc1 $2, $f12 +; MIPS32-NEXT: swl $2, 3($1) +; MIPS32-NEXT: swr $2, 0($1) +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +; +; MIPS32R6-LABEL: store_float_align1: +; MIPS32R6: # %bb.0: # %entry +; MIPS32R6-NEXT: lui $1, %hi(float_align1) +; MIPS32R6-NEXT: addiu $1, $1, %lo(float_align1) +; MIPS32R6-NEXT: swc1 $f12, 0($1) +; MIPS32R6-NEXT: jrc $ra +entry: + store float %a, float* @float_align1, align 1 + ret void +} + +define void @store_float_align2(float %a) { +; MIPS32-LABEL: store_float_align2: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: lui $1, %hi(float_align2) +; MIPS32-NEXT: addiu $1, $1, %lo(float_align2) +; MIPS32-NEXT: mfc1 $2, $f12 +; MIPS32-NEXT: swl $2, 3($1) +; MIPS32-NEXT: swr $2, 0($1) +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +; +; MIPS32R6-LABEL: store_float_align2: +; MIPS32R6: # %bb.0: # %entry +; MIPS32R6-NEXT: lui $1, %hi(float_align2) +; MIPS32R6-NEXT: addiu $1, $1, %lo(float_align2) +; MIPS32R6-NEXT: swc1 $f12, 0($1) +; MIPS32R6-NEXT: jrc $ra +entry: + store float %a, float* @float_align2, align 2 + ret void +} + +define void @store_float_align4(float %a) { +; MIPS32-LABEL: store_float_align4: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: lui $1, %hi(float_align4) +; MIPS32-NEXT: addiu $1, $1, %lo(float_align4) +; MIPS32-NEXT: swc1 $f12, 0($1) +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +; +; MIPS32R6-LABEL: store_float_align4: +; MIPS32R6: # %bb.0: # %entry +; MIPS32R6-NEXT: lui $1, %hi(float_align4) +; MIPS32R6-NEXT: addiu $1, $1, %lo(float_align4) +; MIPS32R6-NEXT: swc1 $f12, 0($1) +; MIPS32R6-NEXT: jrc $ra +entry: + store float %a, float* @float_align4, align 4 + ret void +} + +define void @store_float_align8(float %a) { +; MIPS32-LABEL: store_float_align8: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: lui $1, %hi(float_align8) +; MIPS32-NEXT: addiu $1, $1, %lo(float_align8) +; MIPS32-NEXT: swc1 $f12, 0($1) +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +; +; MIPS32R6-LABEL: store_float_align8: +; MIPS32R6: # %bb.0: # %entry +; MIPS32R6-NEXT: lui $1, %hi(float_align8) +; MIPS32R6-NEXT: addiu $1, $1, %lo(float_align8) +; MIPS32R6-NEXT: swc1 $f12, 0($1) +; MIPS32R6-NEXT: jrc $ra +entry: + store float %a, float* @float_align8, align 8 + ret void +} + +define void @store_i32_align1(i32 signext %a) { +; MIPS32-LABEL: store_i32_align1: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: lui $1, %hi(i32_align1) +; MIPS32-NEXT: addiu $1, $1, %lo(i32_align1) +; MIPS32-NEXT: swl $4, 3($1) +; MIPS32-NEXT: swr $4, 0($1) +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +; +; MIPS32R6-LABEL: store_i32_align1: +; MIPS32R6: # %bb.0: # %entry +; MIPS32R6-NEXT: lui $1, %hi(i32_align1) +; MIPS32R6-NEXT: addiu $1, $1, %lo(i32_align1) +; MIPS32R6-NEXT: sw $4, 0($1) +; MIPS32R6-NEXT: jrc $ra +entry: + store i32 %a, i32* @i32_align1, align 1 + ret void +} + +define void @store_i32_align2(i32 signext %a) { +; MIPS32-LABEL: store_i32_align2: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: lui $1, %hi(i32_align2) +; MIPS32-NEXT: addiu $1, $1, %lo(i32_align2) +; MIPS32-NEXT: swl $4, 3($1) +; MIPS32-NEXT: swr $4, 0($1) +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +; +; MIPS32R6-LABEL: store_i32_align2: +; MIPS32R6: # %bb.0: # %entry +; MIPS32R6-NEXT: lui $1, %hi(i32_align2) +; MIPS32R6-NEXT: addiu $1, $1, %lo(i32_align2) +; MIPS32R6-NEXT: sw $4, 0($1) +; MIPS32R6-NEXT: jrc $ra +entry: + store i32 %a, i32* @i32_align2, align 2 + ret void +} + +define void @store_i32_align4(i32 signext %a) { +; MIPS32-LABEL: store_i32_align4: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: lui $1, %hi(i32_align4) +; MIPS32-NEXT: addiu $1, $1, %lo(i32_align4) +; MIPS32-NEXT: sw $4, 0($1) +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +; +; MIPS32R6-LABEL: store_i32_align4: +; MIPS32R6: # %bb.0: # %entry +; MIPS32R6-NEXT: lui $1, %hi(i32_align4) +; MIPS32R6-NEXT: addiu $1, $1, %lo(i32_align4) +; MIPS32R6-NEXT: sw $4, 0($1) +; MIPS32R6-NEXT: jrc $ra +entry: + store i32 %a, i32* @i32_align4, align 4 + ret void +} + +define void @store_i32_align8(i32 signext %a) { +; MIPS32-LABEL: store_i32_align8: +; MIPS32: # %bb.0: # %entry +; MIPS32-NEXT: lui $1, %hi(i32_align8) +; MIPS32-NEXT: addiu $1, $1, %lo(i32_align8) +; MIPS32-NEXT: sw $4, 0($1) +; MIPS32-NEXT: jr $ra +; MIPS32-NEXT: nop +; +; MIPS32R6-LABEL: store_i32_align8: +; MIPS32R6: # %bb.0: # %entry +; MIPS32R6-NEXT: lui $1, %hi(i32_align8) +; MIPS32R6-NEXT: addiu $1, $1, %lo(i32_align8) +; MIPS32R6-NEXT: sw $4, 0($1) +; MIPS32R6-NEXT: jrc $ra +entry: + store i32 %a, i32* @i32_align8, align 8 + ret void +} Index: llvm/test/CodeGen/Mips/GlobalISel/regbankselect/phi.mir =================================================================== --- llvm/test/CodeGen/Mips/GlobalISel/regbankselect/phi.mir +++ llvm/test/CodeGen/Mips/GlobalISel/regbankselect/phi.mir @@ -34,8 +34,8 @@ define void @phi_ambiguous_i64_in_fpr(i1 %cnd, i64* %i64_ptr_a, i64* %i64_ptr_b, i64* %i64_ptr_c) { entry: - %0 = load i64, i64* %i64_ptr_a, align 4 - %1 = load i64, i64* %i64_ptr_b, align 4 + %0 = load i64, i64* %i64_ptr_a, align 8 + %1 = load i64, i64* %i64_ptr_b, align 8 br i1 %cnd, label %cond.true, label %cond.false cond.true: ; preds = %entry @@ -46,7 +46,7 @@ cond.end: ; preds = %cond.false, %cond.true %cond = phi i64 [ %0, %cond.true ], [ %1, %cond.false ] - store i64 %cond, i64* %i64_ptr_c, align 4 + store i64 %cond, i64* %i64_ptr_c, align 8 ret void } @@ -230,8 +230,8 @@ ; MIPS32: [[COPY1:%[0-9]+]]:gprb(p0) = COPY $a1 ; MIPS32: [[COPY2:%[0-9]+]]:gprb(p0) = COPY $a2 ; MIPS32: [[COPY3:%[0-9]+]]:gprb(p0) = COPY $a3 - ; MIPS32: [[LOAD:%[0-9]+]]:fprb(s64) = G_LOAD [[COPY1]](p0) :: (load 8 from %ir.i64_ptr_a, align 4) - ; MIPS32: [[LOAD1:%[0-9]+]]:fprb(s64) = G_LOAD [[COPY2]](p0) :: (load 8 from %ir.i64_ptr_b, align 4) + ; MIPS32: [[LOAD:%[0-9]+]]:fprb(s64) = G_LOAD [[COPY1]](p0) :: (load 8 from %ir.i64_ptr_a) + ; MIPS32: [[LOAD1:%[0-9]+]]:fprb(s64) = G_LOAD [[COPY2]](p0) :: (load 8 from %ir.i64_ptr_b) ; MIPS32: [[C:%[0-9]+]]:gprb(s32) = G_CONSTANT i32 1 ; MIPS32: [[COPY4:%[0-9]+]]:gprb(s32) = COPY [[COPY]](s32) ; MIPS32: [[AND:%[0-9]+]]:gprb(s32) = G_AND [[COPY4]], [[C]] @@ -244,7 +244,7 @@ ; MIPS32: successors: %bb.3(0x80000000) ; MIPS32: bb.3.cond.end: ; MIPS32: [[PHI:%[0-9]+]]:fprb(s64) = G_PHI [[LOAD]](s64), %bb.1, [[LOAD1]](s64), %bb.2 - ; MIPS32: G_STORE [[PHI]](s64), [[COPY3]](p0) :: (store 8 into %ir.i64_ptr_c, align 4) + ; MIPS32: G_STORE [[PHI]](s64), [[COPY3]](p0) :: (store 8 into %ir.i64_ptr_c) ; MIPS32: RetRA bb.1.entry: liveins: $a0, $a1, $a2, $a3 @@ -253,8 +253,8 @@ %1:_(p0) = COPY $a1 %2:_(p0) = COPY $a2 %3:_(p0) = COPY $a3 - %5:_(s64) = G_LOAD %1(p0) :: (load 8 from %ir.i64_ptr_a, align 4) - %6:_(s64) = G_LOAD %2(p0) :: (load 8 from %ir.i64_ptr_b, align 4) + %5:_(s64) = G_LOAD %1(p0) :: (load 8 from %ir.i64_ptr_a) + %6:_(s64) = G_LOAD %2(p0) :: (load 8 from %ir.i64_ptr_b) %9:_(s32) = G_CONSTANT i32 1 %10:_(s32) = COPY %4(s32) %8:_(s32) = G_AND %10, %9 @@ -268,7 +268,7 @@ bb.4.cond.end: %7:_(s64) = G_PHI %5(s64), %bb.2, %6(s64), %bb.3 - G_STORE %7(s64), %3(p0) :: (store 8 into %ir.i64_ptr_c, align 4) + G_STORE %7(s64), %3(p0) :: (store 8 into %ir.i64_ptr_c) RetRA ...