diff --git a/llvm/lib/Target/M68k/M68kISelLowering.cpp b/llvm/lib/Target/M68k/M68kISelLowering.cpp index c49b83fdc6eb0..d261be6c944c3 100644 --- a/llvm/lib/Target/M68k/M68kISelLowering.cpp +++ b/llvm/lib/Target/M68k/M68kISelLowering.cpp @@ -163,6 +163,8 @@ M68kTargetLowering::M68kTargetLowering(const M68kTargetMachine &TM, setOperationAction(ISD::ATOMIC_CMP_SWAP, {MVT::i8, MVT::i16, MVT::i32}, Subtarget.atLeastM68020() ? Legal : LibCall); + setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Custom); + // 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. @@ -1408,6 +1410,8 @@ SDValue M68kTargetLowering::LowerOperation(SDValue Op, return LowerShiftRightParts(Op, DAG, true); case ISD::SRL_PARTS: return LowerShiftRightParts(Op, DAG, false); + case ISD::ATOMIC_FENCE: + return LowerATOMICFENCE(Op, DAG); } } @@ -3240,6 +3244,28 @@ SDValue M68kTargetLowering::LowerVASTART(SDValue Op, SelectionDAG &DAG) const { MachinePointerInfo(SV)); } +SDValue M68kTargetLowering::LowerATOMICFENCE(SDValue Op, + SelectionDAG &DAG) const { + // Lower to a memory barrier created from inline asm. + const TargetLowering &TLI = DAG.getTargetLoweringInfo(); + LLVMContext &Ctx = *DAG.getContext(); + + const unsigned Flags = InlineAsm::Extra_MayLoad | InlineAsm::Extra_MayStore | + InlineAsm::Extra_HasSideEffects; + const SDValue AsmOperands[4] = { + Op.getOperand(0), // Input chain + DAG.getTargetExternalSymbol( + "", TLI.getProgramPointerTy( + DAG.getDataLayout())), // Empty inline asm string + DAG.getMDNode(MDNode::get(Ctx, {})), // (empty) srcloc + DAG.getTargetConstant(Flags, SDLoc(Op), + TLI.getPointerTy(DAG.getDataLayout())), // Flags + }; + + return DAG.getNode(ISD::INLINEASM, SDLoc(Op), + DAG.getVTList(MVT::Other, MVT::Glue), AsmOperands); +} + // Lower dynamic stack allocation to _alloca call for Cygwin/Mingw targets. // Calls to _alloca are needed to probe the stack when allocating more than 4k // bytes in one go. Touching the stack at 4K increments is necessary to ensure diff --git a/llvm/lib/Target/M68k/M68kISelLowering.h b/llvm/lib/Target/M68k/M68kISelLowering.h index f998f60f4c9d9..bffb11961db79 100644 --- a/llvm/lib/Target/M68k/M68kISelLowering.h +++ b/llvm/lib/Target/M68k/M68kISelLowering.h @@ -238,6 +238,8 @@ class M68kTargetLowering : public TargetLowering { SDValue LowerShiftLeftParts(SDValue Op, SelectionDAG &DAG) const; SDValue LowerShiftRightParts(SDValue Op, SelectionDAG &DAG, bool IsSRA) const; + SDValue LowerATOMICFENCE(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerCallResult(SDValue Chain, SDValue InFlag, CallingConv::ID CallConv, bool IsVarArg, const SmallVectorImpl &Ins, diff --git a/llvm/test/CodeGen/M68k/Atomics/fence.ll b/llvm/test/CodeGen/M68k/Atomics/fence.ll new file mode 100644 index 0000000000000..23318ac302da9 --- /dev/null +++ b/llvm/test/CodeGen/M68k/Atomics/fence.ll @@ -0,0 +1,27 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2 +; RUN: llc -mtriple=m68k-linux-gnu < %s | FileCheck %s + +; M68k's libgcc does NOT have __sync_synchronize so we shouldn't +; lower to that. + +define void @atomic_fence() { +; CHECK-LABEL: atomic_fence: +; CHECK: .cfi_startproc +; CHECK-NEXT: ; %bb.0: ; %entry +; CHECK-NEXT: ;APP +; CHECK-NEXT: ;NO_APP +; CHECK-NEXT: ;APP +; CHECK-NEXT: ;NO_APP +; CHECK-NEXT: ;APP +; CHECK-NEXT: ;NO_APP +; CHECK-NEXT: ;APP +; CHECK-NEXT: ;NO_APP +; CHECK-NEXT: rts +entry: + fence acquire + fence release + fence acq_rel + fence seq_cst + ret void +} +