Skip to content

Commit

Permalink
[M68k] Add support for atomic instructions
Browse files Browse the repository at this point in the history
This adds support for atomic_load, atomic_store, atomic_cmpxchg
and atomic_rmw

Fixes #48236

Reviewed by: myhsu, efriedma

Differential Revision: https://reviews.llvm.org/D136525
  • Loading branch information
0x59616e committed Nov 9, 2022
1 parent c7d6a0f commit e086b24
Show file tree
Hide file tree
Showing 11 changed files with 1,362 additions and 1 deletion.
31 changes: 31 additions & 0 deletions llvm/lib/Target/M68k/M68kISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -157,11 +157,42 @@ M68kTargetLowering::M68kTargetLowering(const M68kTargetMachine &TM,

computeRegisterProperties(STI.getRegisterInfo());

// We lower the `atomic-compare-and-swap` to `__sync_val_compare_and_swap`
// for subtarget < M68020
setMaxAtomicSizeInBitsSupported(32);
setOperationAction(ISD::ATOMIC_CMP_SWAP, {MVT::i8, MVT::i16, MVT::i32},
Subtarget.atLeastM68020() ? Legal : LibCall);

// M68k does not have native read-modify-write support, so expand all of them
// to `__sync_fetch_*` for target < M68020, otherwise expand to CmpxChg.
// See `shouldExpandAtomicRMWInIR` below.
setOperationAction(
{
ISD::ATOMIC_LOAD_ADD,
ISD::ATOMIC_LOAD_SUB,
ISD::ATOMIC_LOAD_AND,
ISD::ATOMIC_LOAD_OR,
ISD::ATOMIC_LOAD_XOR,
ISD::ATOMIC_LOAD_NAND,
ISD::ATOMIC_LOAD_MIN,
ISD::ATOMIC_LOAD_MAX,
ISD::ATOMIC_LOAD_UMIN,
ISD::ATOMIC_LOAD_UMAX,
},
{MVT::i8, MVT::i16, MVT::i32}, LibCall);

// 2^2 bytes
// FIXME can it be just 2^1?
setMinFunctionAlignment(Align::Constant<2>());
}

TargetLoweringBase::AtomicExpansionKind
M68kTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *RMW) const {
return Subtarget.atLeastM68020()
? TargetLoweringBase::AtomicExpansionKind::CmpXChg
: TargetLoweringBase::AtomicExpansionKind::None;
}

EVT M68kTargetLowering::getSetCCResultType(const DataLayout &DL,
LLVMContext &Context, EVT VT) const {
// M68k SETcc producess either 0x00 or 0xFF
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/M68k/M68kISelLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,9 @@ class M68kTargetLowering : public TargetLowering {
CCAssignFn *getCCAssignFn(CallingConv::ID CC, bool Return,
bool IsVarArg) const;

AtomicExpansionKind
shouldExpandAtomicRMWInIR(AtomicRMWInst *RMW) const override;

private:
unsigned GetAlignedArgumentStackSize(unsigned StackSize,
SelectionDAG &DAG) const;
Expand Down
46 changes: 46 additions & 0 deletions llvm/lib/Target/M68k/M68kInstrAtomics.td
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
//===-- M68kInstrAtomics.td - Atomics Instructions ---------*- tablegen -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

foreach size = [8, 16, 32] in {
def : Pat<(!cast<SDPatternOperator>("atomic_load_"#size) MxCP_ARI:$ptr),
(!cast<MxInst>("MOV"#size#"dj") !cast<MxMemOp>("MxARI"#size):$ptr)>;

def : Pat<(!cast<SDPatternOperator>("atomic_store_"#size) MxCP_ARI:$ptr,
!cast<MxRegOp>("MxDRD"#size):$val),
(!cast<MxInst>("MOV"#size#"jd") !cast<MxMemOp>("MxARI"#size):$ptr,
!cast<MxRegOp>("MxDRD"#size):$val)>;
}

let Predicates = [AtLeastM68020] in {
class MxCASOp<bits<2> size_encoding, MxType type>
: MxInst<(outs type.ROp:$out),
(ins type.ROp:$dc, type.ROp:$du, !cast<MxMemOp>("MxARI"#type.Size):$mem),
"cas."#type.Prefix#" $dc, $du, $mem"> {
let Inst = (ascend
(descend 0b00001, size_encoding, 0b011, MxEncAddrMode_j<"mem">.EA),
(descend 0b0000000, (operand "$du", 3), 0b000, (operand "$dc", 3))
);
let Constraints = "$out = $dc";
let mayLoad = 1;
let mayStore = 1;
}

def CAS8 : MxCASOp<0x1, MxType8d>;
def CAS16 : MxCASOp<0x2, MxType16d>;
def CAS32 : MxCASOp<0x3, MxType32d>;


foreach size = [8, 16, 32] in {
def : Pat<(!cast<SDPatternOperator>("atomic_cmp_swap_"#size) MxCP_ARI:$ptr,
!cast<MxRegOp>("MxDRD"#size):$cmp,
!cast<MxRegOp>("MxDRD"#size):$new),
(!cast<MxInst>("CAS"#size) !cast<MxRegOp>("MxDRD"#size):$cmp,
!cast<MxRegOp>("MxDRD"#size):$new,
!cast<MxMemOp>("MxARI"#size):$ptr)>;
}
} // let Predicates = [AtLeastM68020]
1 change: 1 addition & 0 deletions llvm/lib/Target/M68k/M68kInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -781,5 +781,6 @@ include "M68kInstrShiftRotate.td"
include "M68kInstrBits.td"
include "M68kInstrArithmetic.td"
include "M68kInstrControl.td"
include "M68kInstrAtomics.td"

include "M68kInstrCompiler.td"
6 changes: 6 additions & 0 deletions llvm/lib/Target/M68k/M68kTargetMachine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ class M68kPassConfig : public TargetPassConfig {
const M68kSubtarget &getM68kSubtarget() const {
return *getM68kTargetMachine().getSubtargetImpl();
}
void addIRPasses() override;
bool addIRTranslator() override;
bool addLegalizeMachineIR() override;
bool addRegBankSelect() override;
Expand All @@ -157,6 +158,11 @@ TargetPassConfig *M68kTargetMachine::createPassConfig(PassManagerBase &PM) {
return new M68kPassConfig(*this, PM);
}

void M68kPassConfig::addIRPasses() {
addPass(createAtomicExpandPass());
TargetPassConfig::addIRPasses();
}

bool M68kPassConfig::addInstSelector() {
// Install an instruction selector.
addPass(createM68kISelDag(getM68kTargetMachine()));
Expand Down
136 changes: 136 additions & 0 deletions llvm/test/CodeGen/M68k/Atomics/cmpxchg.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc %s -o - -mtriple=m68k -mcpu=M68000 | FileCheck %s --check-prefix=NO-ATOMIC
; RUN: llc %s -o - -mtriple=m68k -mcpu=M68010 | FileCheck %s --check-prefix=NO-ATOMIC
; RUN: llc %s -o - -mtriple=m68k -mcpu=M68020 | FileCheck %s --check-prefix=ATOMIC
; RUN: llc %s -o - -mtriple=m68k -mcpu=M68030 | FileCheck %s --check-prefix=ATOMIC
; RUN: llc %s -o - -mtriple=m68k -mcpu=M68040 | FileCheck %s --check-prefix=ATOMIC

define i1 @cmpxchg_i8_monotonic_monotonic(i8 %cmp, i8 %new, ptr %mem) nounwind {
; NO-ATOMIC-LABEL: cmpxchg_i8_monotonic_monotonic:
; NO-ATOMIC: ; %bb.0:
; NO-ATOMIC-NEXT: suba.l #20, %sp
; NO-ATOMIC-NEXT: movem.l %d2, (16,%sp) ; 8-byte Folded Spill
; NO-ATOMIC-NEXT: move.b (31,%sp), %d0
; NO-ATOMIC-NEXT: and.l #255, %d0
; NO-ATOMIC-NEXT: move.l %d0, (8,%sp)
; NO-ATOMIC-NEXT: move.b (27,%sp), %d2
; NO-ATOMIC-NEXT: move.l %d2, %d0
; NO-ATOMIC-NEXT: and.l #255, %d0
; NO-ATOMIC-NEXT: move.l %d0, (4,%sp)
; NO-ATOMIC-NEXT: move.l (32,%sp), (%sp)
; NO-ATOMIC-NEXT: jsr __sync_val_compare_and_swap_1@PLT
; NO-ATOMIC-NEXT: sub.b %d2, %d0
; NO-ATOMIC-NEXT: seq %d0
; NO-ATOMIC-NEXT: movem.l (16,%sp), %d2 ; 8-byte Folded Reload
; NO-ATOMIC-NEXT: adda.l #20, %sp
; NO-ATOMIC-NEXT: rts
;
; ATOMIC-LABEL: cmpxchg_i8_monotonic_monotonic:
; ATOMIC: ; %bb.0:
; ATOMIC-NEXT: suba.l #4, %sp
; ATOMIC-NEXT: movem.l %d2, (0,%sp) ; 8-byte Folded Spill
; ATOMIC-NEXT: move.l (16,%sp), %a0
; ATOMIC-NEXT: move.b (15,%sp), %d0
; ATOMIC-NEXT: move.b (11,%sp), %d1
; ATOMIC-NEXT: move.b %d1, %d2
; ATOMIC-NEXT: cas.b %d2, %d0, (%a0)
; ATOMIC-NEXT: sub.b %d1, %d2
; ATOMIC-NEXT: seq %d0
; ATOMIC-NEXT: movem.l (0,%sp), %d2 ; 8-byte Folded Reload
; ATOMIC-NEXT: adda.l #4, %sp
; ATOMIC-NEXT: rts
%res = cmpxchg ptr %mem, i8 %cmp, i8 %new monotonic monotonic
%val = extractvalue {i8, i1} %res, 1
ret i1 %val
}

define i16 @cmpxchg_i16_release_monotonic(i16 %cmp, i16 %new, ptr %mem) nounwind {
; NO-ATOMIC-LABEL: cmpxchg_i16_release_monotonic:
; NO-ATOMIC: ; %bb.0:
; NO-ATOMIC-NEXT: suba.l #12, %sp
; NO-ATOMIC-NEXT: move.w (22,%sp), %d0
; NO-ATOMIC-NEXT: and.l #65535, %d0
; NO-ATOMIC-NEXT: move.l %d0, (8,%sp)
; NO-ATOMIC-NEXT: move.w (18,%sp), %d0
; NO-ATOMIC-NEXT: and.l #65535, %d0
; NO-ATOMIC-NEXT: move.l %d0, (4,%sp)
; NO-ATOMIC-NEXT: move.l (24,%sp), (%sp)
; NO-ATOMIC-NEXT: jsr __sync_val_compare_and_swap_2@PLT
; NO-ATOMIC-NEXT: adda.l #12, %sp
; NO-ATOMIC-NEXT: rts
;
; ATOMIC-LABEL: cmpxchg_i16_release_monotonic:
; ATOMIC: ; %bb.0:
; ATOMIC-NEXT: move.l (12,%sp), %a0
; ATOMIC-NEXT: move.w (10,%sp), %d1
; ATOMIC-NEXT: move.w (6,%sp), %d0
; ATOMIC-NEXT: cas.w %d0, %d1, (%a0)
; ATOMIC-NEXT: rts
%res = cmpxchg ptr %mem, i16 %cmp, i16 %new release monotonic
%val = extractvalue {i16, i1} %res, 0
ret i16 %val
}

define i32 @cmpxchg_i32_release_acquire(i32 %cmp, i32 %new, ptr %mem) nounwind {
; NO-ATOMIC-LABEL: cmpxchg_i32_release_acquire:
; NO-ATOMIC: ; %bb.0:
; NO-ATOMIC-NEXT: suba.l #12, %sp
; NO-ATOMIC-NEXT: move.l (20,%sp), (8,%sp)
; NO-ATOMIC-NEXT: move.l (16,%sp), (4,%sp)
; NO-ATOMIC-NEXT: move.l (24,%sp), (%sp)
; NO-ATOMIC-NEXT: jsr __sync_val_compare_and_swap_4@PLT
; NO-ATOMIC-NEXT: adda.l #12, %sp
; NO-ATOMIC-NEXT: rts
;
; ATOMIC-LABEL: cmpxchg_i32_release_acquire:
; ATOMIC: ; %bb.0:
; ATOMIC-NEXT: move.l (12,%sp), %a0
; ATOMIC-NEXT: move.l (8,%sp), %d1
; ATOMIC-NEXT: move.l (4,%sp), %d0
; ATOMIC-NEXT: cas.l %d0, %d1, (%a0)
; ATOMIC-NEXT: rts
%res = cmpxchg ptr %mem, i32 %cmp, i32 %new release acquire
%val = extractvalue {i32, i1} %res, 0
ret i32 %val
}

define i64 @cmpxchg_i64_seqcst_seqcst(i64 %cmp, i64 %new, ptr %mem) nounwind {
; NO-ATOMIC-LABEL: cmpxchg_i64_seqcst_seqcst:
; NO-ATOMIC: ; %bb.0:
; NO-ATOMIC-NEXT: suba.l #36, %sp
; NO-ATOMIC-NEXT: move.l (44,%sp), (28,%sp)
; NO-ATOMIC-NEXT: move.l (40,%sp), (24,%sp)
; NO-ATOMIC-NEXT: lea (24,%sp), %a0
; NO-ATOMIC-NEXT: move.l %a0, (4,%sp)
; NO-ATOMIC-NEXT: move.l #5, (20,%sp)
; NO-ATOMIC-NEXT: move.l #5, (16,%sp)
; NO-ATOMIC-NEXT: move.l (52,%sp), (12,%sp)
; NO-ATOMIC-NEXT: move.l (48,%sp), (8,%sp)
; NO-ATOMIC-NEXT: move.l (56,%sp), (%sp)
; NO-ATOMIC-NEXT: jsr __atomic_compare_exchange_8@PLT
; NO-ATOMIC-NEXT: move.l (28,%sp), %d1
; NO-ATOMIC-NEXT: move.l (24,%sp), %d0
; NO-ATOMIC-NEXT: adda.l #36, %sp
; NO-ATOMIC-NEXT: rts
;
; ATOMIC-LABEL: cmpxchg_i64_seqcst_seqcst:
; ATOMIC: ; %bb.0:
; ATOMIC-NEXT: suba.l #36, %sp
; ATOMIC-NEXT: move.l (44,%sp), (28,%sp)
; ATOMIC-NEXT: move.l (40,%sp), (24,%sp)
; ATOMIC-NEXT: lea (24,%sp), %a0
; ATOMIC-NEXT: move.l %a0, (4,%sp)
; ATOMIC-NEXT: move.l #5, (20,%sp)
; ATOMIC-NEXT: move.l #5, (16,%sp)
; ATOMIC-NEXT: move.l (52,%sp), (12,%sp)
; ATOMIC-NEXT: move.l (48,%sp), (8,%sp)
; ATOMIC-NEXT: move.l (56,%sp), (%sp)
; ATOMIC-NEXT: jsr __atomic_compare_exchange_8@PLT
; ATOMIC-NEXT: move.l (28,%sp), %d1
; ATOMIC-NEXT: move.l (24,%sp), %d0
; ATOMIC-NEXT: adda.l #36, %sp
; ATOMIC-NEXT: rts
%res = cmpxchg ptr %mem, i64 %cmp, i64 %new seq_cst seq_cst
%val = extractvalue {i64, i1} %res, 0
ret i64 %val
}
Loading

2 comments on commit e086b24

@brad0
Copy link
Contributor

@brad0 brad0 commented on e086b24 Nov 13, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seeing this, should have __GCC_HAVE_SYNC_COMPARE_AND_SWAP_X defined in clang/lib/Basic/Targets/M68k.cpp in M68kTargetInfo::getTargetDefines().

@0x59616e
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, I'll look into it.

Please sign in to comment.