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;
+}
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,
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:
; 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:
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
;
; 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: