Skip to content

Commit

Permalink
[RISCV][GISel] Select G_FENCE. (#73184)
Browse files Browse the repository at this point in the history
Using IR test to make it easier to compare with the SelectionDAG test
output. The constant operands otherwise make it harder to understand.
  • Loading branch information
topperc committed Nov 28, 2023
1 parent a3b7b2d commit ffcc5c7
Show file tree
Hide file tree
Showing 2 changed files with 168 additions and 0 deletions.
68 changes: 68 additions & 0 deletions llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@ class RISCVInstructionSelector : public InstructionSelector {
MachineRegisterInfo &MRI) const;
bool selectIntrinsicWithSideEffects(MachineInstr &MI, MachineIRBuilder &MIB,
MachineRegisterInfo &MRI) const;
void emitFence(AtomicOrdering FenceOrdering, SyncScope::ID FenceSSID,
MachineIRBuilder &MIB) const;

ComplexRendererFns selectShiftMask(MachineOperand &Root) const;
ComplexRendererFns selectAddrRegImm(MachineOperand &Root) const;
Expand Down Expand Up @@ -612,6 +614,15 @@ bool RISCVInstructionSelector::select(MachineInstr &MI) {
return selectFPCompare(MI, MIB, MRI);
case TargetOpcode::G_INTRINSIC_W_SIDE_EFFECTS:
return selectIntrinsicWithSideEffects(MI, MIB, MRI);
case TargetOpcode::G_FENCE: {
AtomicOrdering FenceOrdering =
static_cast<AtomicOrdering>(MI.getOperand(0).getImm());
SyncScope::ID FenceSSID =
static_cast<SyncScope::ID>(MI.getOperand(1).getImm());
emitFence(FenceOrdering, FenceSSID, MIB);
MI.eraseFromParent();
return true;
}
default:
return false;
}
Expand Down Expand Up @@ -1087,6 +1098,63 @@ bool RISCVInstructionSelector::selectIntrinsicWithSideEffects(
return true;
}

void RISCVInstructionSelector::emitFence(AtomicOrdering FenceOrdering,
SyncScope::ID FenceSSID,
MachineIRBuilder &MIB) const {
if (STI.hasStdExtZtso()) {
// The only fence that needs an instruction is a sequentially-consistent
// cross-thread fence.
if (FenceOrdering == AtomicOrdering::SequentiallyConsistent &&
FenceSSID == SyncScope::System) {
// fence rw, rw
MIB.buildInstr(RISCV::FENCE, {}, {})
.addImm(RISCVFenceField::R | RISCVFenceField::W)
.addImm(RISCVFenceField::R | RISCVFenceField::W);
return;
}

// MEMBARRIER is a compiler barrier; it codegens to a no-op.
MIB.buildInstr(TargetOpcode::MEMBARRIER, {}, {});
return;
}

// 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) {
MIB.buildInstr(TargetOpcode::MEMBARRIER, {}, {});
return;
}

// Refer to Table A.6 in the version 2.3 draft of the RISC-V Instruction Set
// Manual: Volume I.
unsigned Pred, Succ;
switch (FenceOrdering) {
default:
llvm_unreachable("Unexpected ordering");
case AtomicOrdering::AcquireRelease:
// fence acq_rel -> fence.tso
MIB.buildInstr(RISCV::FENCE_TSO, {}, {});
return;
case AtomicOrdering::Acquire:
// fence acquire -> fence r, rw
Pred = RISCVFenceField::R;
Succ = RISCVFenceField::R | RISCVFenceField::W;
break;
case AtomicOrdering::Release:
// fence release -> fence rw, w
Pred = RISCVFenceField::R | RISCVFenceField::W;
Succ = RISCVFenceField::W;
break;
case AtomicOrdering::SequentiallyConsistent:
// fence seq_cst -> fence rw, rw
Pred = RISCVFenceField::R | RISCVFenceField::W;
Succ = RISCVFenceField::R | RISCVFenceField::W;
break;
}
MIB.buildInstr(RISCV::FENCE, {}, {}).addImm(Pred).addImm(Succ);
}

namespace llvm {
InstructionSelector *
createRISCVInstructionSelector(const RISCVTargetMachine &TM,
Expand Down
100 changes: 100 additions & 0 deletions llvm/test/CodeGen/RISCV/GlobalISel/atomic-fence.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=riscv32 -global-isel -verify-machineinstrs < %s \
; RUN: | FileCheck --check-prefixes=CHECK,WMO %s
; RUN: llc -mtriple=riscv32 -mattr=+a -global-isel -verify-machineinstrs < %s \
; RUN: | FileCheck --check-prefixes=CHECK,WMO %s
; RUN: llc -mtriple=riscv32 -mattr=+a,+experimental-ztso -global-isel -verify-machineinstrs < %s \
; RUN: | FileCheck --check-prefixes=CHECK,TSO %s
; RUN: llc -mtriple=riscv64 -global-isel -verify-machineinstrs < %s \
; RUN: | FileCheck --check-prefixes=CHECK,WMO %s
; RUN: llc -mtriple=riscv64 -mattr=+a -global-isel -verify-machineinstrs < %s \
; RUN: | FileCheck --check-prefixes=CHECK,WMO %s
; RUN: llc -mtriple=riscv64 -mattr=+a,+experimental-ztso -global-isel -verify-machineinstrs < %s \
; RUN: | FileCheck --check-prefixes=CHECK,TSO %s

define void @fence_acquire() nounwind {
; WMO-LABEL: fence_acquire:
; WMO: # %bb.0:
; WMO-NEXT: fence r, rw
; WMO-NEXT: ret
;
; TSO-LABEL: fence_acquire:
; TSO: # %bb.0:
; TSO-NEXT: #MEMBARRIER
; TSO-NEXT: ret
fence acquire
ret void
}

define void @fence_release() nounwind {
; WMO-LABEL: fence_release:
; WMO: # %bb.0:
; WMO-NEXT: fence rw, w
; WMO-NEXT: ret
;
; TSO-LABEL: fence_release:
; TSO: # %bb.0:
; TSO-NEXT: #MEMBARRIER
; TSO-NEXT: ret
fence release
ret void
}

define void @fence_acq_rel() nounwind {
; WMO-LABEL: fence_acq_rel:
; WMO: # %bb.0:
; WMO-NEXT: fence.tso
; WMO-NEXT: ret
;
; TSO-LABEL: fence_acq_rel:
; TSO: # %bb.0:
; TSO-NEXT: #MEMBARRIER
; TSO-NEXT: ret
fence acq_rel
ret void
}

define void @fence_seq_cst() nounwind {
; CHECK-LABEL: fence_seq_cst:
; CHECK: # %bb.0:
; CHECK-NEXT: fence rw, rw
; CHECK-NEXT: ret
fence seq_cst
ret void
}

define void @fence_singlethread_acquire() nounwind {
; CHECK-LABEL: fence_singlethread_acquire:
; CHECK: # %bb.0:
; CHECK-NEXT: #MEMBARRIER
; CHECK-NEXT: ret
fence syncscope("singlethread") acquire
ret void
}

define void @fence_singlethread_release() nounwind {
; CHECK-LABEL: fence_singlethread_release:
; CHECK: # %bb.0:
; CHECK-NEXT: #MEMBARRIER
; CHECK-NEXT: ret
fence syncscope("singlethread") release
ret void
}

define void @fence_singlethread_acq_rel() nounwind {
; CHECK-LABEL: fence_singlethread_acq_rel:
; CHECK: # %bb.0:
; CHECK-NEXT: #MEMBARRIER
; CHECK-NEXT: ret
fence syncscope("singlethread") acq_rel
ret void
}

define void @fence_singlethread_seq_cst() nounwind {
; CHECK-LABEL: fence_singlethread_seq_cst:
; CHECK: # %bb.0:
; CHECK-NEXT: #MEMBARRIER
; CHECK-NEXT: ret
fence syncscope("singlethread") seq_cst
ret void
}

0 comments on commit ffcc5c7

Please sign in to comment.