Skip to content

Commit

Permalink
[LoongArch] Don't merge FrameIndex accesses into [F]{LD,ST}X
Browse files Browse the repository at this point in the history
Otherwise eliminateFrameIndex cannot figure out how to fixup the stack
offset with its stateless logic, because there wouldn't be an immediate
slot for it to trivially write to, and it may not be easy to transform
the surrounding code to make it work.

This fixes a fairly common crash when compiling moderately complex code with
Clang.

Differential Revision: https://reviews.llvm.org/D135251
  • Loading branch information
xen0n authored and SixWeining committed Oct 9, 2022
1 parent f204229 commit 31327c2
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 4 deletions.
8 changes: 8 additions & 0 deletions llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.cpp
Expand Up @@ -88,6 +88,14 @@ bool LoongArchDAGToDAGISel::SelectBaseAddr(SDValue Addr, SDValue &Base) {
return true;
}

bool LoongArchDAGToDAGISel::selectNonFIBaseAddr(SDValue Addr, SDValue &Base) {
// If this is FrameIndex, don't select it.
if (isa<FrameIndexSDNode>(Addr))
return false;
Base = Addr;
return true;
}

bool LoongArchDAGToDAGISel::selectShiftMask(SDValue N, unsigned ShiftWidth,
SDValue &ShAmt) {
// Shift instructions on LoongArch only read the lower 5 or 6 bits of the
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/LoongArch/LoongArchISelDAGToDAG.h
Expand Up @@ -39,6 +39,7 @@ class LoongArchDAGToDAGISel : public SelectionDAGISel {
void Select(SDNode *Node) override;

bool SelectBaseAddr(SDValue Addr, SDValue &Base);
bool selectNonFIBaseAddr(SDValue Addr, SDValue &Base);

bool selectShiftMask(SDValue N, unsigned ShiftWidth, SDValue &ShAmt);
bool selectShiftMaskGRLen(SDValue N, SDValue &ShAmt) {
Expand Down
9 changes: 5 additions & 4 deletions llvm/lib/Target/LoongArch/LoongArchInstrInfo.td
Expand Up @@ -248,6 +248,7 @@ def ImmSubFrom32 : SDNodeXForm<imm, [{
}]>;

def BaseAddr : ComplexPattern<iPTR, 1, "SelectBaseAddr">;
def NonFIBaseAddr : ComplexPattern<iPTR, 1, "selectNonFIBaseAddr">;

def fma_nsz : PatFrag<(ops node:$fj, node:$fk, node:$fa),
(fma node:$fj, node:$fk, node:$fa), [{
Expand Down Expand Up @@ -987,8 +988,8 @@ defm : LdPat<load, LD_D, i64>;
// LA64 register-register-addressed loads
let Predicates = [IsLA64] in {
class RegRegLdPat<PatFrag LoadOp, LAInst Inst, ValueType vt>
: Pat<(vt (LoadOp (add BaseAddr:$rj, GPR:$rk))),
(Inst BaseAddr:$rj, GPR:$rk)>;
: Pat<(vt (LoadOp (add NonFIBaseAddr:$rj, GPR:$rk))),
(Inst NonFIBaseAddr:$rj, GPR:$rk)>;

def : RegRegLdPat<extloadi8, LDX_B, i64>;
def : RegRegLdPat<sextloadi8, LDX_B, i64>;
Expand Down Expand Up @@ -1036,8 +1037,8 @@ def : Pat<(store (i64 GPR:$rd), (AddLike BaseAddr:$rj, simm14_lsl2:$imm14)),
let Predicates = [IsLA64] in {
class RegRegStPat<PatFrag StoreOp, LAInst Inst, RegisterClass StTy,
ValueType vt>
: Pat<(StoreOp (vt StTy:$rd), (add BaseAddr:$rj, GPR:$rk)),
(Inst StTy:$rd, BaseAddr:$rj, GPR:$rk)>;
: Pat<(StoreOp (vt StTy:$rd), (add NonFIBaseAddr:$rj, GPR:$rk)),
(Inst StTy:$rd, NonFIBaseAddr:$rj, GPR:$rk)>;

def : RegRegStPat<truncstorei8, STX_B, GPR, i64>;
def : RegRegStPat<truncstorei16, STX_H, GPR, i64>;
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/LoongArch/LoongArchRegisterInfo.cpp
Expand Up @@ -114,6 +114,9 @@ void LoongArchRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
assert(SPAdj == 0 && "Unexpected non-zero SPAdj value");

MachineInstr &MI = *II;
assert(MI.getOperand(FIOperandNum + 1).isImm() &&
"Unexpected FI-consuming insn");

MachineBasicBlock &MBB = *MI.getParent();
MachineFunction &MF = *MI.getParent()->getParent();
MachineRegisterInfo &MRI = MF.getRegInfo();
Expand Down
68 changes: 68 additions & 0 deletions llvm/test/CodeGen/LoongArch/ldx-stx-sp-1.ll
@@ -0,0 +1,68 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc --mtriple=loongarch64 --mattr=+f < %s | FileCheck %s

;; This should not crash the code generator, but the indexed loads/stores
;; should still be present (the important part is that [f]{ld,st}x shouldn't
;; take an $sp argument).

define i8 @test_load_i(i64 %i) {
; CHECK-LABEL: test_load_i:
; CHECK: # %bb.0:
; CHECK-NEXT: addi.d $sp, $sp, -16
; CHECK-NEXT: .cfi_def_cfa_offset 16
; CHECK-NEXT: addi.d $a1, $sp, 8
; CHECK-NEXT: ldx.b $a0, $a0, $a1
; CHECK-NEXT: addi.d $sp, $sp, 16
; CHECK-NEXT: ret
%1 = alloca ptr
%2 = getelementptr inbounds i8, ptr %1, i64 %i
%3 = load i8, ptr %2
ret i8 %3
}

define float @test_load_f(i64 %i) {
; CHECK-LABEL: test_load_f:
; CHECK: # %bb.0:
; CHECK-NEXT: addi.d $sp, $sp, -16
; CHECK-NEXT: .cfi_def_cfa_offset 16
; CHECK-NEXT: slli.d $a0, $a0, 2
; CHECK-NEXT: addi.d $a1, $sp, 8
; CHECK-NEXT: fldx.s $fa0, $a0, $a1
; CHECK-NEXT: addi.d $sp, $sp, 16
; CHECK-NEXT: ret
%1 = alloca ptr
%2 = getelementptr inbounds float, ptr %1, i64 %i
%3 = load float, ptr %2
ret float %3
}

define void @test_store_i(i64 %i, i8 %v) {
; CHECK-LABEL: test_store_i:
; CHECK: # %bb.0:
; CHECK-NEXT: addi.d $sp, $sp, -16
; CHECK-NEXT: .cfi_def_cfa_offset 16
; CHECK-NEXT: addi.d $a2, $sp, 8
; CHECK-NEXT: stx.b $a1, $a0, $a2
; CHECK-NEXT: addi.d $sp, $sp, 16
; CHECK-NEXT: ret
%1 = alloca ptr
%2 = getelementptr inbounds i8, ptr %1, i64 %i
store i8 %v, ptr %2, align 1
ret void
}

define void @test_store_f(i64 %i, float %v) {
; CHECK-LABEL: test_store_f:
; CHECK: # %bb.0:
; CHECK-NEXT: addi.d $sp, $sp, -16
; CHECK-NEXT: .cfi_def_cfa_offset 16
; CHECK-NEXT: slli.d $a0, $a0, 2
; CHECK-NEXT: addi.d $a1, $sp, 8
; CHECK-NEXT: fstx.s $fa0, $a0, $a1
; CHECK-NEXT: addi.d $sp, $sp, 16
; CHECK-NEXT: ret
%1 = alloca ptr
%2 = getelementptr inbounds float, ptr %1, i64 %i
store float %v, ptr %2, align 4
ret void
}
20 changes: 20 additions & 0 deletions llvm/test/CodeGen/LoongArch/ldx-stx-sp-2.ll
@@ -0,0 +1,20 @@
; RUN: llc --mtriple=loongarch32 < %s
; RUN: llc --mtriple=loongarch64 < %s

;; This should not crash the code generator.

@.str.2 = external dso_local unnamed_addr constant [69 x i8], align 1

define dso_local void @main() {
entry:
%n0 = alloca [2 x [3 x i32]], align 4
%0 = load i32, ptr poison, align 4
%idxprom15 = sext i32 %0 to i64
%arrayidx16 = getelementptr inbounds [2 x [3 x i32]], ptr %n0, i64 0, i64 %idxprom15
%arrayidx17 = getelementptr inbounds [3 x i32], ptr %arrayidx16, i64 0, i64 0
%1 = load i32, ptr %arrayidx17, align 4
call void (ptr, ...) @printf(ptr noundef @.str.2, i32 noundef signext %1)
ret void
}

declare void @printf(ptr, ...)
23 changes: 23 additions & 0 deletions llvm/test/CodeGen/LoongArch/ldx-stx-sp-3.ll
@@ -0,0 +1,23 @@
; RUN: llc --mtriple=loongarch32 < %s
; RUN: llc --mtriple=loongarch64 < %s

;; This should not crash the code generator.

define void @_ZN12_GLOBAL__N_111DumpVisitorclIN4llvm16itanium_demangle8FoldExprEEEvPKT_() {
entry:
%ref.tmp6.i.i = alloca [4 x i8], align 1
br label %for.cond.i.i

for.cond.i.i: ; preds = %for.body.i.i, %entry
%__begin0.0.add.i.i = add nuw nsw i64 poison, 1
br label %for.body.i.i

for.body.i.i: ; preds = %for.cond.i.i
%__begin0.0.ptr.i.i = getelementptr inbounds i8, ptr %ref.tmp6.i.i, i64 %__begin0.0.add.i.i
%0 = load i8, ptr %__begin0.0.ptr.i.i, align 1
%tobool18.not.i.i = icmp eq i8 %0, 0
br i1 %tobool18.not.i.i, label %for.cond.i.i, label %exit

exit: ; preds = %for.body.i.i
unreachable
}

0 comments on commit 31327c2

Please sign in to comment.