From c88f27fe1e449158a450d54b8504b2ff9ca490b4 Mon Sep 17 00:00:00 2001 From: WANG Xuerui Date: Wed, 28 Jun 2023 08:25:28 +0800 Subject: [PATCH] [LoongArch] Add back SDNPSideEffect properties to CSR and IOCSR read ops In general, CSR and IOCSR reads should be treated as volatile because: * there may well be intervening writes between seemingly common expressions; * the stateful entity behind a given (IO)CSR may well be volatile. Confirmed to fix broken Clang Linux/LoongArch builds (dying when a userspace process tries to use FPU, panicking when that process happens to be PID 1) with this patch. Fixes: https://github.com/llvm/llvm-project/issues/63549 Fixes: 2efdacf74c54 ("[LoongArch] Add missing chains and remove unnecessary `SDNPSideEffect` property for some intrinsic nodes") Reviewed By: SixWeining, hev Differential Revision: https://reviews.llvm.org/D153865 --- llvm/lib/Target/LoongArch/LoongArchInstrInfo.td | 10 +- .../LoongArch/intrinsic-csr-side-effects.ll | 47 ++++++ .../LoongArch/intrinsic-iocsr-side-effects.ll | 180 +++++++++++++++++++++ llvm/test/CodeGen/LoongArch/intrinsic-la64.ll | 2 + llvm/test/CodeGen/LoongArch/intrinsic.ll | 4 + 5 files changed, 238 insertions(+), 5 deletions(-) create mode 100644 llvm/test/CodeGen/LoongArch/intrinsic-csr-side-effects.ll create mode 100644 llvm/test/CodeGen/LoongArch/intrinsic-iocsr-side-effects.ll diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td index 2bdc291..44e4866 100644 --- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td +++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td @@ -114,20 +114,20 @@ def loongarch_movgr2fcsr : SDNode<"LoongArchISD::MOVGR2FCSR", def loongarch_syscall : SDNode<"LoongArchISD::SYSCALL", SDT_LoongArchVI, [SDNPHasChain, SDNPSideEffect]>; def loongarch_csrrd : SDNode<"LoongArchISD::CSRRD", SDT_LoongArchCsrrd, - [SDNPHasChain]>; + [SDNPHasChain, SDNPSideEffect]>; def loongarch_csrwr : SDNode<"LoongArchISD::CSRWR", SDT_LoongArchCsrwr, [SDNPHasChain, SDNPSideEffect]>; def loongarch_csrxchg : SDNode<"LoongArchISD::CSRXCHG", SDT_LoongArchCsrxchg, [SDNPHasChain, SDNPSideEffect]>; def loongarch_iocsrrd_b : SDNode<"LoongArchISD::IOCSRRD_B", SDTUnaryOp, - [SDNPHasChain]>; + [SDNPHasChain, SDNPSideEffect]>; def loongarch_iocsrrd_h : SDNode<"LoongArchISD::IOCSRRD_H", SDTUnaryOp, - [SDNPHasChain]>; + [SDNPHasChain, SDNPSideEffect]>; def loongarch_iocsrrd_w : SDNode<"LoongArchISD::IOCSRRD_W", SDTUnaryOp, - [SDNPHasChain]>; + [SDNPHasChain, SDNPSideEffect]>; def loongarch_iocsrrd_d : SDNode<"LoongArchISD::IOCSRRD_D", SDTUnaryOp, - [SDNPHasChain]>; + [SDNPHasChain, SDNPSideEffect]>; def loongarch_iocsrwr_b : SDNode<"LoongArchISD::IOCSRWR_B", SDT_LoongArchIocsrwr, [SDNPHasChain, SDNPSideEffect]>; diff --git a/llvm/test/CodeGen/LoongArch/intrinsic-csr-side-effects.ll b/llvm/test/CodeGen/LoongArch/intrinsic-csr-side-effects.ll new file mode 100644 index 0000000..e3e23e4 --- /dev/null +++ b/llvm/test/CodeGen/LoongArch/intrinsic-csr-side-effects.ll @@ -0,0 +1,47 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc --mtriple=loongarch32 < %s | FileCheck %s +; RUN: llc --mtriple=loongarch64 < %s | FileCheck %s + +declare i32 @llvm.loongarch.csrrd.w(i32 immarg) nounwind +declare i32 @llvm.loongarch.csrwr.w(i32, i32 immarg) nounwind +declare void @bug() + +define dso_local void @foo(i32 noundef signext %flag) nounwind { +; CHECK-LABEL: foo: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: beqz $a0, .LBB0_2 +; CHECK-NEXT: # %bb.1: # %if.then +; CHECK-NEXT: csrrd $a0, 2 +; CHECK-NEXT: ori $a0, $a0, 1 +; CHECK-NEXT: csrwr $a0, 2 +; CHECK-NEXT: .LBB0_2: # %if.end +; CHECK-NEXT: csrrd $a0, 2 +; CHECK-NEXT: andi $a0, $a0, 1 +; CHECK-NEXT: bnez $a0, .LBB0_4 +; CHECK-NEXT: # %bb.3: # %if.then2 +; CHECK-NEXT: b %plt(bug) +; CHECK-NEXT: .LBB0_4: # %if.end3 +; CHECK-NEXT: ret +entry: + %tobool.not = icmp eq i32 %flag, 0 + br i1 %tobool.not, label %if.end, label %if.then + +if.then: ; preds = %entry + %0 = tail call i32 @llvm.loongarch.csrrd.w(i32 2) + %or = or i32 %0, 1 + %1 = tail call i32 @llvm.loongarch.csrwr.w(i32 %or, i32 2) + br label %if.end + +if.end: ; preds = %if.then, %entry + %2 = tail call i32 @llvm.loongarch.csrrd.w(i32 2) + %and = and i32 %2, 1 + %tobool1.not = icmp eq i32 %and, 0 + br i1 %tobool1.not, label %if.then2, label %if.end3 + +if.then2: ; preds = %if.end + tail call void @bug() + br label %if.end3 + +if.end3: ; preds = %if.then2, %if.end + ret void +} diff --git a/llvm/test/CodeGen/LoongArch/intrinsic-iocsr-side-effects.ll b/llvm/test/CodeGen/LoongArch/intrinsic-iocsr-side-effects.ll new file mode 100644 index 0000000..ad78f7f --- /dev/null +++ b/llvm/test/CodeGen/LoongArch/intrinsic-iocsr-side-effects.ll @@ -0,0 +1,180 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc --mtriple=loongarch64 < %s | FileCheck %s + +declare i32 @llvm.loongarch.iocsrrd.b(i32) nounwind +declare void @llvm.loongarch.iocsrwr.b(i32, i32) nounwind +declare i32 @llvm.loongarch.iocsrrd.h(i32) nounwind +declare void @llvm.loongarch.iocsrwr.h(i32, i32) nounwind +declare i32 @llvm.loongarch.iocsrrd.w(i32) nounwind +declare void @llvm.loongarch.iocsrwr.w(i32, i32) nounwind +declare i64 @llvm.loongarch.iocsrrd.d(i32) nounwind +declare void @llvm.loongarch.iocsrwr.d(i64, i32) nounwind +declare void @bug() + +define dso_local void @test_b(i32 noundef signext %flag) nounwind { +; CHECK-LABEL: test_b: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: beqz $a0, .LBB0_2 +; CHECK-NEXT: # %bb.1: # %if.then +; CHECK-NEXT: ori $a0, $zero, 2 +; CHECK-NEXT: iocsrrd.b $a1, $a0 +; CHECK-NEXT: ori $a1, $a1, 1 +; CHECK-NEXT: iocsrwr.b $a1, $a0 +; CHECK-NEXT: .LBB0_2: # %if.end +; CHECK-NEXT: ori $a0, $zero, 2 +; CHECK-NEXT: iocsrrd.b $a0, $a0 +; CHECK-NEXT: andi $a0, $a0, 1 +; CHECK-NEXT: bnez $a0, .LBB0_4 +; CHECK-NEXT: # %bb.3: # %if.then2 +; CHECK-NEXT: b %plt(bug) +; CHECK-NEXT: .LBB0_4: # %if.end3 +; CHECK-NEXT: ret +entry: + %tobool.not = icmp eq i32 %flag, 0 + br i1 %tobool.not, label %if.end, label %if.then + +if.then: ; preds = %entry + %0 = tail call i32 @llvm.loongarch.iocsrrd.b(i32 2) + %or = or i32 %0, 1 + tail call void @llvm.loongarch.iocsrwr.b(i32 %or, i32 2) + br label %if.end + +if.end: ; preds = %if.then, %entry + %1 = tail call i32 @llvm.loongarch.iocsrrd.b(i32 2) + %and = and i32 %1, 1 + %tobool1.not = icmp eq i32 %and, 0 + br i1 %tobool1.not, label %if.then2, label %if.end3 + +if.then2: ; preds = %if.end + tail call void @bug() + br label %if.end3 + +if.end3: ; preds = %if.then2, %if.end + ret void +} + +define dso_local void @test_h(i32 noundef signext %flag) nounwind { +; CHECK-LABEL: test_h: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: beqz $a0, .LBB1_2 +; CHECK-NEXT: # %bb.1: # %if.then +; CHECK-NEXT: ori $a0, $zero, 2 +; CHECK-NEXT: iocsrrd.h $a1, $a0 +; CHECK-NEXT: ori $a1, $a1, 1 +; CHECK-NEXT: iocsrwr.h $a1, $a0 +; CHECK-NEXT: .LBB1_2: # %if.end +; CHECK-NEXT: ori $a0, $zero, 2 +; CHECK-NEXT: iocsrrd.h $a0, $a0 +; CHECK-NEXT: andi $a0, $a0, 1 +; CHECK-NEXT: bnez $a0, .LBB1_4 +; CHECK-NEXT: # %bb.3: # %if.then2 +; CHECK-NEXT: b %plt(bug) +; CHECK-NEXT: .LBB1_4: # %if.end3 +; CHECK-NEXT: ret +entry: + %tobool.not = icmp eq i32 %flag, 0 + br i1 %tobool.not, label %if.end, label %if.then + +if.then: ; preds = %entry + %0 = tail call i32 @llvm.loongarch.iocsrrd.h(i32 2) + %or = or i32 %0, 1 + tail call void @llvm.loongarch.iocsrwr.h(i32 %or, i32 2) + br label %if.end + +if.end: ; preds = %if.then, %entry + %1 = tail call i32 @llvm.loongarch.iocsrrd.h(i32 2) + %and = and i32 %1, 1 + %tobool1.not = icmp eq i32 %and, 0 + br i1 %tobool1.not, label %if.then2, label %if.end3 + +if.then2: ; preds = %if.end + tail call void @bug() + br label %if.end3 + +if.end3: ; preds = %if.then2, %if.end + ret void +} + +define dso_local void @test_w(i32 noundef signext %flag) nounwind { +; CHECK-LABEL: test_w: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: beqz $a0, .LBB2_2 +; CHECK-NEXT: # %bb.1: # %if.then +; CHECK-NEXT: ori $a0, $zero, 2 +; CHECK-NEXT: iocsrrd.w $a1, $a0 +; CHECK-NEXT: ori $a1, $a1, 1 +; CHECK-NEXT: iocsrwr.w $a1, $a0 +; CHECK-NEXT: .LBB2_2: # %if.end +; CHECK-NEXT: ori $a0, $zero, 2 +; CHECK-NEXT: iocsrrd.w $a0, $a0 +; CHECK-NEXT: andi $a0, $a0, 1 +; CHECK-NEXT: bnez $a0, .LBB2_4 +; CHECK-NEXT: # %bb.3: # %if.then2 +; CHECK-NEXT: b %plt(bug) +; CHECK-NEXT: .LBB2_4: # %if.end3 +; CHECK-NEXT: ret +entry: + %tobool.not = icmp eq i32 %flag, 0 + br i1 %tobool.not, label %if.end, label %if.then + +if.then: ; preds = %entry + %0 = tail call i32 @llvm.loongarch.iocsrrd.w(i32 2) + %or = or i32 %0, 1 + tail call void @llvm.loongarch.iocsrwr.w(i32 %or, i32 2) + br label %if.end + +if.end: ; preds = %if.then, %entry + %1 = tail call i32 @llvm.loongarch.iocsrrd.w(i32 2) + %and = and i32 %1, 1 + %tobool1.not = icmp eq i32 %and, 0 + br i1 %tobool1.not, label %if.then2, label %if.end3 + +if.then2: ; preds = %if.end + tail call void @bug() + br label %if.end3 + +if.end3: ; preds = %if.then2, %if.end + ret void +} + +define dso_local void @test_d(i32 noundef signext %flag) nounwind { +; CHECK-LABEL: test_d: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: beqz $a0, .LBB3_2 +; CHECK-NEXT: # %bb.1: # %if.then +; CHECK-NEXT: ori $a0, $zero, 2 +; CHECK-NEXT: iocsrrd.d $a1, $a0 +; CHECK-NEXT: ori $a1, $a1, 1 +; CHECK-NEXT: iocsrwr.d $a1, $a0 +; CHECK-NEXT: .LBB3_2: # %if.end +; CHECK-NEXT: ori $a0, $zero, 2 +; CHECK-NEXT: iocsrrd.d $a0, $a0 +; CHECK-NEXT: andi $a0, $a0, 1 +; CHECK-NEXT: bnez $a0, .LBB3_4 +; CHECK-NEXT: # %bb.3: # %if.then2 +; CHECK-NEXT: b %plt(bug) +; CHECK-NEXT: .LBB3_4: # %if.end3 +; CHECK-NEXT: ret +entry: + %tobool.not = icmp eq i32 %flag, 0 + br i1 %tobool.not, label %if.end, label %if.then + +if.then: ; preds = %entry + %0 = tail call i64 @llvm.loongarch.iocsrrd.d(i32 2) + %or = or i64 %0, 1 + tail call void @llvm.loongarch.iocsrwr.d(i64 %or, i32 2) + br label %if.end + +if.end: ; preds = %if.then, %entry + %1 = tail call i64 @llvm.loongarch.iocsrrd.d(i32 2) + %and = and i64 %1, 1 + %tobool1.not = icmp eq i64 %and, 0 + br i1 %tobool1.not, label %if.then2, label %if.end3 + +if.then2: ; preds = %if.end + tail call void @bug() + br label %if.end3 + +if.end3: ; preds = %if.then2, %if.end + ret void +} diff --git a/llvm/test/CodeGen/LoongArch/intrinsic-la64.ll b/llvm/test/CodeGen/LoongArch/intrinsic-la64.ll index 94e3f53..f0ebd85 100644 --- a/llvm/test/CodeGen/LoongArch/intrinsic-la64.ll +++ b/llvm/test/CodeGen/LoongArch/intrinsic-la64.ll @@ -178,6 +178,7 @@ entry: define void @csrrd_d_noret() { ; CHECK-LABEL: csrrd_d_noret: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: csrrd $a0, 1 ; CHECK-NEXT: ret entry: %0 = tail call i64 @llvm.loongarch.csrrd.d(i32 1) @@ -239,6 +240,7 @@ entry: define void @iocsrrd_d_noret(i32 %a) { ; CHECK-LABEL: iocsrrd_d_noret: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: iocsrrd.d $a0, $a0 ; CHECK-NEXT: ret entry: %0 = tail call i64 @llvm.loongarch.iocsrrd.d(i32 %a) diff --git a/llvm/test/CodeGen/LoongArch/intrinsic.ll b/llvm/test/CodeGen/LoongArch/intrinsic.ll index 065bf7c..f49a250 100644 --- a/llvm/test/CodeGen/LoongArch/intrinsic.ll +++ b/llvm/test/CodeGen/LoongArch/intrinsic.ll @@ -103,6 +103,7 @@ entry: define void @csrrd_w_noret() { ; CHECK-LABEL: csrrd_w_noret: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: csrrd $a0, 1 ; CHECK-NEXT: ret entry: %0 = tail call i32 @llvm.loongarch.csrrd.w(i32 1) @@ -184,6 +185,7 @@ entry: define void @iocsrrd_b_noret(i32 %a) { ; CHECK-LABEL: iocsrrd_b_noret: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: iocsrrd.b $a0, $a0 ; CHECK-NEXT: ret entry: %0 = tail call i32 @llvm.loongarch.iocsrrd.b(i32 %a) @@ -193,6 +195,7 @@ entry: define void @iocsrrd_h_noret(i32 %a) { ; CHECK-LABEL: iocsrrd_h_noret: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: iocsrrd.h $a0, $a0 ; CHECK-NEXT: ret entry: %0 = tail call i32 @llvm.loongarch.iocsrrd.h(i32 %a) @@ -202,6 +205,7 @@ entry: define void @iocsrrd_w_noret(i32 %a) { ; CHECK-LABEL: iocsrrd_w_noret: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: iocsrrd.w $a0, $a0 ; CHECK-NEXT: ret entry: %0 = tail call i32 @llvm.loongarch.iocsrrd.w(i32 %a) -- 2.7.4