diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h --- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.h +++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.h @@ -183,6 +183,10 @@ bool isUsedByReturnOnly(SDNode *N, SDValue &Chain) const override; + bool isLegalAddressingMode(const DataLayout &DL, const AddrMode &AM, Type *Ty, + unsigned AS, + Instruction *I = nullptr) const override; + private: /// Target-specific function used to lower LoongArch calling conventions. typedef bool LoongArchCCAssignFn(const DataLayout &DL, LoongArchABI::ABI ABI, diff --git a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp --- a/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp +++ b/llvm/lib/Target/LoongArch/LoongArchISelLowering.cpp @@ -3142,3 +3142,48 @@ return false; } + +bool LoongArchTargetLowering::isLegalAddressingMode(const DataLayout &DL, + const AddrMode &AM, + Type *Ty, unsigned AS, + Instruction *I) const { + // LoongArch has four basic addressing modes: + // 1. reg + // 2. reg + 12-bit signed offset + // 3. reg + 14-bit signed offset left-shifted by 2 + // 4. reg1 + reg2 + // TODO: Add more checks after support vector extension. + + // No global is ever allowed as a base. + if (AM.BaseGV) + return false; + + // Require a 12 or 14 bit signed offset. + if (!isInt<12>(AM.BaseOffs) || !isShiftedInt<14, 2>(AM.BaseOffs)) + return false; + + switch (AM.Scale) { + case 0: + // "i" is not allowed. + if (!AM.HasBaseReg) + return false; + // Otherwise we have "r+i". + break; + case 1: + // "r+r+i" is not allowed. + if (AM.HasBaseReg && AM.BaseOffs != 0) + return false; + // Otherwise we have "r+r" or "r+i". + break; + case 2: + // "2*r+r" or "2*r+i" is not allowed. + if (AM.HasBaseReg || AM.BaseOffs) + return false; + // Otherwise we have "r+r". + break; + default: + return false; + } + + return true; +} diff --git a/llvm/test/CodeGen/LoongArch/ldptr.ll b/llvm/test/CodeGen/LoongArch/ldptr.ll --- a/llvm/test/CodeGen/LoongArch/ldptr.ll +++ b/llvm/test/CodeGen/LoongArch/ldptr.ll @@ -81,12 +81,10 @@ define i64 @ldptr_d(ptr %p) nounwind { ; LA32-LABEL: ldptr_d: ; LA32: # %bb.0: # %entry -; LA32-NEXT: ori $a1, $zero, 2052 +; LA32-NEXT: ori $a1, $zero, 2048 ; LA32-NEXT: add.w $a1, $a0, $a1 -; LA32-NEXT: ori $a2, $zero, 2048 -; LA32-NEXT: add.w $a0, $a0, $a2 -; LA32-NEXT: ld.w $a0, $a0, 0 -; LA32-NEXT: ld.w $a1, $a1, 0 +; LA32-NEXT: ld.w $a0, $a1, 0 +; LA32-NEXT: ld.w $a1, $a1, 4 ; LA32-NEXT: ret ; ; LA64-LABEL: ldptr_d: @@ -104,11 +102,9 @@ ; LA32-LABEL: ldptr_d_too_big_offset: ; LA32: # %bb.0: # %entry ; LA32-NEXT: lu12i.w $a1, 8 -; LA32-NEXT: ori $a2, $a1, 4 -; LA32-NEXT: add.w $a2, $a0, $a2 -; LA32-NEXT: add.w $a0, $a0, $a1 -; LA32-NEXT: ld.w $a0, $a0, 0 -; LA32-NEXT: ld.w $a1, $a2, 0 +; LA32-NEXT: add.w $a1, $a0, $a1 +; LA32-NEXT: ld.w $a0, $a1, 0 +; LA32-NEXT: ld.w $a1, $a1, 4 ; LA32-NEXT: ret ; ; LA64-LABEL: ldptr_d_too_big_offset: diff --git a/llvm/test/CodeGen/LoongArch/stptr.ll b/llvm/test/CodeGen/LoongArch/stptr.ll --- a/llvm/test/CodeGen/LoongArch/stptr.ll +++ b/llvm/test/CodeGen/LoongArch/stptr.ll @@ -76,11 +76,9 @@ define void @stptr_d(ptr %p, i64 %val) nounwind { ; LA32-LABEL: stptr_d: ; LA32: # %bb.0: -; LA32-NEXT: ori $a3, $zero, 2052 -; LA32-NEXT: add.w $a3, $a0, $a3 -; LA32-NEXT: st.w $a2, $a3, 0 -; LA32-NEXT: ori $a2, $zero, 2048 -; LA32-NEXT: add.w $a0, $a0, $a2 +; LA32-NEXT: ori $a3, $zero, 2048 +; LA32-NEXT: add.w $a0, $a0, $a3 +; LA32-NEXT: st.w $a2, $a0, 4 ; LA32-NEXT: st.w $a1, $a0, 0 ; LA32-NEXT: ret ; @@ -98,11 +96,9 @@ ; LA32-LABEL: stptr_d_too_big_offset: ; LA32: # %bb.0: ; LA32-NEXT: lu12i.w $a3, 8 -; LA32-NEXT: add.w $a4, $a0, $a3 -; LA32-NEXT: st.w $a1, $a4, 0 -; LA32-NEXT: ori $a1, $a3, 4 -; LA32-NEXT: add.w $a0, $a0, $a1 -; LA32-NEXT: st.w $a2, $a0, 0 +; LA32-NEXT: add.w $a0, $a0, $a3 +; LA32-NEXT: st.w $a2, $a0, 4 +; LA32-NEXT: st.w $a1, $a0, 0 ; LA32-NEXT: ret ; ; LA64-LABEL: stptr_d_too_big_offset: