From c4ce1e0131aa04cec4803740c3c203c7f000e837 Mon Sep 17 00:00:00 2001 From: Philip Reames Date: Tue, 10 Jan 2023 09:51:56 -0800 Subject: [PATCH] [RISCV] Avoid emitting hardware fences for singlethread fences singlethread fences only synchronize with code running on the same hardware thread (i.e. signal handlers). Because of this, we need to prevent instruction reordering, but do not need to emit hardware fence instructions. The implementation strategy here matches many other backends. The main motivation of this patch is to introduce the MEMBARRIER node and get some test coverage for it. Differential Revision: https://reviews.llvm.org/D141311 --- llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp | 3 +++ llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 19 +++++++++++++++++++ llvm/lib/Target/RISCV/RISCVInstrInfo.td | 3 +++ llvm/test/CodeGen/RISCV/atomic-fence.ll | 8 ++++---- 4 files changed, 29 insertions(+), 4 deletions(-) diff --git a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp index 5c36a91..3bafbcc 100644 --- a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp +++ b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp @@ -116,6 +116,9 @@ void RISCVAsmPrinter::emitInstruction(const MachineInstr *MI) { case RISCV::HWASAN_CHECK_MEMACCESS_SHORTGRANULES: LowerHWASAN_CHECK_MEMACCESS(*MI); return; + case RISCV::PseudoMemBarrier: + OutStreamer->emitRawComment("MEMBARRIER"); + return; } MCInst TmpInst; diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp index 74dc737..8c1c8b55 100644 --- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp +++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp @@ -461,6 +461,8 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM, setMaxAtomicSizeInBitsSupported(0); } + setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Custom); + setBooleanContents(ZeroOrOneBooleanContent); if (Subtarget.hasVInstructions()) { @@ -3667,11 +3669,28 @@ static SDValue lowerConstant(SDValue Op, SelectionDAG &DAG, return SDValue(); } +static SDValue LowerATOMIC_FENCE(SDValue Op, SelectionDAG &DAG) { + SDLoc dl(Op); + SyncScope::ID FenceSSID = + static_cast(Op.getConstantOperandVal(2)); + + // singlethread fences only synchronize with signal handlers on the same + // thread and thus only need to preserve instruction order, not actually + // enforce memory ordering. + if (FenceSSID == SyncScope::SingleThread) + // MEMBARRIER is a compiler barrier; it codegens to a no-op. + return DAG.getNode(ISD::MEMBARRIER, dl, MVT::Other, Op.getOperand(0)); + + return Op; +} + SDValue RISCVTargetLowering::LowerOperation(SDValue Op, SelectionDAG &DAG) const { switch (Op.getOpcode()) { default: report_fatal_error("unimplemented operand"); + case ISD::ATOMIC_FENCE: + return LowerATOMIC_FENCE(Op, DAG); case ISD::GlobalAddress: return lowerGlobalAddress(Op, DAG); case ISD::BlockAddress: diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td index c699a94..e46982e 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td @@ -1843,6 +1843,9 @@ def : Pat<(binop_allwusers GPR:$rs1, (AddiPair:$rs2)), (AddiPairImmSmall AddiPair:$rs2))>; } +let hasSideEffects = 1, isMeta = 1 in +def PseudoMemBarrier : Pseudo<(outs), (ins), [(membarrier)]>; + //===----------------------------------------------------------------------===// // Standard extensions //===----------------------------------------------------------------------===// diff --git a/llvm/test/CodeGen/RISCV/atomic-fence.ll b/llvm/test/CodeGen/RISCV/atomic-fence.ll index ff91652..a8d49ce 100644 --- a/llvm/test/CodeGen/RISCV/atomic-fence.ll +++ b/llvm/test/CodeGen/RISCV/atomic-fence.ll @@ -51,7 +51,7 @@ define void @fence_seq_cst() nounwind { define void @fence_singlethread_acquire() nounwind { ; CHECK-LABEL: fence_singlethread_acquire: ; CHECK: # %bb.0: -; CHECK-NEXT: fence r, rw +; CHECK-NEXT: #MEMBARRIER ; CHECK-NEXT: ret fence syncscope("singlethread") acquire ret void @@ -60,7 +60,7 @@ define void @fence_singlethread_acquire() nounwind { define void @fence_singlethread_release() nounwind { ; CHECK-LABEL: fence_singlethread_release: ; CHECK: # %bb.0: -; CHECK-NEXT: fence rw, w +; CHECK-NEXT: #MEMBARRIER ; CHECK-NEXT: ret fence syncscope("singlethread") release ret void @@ -69,7 +69,7 @@ define void @fence_singlethread_release() nounwind { define void @fence_singlethread_acq_rel() nounwind { ; CHECK-LABEL: fence_singlethread_acq_rel: ; CHECK: # %bb.0: -; CHECK-NEXT: fence.tso +; CHECK-NEXT: #MEMBARRIER ; CHECK-NEXT: ret fence syncscope("singlethread") acq_rel ret void @@ -78,7 +78,7 @@ define void @fence_singlethread_acq_rel() nounwind { define void @fence_singlethread_seq_cst() nounwind { ; CHECK-LABEL: fence_singlethread_seq_cst: ; CHECK: # %bb.0: -; CHECK-NEXT: fence rw, rw +; CHECK-NEXT: #MEMBARRIER ; CHECK-NEXT: ret fence syncscope("singlethread") seq_cst ret void -- 2.7.4