llvm.org GIT mirror llvm / 020dc8d
IR: Add fp operations to atomicrmw Add just fadd/fsub for now. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@351778 91177308-0d34-0410-b5e6-96231b3b80d8 Matt Arsenault 8 months ago
26 changed file(s) with 392 addition(s) and 22 deletion(s). Raw diff Collapse all Expand all
86668666 - min
86678667 - umax
86688668 - umin
8669 - fadd
8670 - fsub
86698671
86708672 For most of these operations, the type of '' must be an integer
86718673 type whose bit width is a power of two greater than or equal to eight
86728674 and less than or equal to a target-specific size limit. For xchg, this
86738675 may also be a floating point type with the same size constraints as
8674 integers. The type of the '````' operand must be a pointer to
8675 that type. If the ``atomicrmw`` is marked as ``volatile``, then the
8676 optimizer is not allowed to modify the number or order of execution of
8677 this ``atomicrmw`` with other :ref:`volatile operations `.
8676 integers. For fadd/fsub, this must be a floating point type. The
8677 type of the '````' operand must be a pointer to that type. If
8678 the ``atomicrmw`` is marked as ``volatile``, then the optimizer is not
8679 allowed to modify the number or order of execution of this
8680 ``atomicrmw`` with other :ref:`volatile operations `.
86788681
86798682 A ``atomicrmw`` instruction can also take an optional
86808683 ":ref:`syncscope `" argument.
87008703 comparison)
87018704 - umin: ``*ptr = *ptr < val ? *ptr : val`` (using an unsigned
87028705 comparison)
8706 - fadd: ``*ptr = *ptr + val`` (using floating point arithmetic)
8707 - fsub: ``*ptr = *ptr - val`` (using floating point arithmetic)
87038708
87048709 Example:
87058710 """"""""
405405 RMW_MAX = 7,
406406 RMW_MIN = 8,
407407 RMW_UMAX = 9,
408 RMW_UMIN = 10
408 RMW_UMIN = 10,
409 RMW_FADD = 11,
410 RMW_FSUB = 12
409411 };
410412
411413 /// OverflowingBinaryOperatorOptionalFlags - Flags for serializing
17141714
17151715 /// Returns how the IR-level AtomicExpand pass should expand the given
17161716 /// AtomicRMW, if at all. Default is to never expand.
1717 virtual AtomicExpansionKind shouldExpandAtomicRMWInIR(AtomicRMWInst *) const {
1718 return AtomicExpansionKind::None;
1717 virtual AtomicExpansionKind shouldExpandAtomicRMWInIR(AtomicRMWInst *RMW) const {
1718 return RMW->isFloatingPointOperation() ?
1719 AtomicExpansionKind::CmpXChg : AtomicExpansionKind::None;
17191720 }
17201721
17211722 /// On some platforms, an AtomicRMW that never actually modifies the value
723723 /// *p = old
724724 UMin,
725725
726 /// *p = old + v
727 FAdd,
728
729 /// *p = old - v
730 FSub,
731
726732 FIRST_BINOP = Xchg,
727 LAST_BINOP = UMin,
733 LAST_BINOP = FSub,
728734 BAD_BINOP
729735 };
730736
746752
747753 static StringRef getOperationName(BinOp Op);
748754
755 static bool isFPOperation(BinOp Op) {
756 switch (Op) {
757 case AtomicRMWInst::FAdd:
758 case AtomicRMWInst::FSub:
759 return true;
760 default:
761 return false;
762 }
763 }
764
749765 void setOperation(BinOp Operation) {
750766 unsigned short SubclassData = getSubclassDataFromInstruction();
751767 setInstructionSubclassData((SubclassData & 31) |
801817 /// Returns the address space of the pointer operand.
802818 unsigned getPointerAddressSpace() const {
803819 return getPointerOperand()->getType()->getPointerAddressSpace();
820 }
821
822 bool isFloatingPointOperation() const {
823 return isFPOperation(getOperation());
804824 }
805825
806826 // Methods for support type inquiry through isa, cast, and dyn_cast:
68146814 AtomicOrdering Ordering = AtomicOrdering::NotAtomic;
68156815 SyncScope::ID SSID = SyncScope::System;
68166816 bool isVolatile = false;
6817 bool IsFP = false;
68176818 AtomicRMWInst::BinOp Operation;
68186819
68196820 if (EatIfPresent(lltok::kw_volatile))
68326833 case lltok::kw_min: Operation = AtomicRMWInst::Min; break;
68336834 case lltok::kw_umax: Operation = AtomicRMWInst::UMax; break;
68346835 case lltok::kw_umin: Operation = AtomicRMWInst::UMin; break;
6836 case lltok::kw_fadd:
6837 Operation = AtomicRMWInst::FAdd;
6838 IsFP = true;
6839 break;
6840 case lltok::kw_fsub:
6841 Operation = AtomicRMWInst::FSub;
6842 IsFP = true;
6843 break;
68356844 }
68366845 Lex.Lex(); // Eat the operation.
68376846
68486857 if (cast(Ptr->getType())->getElementType() != Val->getType())
68496858 return Error(ValLoc, "atomicrmw value and pointer type do not match");
68506859
6851 if (Operation != AtomicRMWInst::Xchg && !Val->getType()->isIntegerTy()) {
6852 return Error(ValLoc, "atomicrmw " +
6853 AtomicRMWInst::getOperationName(Operation) +
6854 " operand must be an integer");
6855 }
6856
6857 if (Operation == AtomicRMWInst::Xchg &&
6858 !Val->getType()->isIntegerTy() &&
6859 !Val->getType()->isFloatingPointTy()) {
6860 return Error(ValLoc, "atomicrmw " +
6861 AtomicRMWInst::getOperationName(Operation) +
6862 " operand must be an integer or floating point type");
6860 if (Operation == AtomicRMWInst::Xchg) {
6861 if (!Val->getType()->isIntegerTy() &&
6862 !Val->getType()->isFloatingPointTy()) {
6863 return Error(ValLoc, "atomicrmw " +
6864 AtomicRMWInst::getOperationName(Operation) +
6865 " operand must be an integer or floating point type");
6866 }
6867 } else if (IsFP) {
6868 if (!Val->getType()->isFloatingPointTy()) {
6869 return Error(ValLoc, "atomicrmw " +
6870 AtomicRMWInst::getOperationName(Operation) +
6871 " operand must be a floating point type");
6872 }
6873 } else {
6874 if (!Val->getType()->isIntegerTy()) {
6875 return Error(ValLoc, "atomicrmw " +
6876 AtomicRMWInst::getOperationName(Operation) +
6877 " operand must be an integer");
6878 }
68636879 }
68646880
68656881 unsigned Size = Val->getType()->getPrimitiveSizeInBits();
10331033 case bitc::RMW_MIN: return AtomicRMWInst::Min;
10341034 case bitc::RMW_UMAX: return AtomicRMWInst::UMax;
10351035 case bitc::RMW_UMIN: return AtomicRMWInst::UMin;
1036 case bitc::RMW_FADD: return AtomicRMWInst::FAdd;
1037 case bitc::RMW_FSUB: return AtomicRMWInst::FSub;
10361038 }
10371039 }
10381040
558558 case AtomicRMWInst::Min: return bitc::RMW_MIN;
559559 case AtomicRMWInst::UMax: return bitc::RMW_UMAX;
560560 case AtomicRMWInst::UMin: return bitc::RMW_UMIN;
561 case AtomicRMWInst::FAdd: return bitc::RMW_FADD;
562 case AtomicRMWInst::FSub: return bitc::RMW_FSUB;
561563 }
562564 }
563565
548548 case AtomicRMWInst::UMin:
549549 NewVal = Builder.CreateICmpULE(Loaded, Inc);
550550 return Builder.CreateSelect(NewVal, Loaded, Inc, "new");
551 case AtomicRMWInst::FAdd:
552 return Builder.CreateFAdd(Loaded, Inc, "new");
553 case AtomicRMWInst::FSub:
554 return Builder.CreateFSub(Loaded, Inc, "new");
551555 default:
552556 llvm_unreachable("Unknown atomic op");
553557 }
15461550 case AtomicRMWInst::Min:
15471551 case AtomicRMWInst::UMax:
15481552 case AtomicRMWInst::UMin:
1553 case AtomicRMWInst::FAdd:
1554 case AtomicRMWInst::FSub:
15491555 // No atomic libcalls are available for max/min/umax/umin.
15501556 return {};
15511557 }
14061406 return "umax";
14071407 case AtomicRMWInst::UMin:
14081408 return "umin";
1409 case AtomicRMWInst::FAdd:
1410 return "fadd";
1411 case AtomicRMWInst::FSub:
1412 return "fsub";
14091413 case AtomicRMWInst::BAD_BINOP:
14101414 return "";
14111415 }
34343434 AtomicRMWInst::getOperationName(Op) +
34353435 " operand must have integer or floating point type!",
34363436 &RMWI, ElTy);
3437 } else if (AtomicRMWInst::isFPOperation(Op)) {
3438 Assert(ElTy->isFloatingPointTy(), "atomicrmw " +
3439 AtomicRMWInst::getOperationName(Op) +
3440 " operand must have floating point type!",
3441 &RMWI, ElTy);
34373442 } else {
34383443 Assert(ElTy->isIntegerTy(), "atomicrmw " +
34393444 AtomicRMWInst::getOperationName(Op) +
1159911599 // For the real atomic operations, we have ldxr/stxr up to 128 bits,
1160011600 TargetLowering::AtomicExpansionKind
1160111601 AArch64TargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const {
11602 if (AI->isFloatingPointOperation())
11603 return AtomicExpansionKind::CmpXChg;
11604
1160211605 unsigned Size = AI->getType()->getPrimitiveSizeInBits();
1160311606 if (Size > 128) return AtomicExpansionKind::None;
1160411607 // Nand not supported in LSE.
1464414644 // and up to 64 bits on the non-M profiles
1464514645 TargetLowering::AtomicExpansionKind
1464614646 ARMTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const {
14647 if (AI->isFloatingPointOperation())
14648 return AtomicExpansionKind::CmpXChg;
14649
1464714650 unsigned Size = AI->getType()->getPrimitiveSizeInBits();
1464814651 bool hasAtomicRMW = !Subtarget->isThumb() || Subtarget->hasV8MBaselineOps();
1464914652 return (Size <= (Subtarget->isMClass() ? 32U : 64U) && hasAtomicRMW)
31093109 AtomicOrdering Ord) const {
31103110 BasicBlock *BB = Builder.GetInsertBlock();
31113111 Module *M = BB->getParent()->getParent();
3112 Type *Ty = cast(Addr->getType())->getElementType();
3112 auto PT = cast(Addr->getType());
3113 Type *Ty = PT->getElementType();
31133114 unsigned SZ = Ty->getPrimitiveSizeInBits();
31143115 assert((SZ == 32 || SZ == 64) && "Only 32/64-bit atomic loads supported");
31153116 Intrinsic::ID IntID = (SZ == 32) ? Intrinsic::hexagon_L2_loadw_locked
31163117 : Intrinsic::hexagon_L4_loadd_locked;
3118
3119 PointerType *NewPtrTy
3120 = Builder.getIntNTy(SZ)->getPointerTo(PT->getAddressSpace());
3121 Addr = Builder.CreateBitCast(Addr, NewPtrTy);
3122
31173123 Value *Fn = Intrinsic::getDeclaration(M, IntID);
3118 return Builder.CreateCall(Fn, Addr, "larx");
3124 Value *Call = Builder.CreateCall(Fn, Addr, "larx");
3125
3126 return Builder.CreateBitCast(Call, Ty);
31193127 }
31203128
31213129 /// Perform a store-conditional operation to Addr. Return the status of the
31263134 Module *M = BB->getParent()->getParent();
31273135 Type *Ty = Val->getType();
31283136 unsigned SZ = Ty->getPrimitiveSizeInBits();
3137
3138 Type *CastTy = Builder.getIntNTy(SZ);
31293139 assert((SZ == 32 || SZ == 64) && "Only 32/64-bit atomic stores supported");
31303140 Intrinsic::ID IntID = (SZ == 32) ? Intrinsic::hexagon_S2_storew_locked
31313141 : Intrinsic::hexagon_S4_stored_locked;
31323142 Value *Fn = Intrinsic::getDeclaration(M, IntID);
3143
3144 unsigned AS = Addr->getType()->getPointerAddressSpace();
3145 Addr = Builder.CreateBitCast(Addr, CastTy->getPointerTo(AS));
3146 Val = Builder.CreateBitCast(Val, CastTy);
3147
31333148 Value *Call = Builder.CreateCall(Fn, {Addr, Val}, "stcx");
31343149 Value *Cmp = Builder.CreateICmpEQ(Call, Builder.getInt32(0), "");
31353150 Value *Ext = Builder.CreateZExt(Cmp, Type::getInt32Ty(M->getContext()));
18221822 TargetLowering::AtomicExpansionKind
18231823 RISCVTargetLowering::shouldExpandAtomicCmpXchgInIR(
18241824 AtomicCmpXchgInst *CI) const {
1825 if (CI->isFloatingPointOperation())
1826 return AtomicExpansionKind::CmpXChg;
1827
18251828 unsigned Size = CI->getCompareOperand()->getType()->getPrimitiveSizeInBits();
18261829 if (Size == 8 || Size == 16)
18271830 return AtomicExpansionKind::MaskedIntrinsic;
3838 fence syncscope("device") seq_cst
3939 ret void
4040 }
41
42 define void @fp_atomics(float* %x) {
43 ; CHECK: atomicrmw fadd float* %x, float 1.000000e+00 seq_cst
44 atomicrmw fadd float* %x, float 1.0 seq_cst
45
46 ; CHECK: atomicrmw volatile fadd float* %x, float 1.000000e+00 seq_cst
47 atomicrmw volatile fadd float* %x, float 1.0 seq_cst
48
49 ret void
50 }
0 ; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
1
2 ; CHECK: error: atomicrmw fadd operand must be a floating point type
3 define void @f(i32* %ptr) {
4 atomicrmw fadd i32* %ptr, i32 2 seq_cst
5 ret void
6 }
0 ; RUN: not llvm-as -disable-output %s 2>&1 | FileCheck %s
1
2 ; CHECK: error: atomicrmw fsub operand must be a floating point type
3 define void @f(i32* %ptr) {
4 atomicrmw fsub i32* %ptr, i32 2 seq_cst
5 ret void
6 }
763763 define void @fp_atomics(float* %word) {
764764 ; CHECK: %atomicrmw.xchg = atomicrmw xchg float* %word, float 1.000000e+00 monotonic
765765 %atomicrmw.xchg = atomicrmw xchg float* %word, float 1.0 monotonic
766
767 ; CHECK: %atomicrmw.fadd = atomicrmw fadd float* %word, float 1.000000e+00 monotonic
768 %atomicrmw.fadd = atomicrmw fadd float* %word, float 1.0 monotonic
769
770 ; CHECK: %atomicrmw.fsub = atomicrmw fsub float* %word, float 1.000000e+00 monotonic
771 %atomicrmw.fsub = atomicrmw fsub float* %word, float 1.0 monotonic
772
766773 ret void
767774 }
768775
0 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
1 ; RUN: opt -S -mtriple=aarch64-linux-gnu -atomic-expand %s | FileCheck %s
2
3 define float @test_atomicrmw_fadd_f32(float* %ptr, float %value) {
4 ; CHECK-LABEL: @test_atomicrmw_fadd_f32(
5 ; CHECK-NEXT: [[TMP1:%.*]] = load float, float* [[PTR:%.*]], align 4
6 ; CHECK-NEXT: br label [[ATOMICRMW_START:%.*]]
7 ; CHECK: atomicrmw.start:
8 ; CHECK-NEXT: [[LOADED:%.*]] = phi float [ [[TMP1]], [[TMP0:%.*]] ], [ [[TMP6:%.*]], [[ATOMICRMW_START]] ]
9 ; CHECK-NEXT: [[NEW:%.*]] = fadd float [[LOADED]], [[VALUE:%.*]]
10 ; CHECK-NEXT: [[TMP2:%.*]] = bitcast float* [[PTR]] to i32*
11 ; CHECK-NEXT: [[TMP3:%.*]] = bitcast float [[NEW]] to i32
12 ; CHECK-NEXT: [[TMP4:%.*]] = bitcast float [[LOADED]] to i32
13 ; CHECK-NEXT: [[TMP5:%.*]] = cmpxchg i32* [[TMP2]], i32 [[TMP4]], i32 [[TMP3]] seq_cst seq_cst
14 ; CHECK-NEXT: [[SUCCESS:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1
15 ; CHECK-NEXT: [[NEWLOADED:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0
16 ; CHECK-NEXT: [[TMP6]] = bitcast i32 [[NEWLOADED]] to float
17 ; CHECK-NEXT: br i1 [[SUCCESS]], label [[ATOMICRMW_END:%.*]], label [[ATOMICRMW_START]]
18 ; CHECK: atomicrmw.end:
19 ; CHECK-NEXT: ret float [[TMP6]]
20 ;
21 %res = atomicrmw fadd float* %ptr, float %value seq_cst
22 ret float %res
23 }
24
25 define float @test_atomicrmw_fsub_f32(float* %ptr, float %value) {
26 ; CHECK-LABEL: @test_atomicrmw_fsub_f32(
27 ; CHECK-NEXT: [[TMP1:%.*]] = load float, float* [[PTR:%.*]], align 4
28 ; CHECK-NEXT: br label [[ATOMICRMW_START:%.*]]
29 ; CHECK: atomicrmw.start:
30 ; CHECK-NEXT: [[LOADED:%.*]] = phi float [ [[TMP1]], [[TMP0:%.*]] ], [ [[TMP6:%.*]], [[ATOMICRMW_START]] ]
31 ; CHECK-NEXT: [[NEW:%.*]] = fsub float [[LOADED]], [[VALUE:%.*]]
32 ; CHECK-NEXT: [[TMP2:%.*]] = bitcast float* [[PTR]] to i32*
33 ; CHECK-NEXT: [[TMP3:%.*]] = bitcast float [[NEW]] to i32
34 ; CHECK-NEXT: [[TMP4:%.*]] = bitcast float [[LOADED]] to i32
35 ; CHECK-NEXT: [[TMP5:%.*]] = cmpxchg i32* [[TMP2]], i32 [[TMP4]], i32 [[TMP3]] seq_cst seq_cst
36 ; CHECK-NEXT: [[SUCCESS:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1
37 ; CHECK-NEXT: [[NEWLOADED:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0
38 ; CHECK-NEXT: [[TMP6]] = bitcast i32 [[NEWLOADED]] to float
39 ; CHECK-NEXT: br i1 [[SUCCESS]], label [[ATOMICRMW_END:%.*]], label [[ATOMICRMW_START]]
40 ; CHECK: atomicrmw.end:
41 ; CHECK-NEXT: ret float [[TMP6]]
42 ;
43 %res = atomicrmw fsub float* %ptr, float %value seq_cst
44 ret float %res
45 }
46
0 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
1 ; RUN: opt -S -mtriple=armv7-apple-ios7.0 -atomic-expand %s | FileCheck %s
2
3 define float @test_atomicrmw_fadd_f32(float* %ptr, float %value) {
4 ; CHECK-LABEL: @test_atomicrmw_fadd_f32(
5 ; CHECK-NEXT: call void @llvm.arm.dmb(i32 11)
6 ; CHECK-NEXT: [[TMP1:%.*]] = load float, float* [[PTR:%.*]], align 4
7 ; CHECK-NEXT: br label [[ATOMICRMW_START:%.*]]
8 ; CHECK: atomicrmw.start:
9 ; CHECK-NEXT: [[LOADED:%.*]] = phi float [ [[TMP1]], [[TMP0:%.*]] ], [ [[TMP6:%.*]], [[ATOMICRMW_START]] ]
10 ; CHECK-NEXT: [[NEW:%.*]] = fadd float [[LOADED]], [[VALUE:%.*]]
11 ; CHECK-NEXT: [[TMP2:%.*]] = bitcast float* [[PTR]] to i32*
12 ; CHECK-NEXT: [[TMP3:%.*]] = bitcast float [[NEW]] to i32
13 ; CHECK-NEXT: [[TMP4:%.*]] = bitcast float [[LOADED]] to i32
14 ; CHECK-NEXT: [[TMP5:%.*]] = cmpxchg i32* [[TMP2]], i32 [[TMP4]], i32 [[TMP3]] monotonic monotonic
15 ; CHECK-NEXT: [[SUCCESS:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1
16 ; CHECK-NEXT: [[NEWLOADED:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0
17 ; CHECK-NEXT: [[TMP6]] = bitcast i32 [[NEWLOADED]] to float
18 ; CHECK-NEXT: br i1 [[SUCCESS]], label [[ATOMICRMW_END:%.*]], label [[ATOMICRMW_START]]
19 ; CHECK: atomicrmw.end:
20 ; CHECK-NEXT: call void @llvm.arm.dmb(i32 11)
21 ; CHECK-NEXT: ret float [[TMP6]]
22 ;
23 %res = atomicrmw fadd float* %ptr, float %value seq_cst
24 ret float %res
25 }
26
27 define float @test_atomicrmw_fsub_f32(float* %ptr, float %value) {
28 ; CHECK-LABEL: @test_atomicrmw_fsub_f32(
29 ; CHECK-NEXT: call void @llvm.arm.dmb(i32 11)
30 ; CHECK-NEXT: [[TMP1:%.*]] = load float, float* [[PTR:%.*]], align 4
31 ; CHECK-NEXT: br label [[ATOMICRMW_START:%.*]]
32 ; CHECK: atomicrmw.start:
33 ; CHECK-NEXT: [[LOADED:%.*]] = phi float [ [[TMP1]], [[TMP0:%.*]] ], [ [[TMP6:%.*]], [[ATOMICRMW_START]] ]
34 ; CHECK-NEXT: [[NEW:%.*]] = fsub float [[LOADED]], [[VALUE:%.*]]
35 ; CHECK-NEXT: [[TMP2:%.*]] = bitcast float* [[PTR]] to i32*
36 ; CHECK-NEXT: [[TMP3:%.*]] = bitcast float [[NEW]] to i32
37 ; CHECK-NEXT: [[TMP4:%.*]] = bitcast float [[LOADED]] to i32
38 ; CHECK-NEXT: [[TMP5:%.*]] = cmpxchg i32* [[TMP2]], i32 [[TMP4]], i32 [[TMP3]] monotonic monotonic
39 ; CHECK-NEXT: [[SUCCESS:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1
40 ; CHECK-NEXT: [[NEWLOADED:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0
41 ; CHECK-NEXT: [[TMP6]] = bitcast i32 [[NEWLOADED]] to float
42 ; CHECK-NEXT: br i1 [[SUCCESS]], label [[ATOMICRMW_END:%.*]], label [[ATOMICRMW_START]]
43 ; CHECK: atomicrmw.end:
44 ; CHECK-NEXT: call void @llvm.arm.dmb(i32 11)
45 ; CHECK-NEXT: ret float [[TMP6]]
46 ;
47 %res = atomicrmw fsub float* %ptr, float %value seq_cst
48 ret float %res
49 }
50
0 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
1 ; RUN: opt -S -mtriple=hexagon-- -atomic-expand %s | FileCheck %s
2
3 define float @test_atomicrmw_fadd_f32(float* %ptr, float %value) {
4 ; CHECK-LABEL: @test_atomicrmw_fadd_f32(
5 ; CHECK-NEXT: br label [[ATOMICRMW_START:%.*]]
6 ; CHECK: atomicrmw.start:
7 ; CHECK-NEXT: [[TMP1:%.*]] = bitcast float* [[PTR:%.*]] to i32*
8 ; CHECK-NEXT: [[LARX:%.*]] = call i32 @llvm.hexagon.L2.loadw.locked(i32* [[TMP1]])
9 ; CHECK-NEXT: [[TMP2:%.*]] = bitcast i32 [[LARX]] to float
10 ; CHECK-NEXT: [[NEW:%.*]] = fadd float [[TMP2]], [[VALUE:%.*]]
11 ; CHECK-NEXT: [[TMP3:%.*]] = bitcast float* [[PTR]] to i32*
12 ; CHECK-NEXT: [[TMP4:%.*]] = bitcast float [[NEW]] to i32
13 ; CHECK-NEXT: [[STCX:%.*]] = call i32 @llvm.hexagon.S2.storew.locked(i32* [[TMP3]], i32 [[TMP4]])
14 ; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[STCX]], 0
15 ; CHECK-NEXT: [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
16 ; CHECK-NEXT: [[TRYAGAIN:%.*]] = icmp ne i32 [[TMP6]], 0
17 ; CHECK-NEXT: br i1 [[TRYAGAIN]], label [[ATOMICRMW_START]], label [[ATOMICRMW_END:%.*]]
18 ; CHECK: atomicrmw.end:
19 ; CHECK-NEXT: ret float [[TMP2]]
20 ;
21 %res = atomicrmw fadd float* %ptr, float %value seq_cst
22 ret float %res
23 }
24
25 define float @test_atomicrmw_fsub_f32(float* %ptr, float %value) {
26 ; CHECK-LABEL: @test_atomicrmw_fsub_f32(
27 ; CHECK-NEXT: br label [[ATOMICRMW_START:%.*]]
28 ; CHECK: atomicrmw.start:
29 ; CHECK-NEXT: [[TMP1:%.*]] = bitcast float* [[PTR:%.*]] to i32*
30 ; CHECK-NEXT: [[LARX:%.*]] = call i32 @llvm.hexagon.L2.loadw.locked(i32* [[TMP1]])
31 ; CHECK-NEXT: [[TMP2:%.*]] = bitcast i32 [[LARX]] to float
32 ; CHECK-NEXT: [[NEW:%.*]] = fsub float [[TMP2]], [[VALUE:%.*]]
33 ; CHECK-NEXT: [[TMP3:%.*]] = bitcast float* [[PTR]] to i32*
34 ; CHECK-NEXT: [[TMP4:%.*]] = bitcast float [[NEW]] to i32
35 ; CHECK-NEXT: [[STCX:%.*]] = call i32 @llvm.hexagon.S2.storew.locked(i32* [[TMP3]], i32 [[TMP4]])
36 ; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i32 [[STCX]], 0
37 ; CHECK-NEXT: [[TMP6:%.*]] = zext i1 [[TMP5]] to i32
38 ; CHECK-NEXT: [[TRYAGAIN:%.*]] = icmp ne i32 [[TMP6]], 0
39 ; CHECK-NEXT: br i1 [[TRYAGAIN]], label [[ATOMICRMW_START]], label [[ATOMICRMW_END:%.*]]
40 ; CHECK: atomicrmw.end:
41 ; CHECK-NEXT: ret float [[TMP2]]
42 ;
43 %res = atomicrmw fsub float* %ptr, float %value seq_cst
44 ret float %res
45 }
46
0 if not 'Hexagon' in config.root.targets:
1 config.unsupported = True
0 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
1 ; RUN: opt -S -mtriple=mips64-mti-linux-gnu -atomic-expand %s | FileCheck %s
2
3 define float @test_atomicrmw_fadd_f32(float* %ptr, float %value) {
4 ; CHECK-LABEL: @test_atomicrmw_fadd_f32(
5 ; CHECK-NEXT: fence seq_cst
6 ; CHECK-NEXT: [[TMP1:%.*]] = load float, float* [[PTR:%.*]], align 4
7 ; CHECK-NEXT: br label [[ATOMICRMW_START:%.*]]
8 ; CHECK: atomicrmw.start:
9 ; CHECK-NEXT: [[LOADED:%.*]] = phi float [ [[TMP1]], [[TMP0:%.*]] ], [ [[TMP6:%.*]], [[ATOMICRMW_START]] ]
10 ; CHECK-NEXT: [[NEW:%.*]] = fadd float [[LOADED]], [[VALUE:%.*]]
11 ; CHECK-NEXT: [[TMP2:%.*]] = bitcast float* [[PTR]] to i32*
12 ; CHECK-NEXT: [[TMP3:%.*]] = bitcast float [[NEW]] to i32
13 ; CHECK-NEXT: [[TMP4:%.*]] = bitcast float [[LOADED]] to i32
14 ; CHECK-NEXT: [[TMP5:%.*]] = cmpxchg i32* [[TMP2]], i32 [[TMP4]], i32 [[TMP3]] monotonic monotonic
15 ; CHECK-NEXT: [[SUCCESS:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1
16 ; CHECK-NEXT: [[NEWLOADED:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0
17 ; CHECK-NEXT: [[TMP6]] = bitcast i32 [[NEWLOADED]] to float
18 ; CHECK-NEXT: br i1 [[SUCCESS]], label [[ATOMICRMW_END:%.*]], label [[ATOMICRMW_START]]
19 ; CHECK: atomicrmw.end:
20 ; CHECK-NEXT: fence seq_cst
21 ; CHECK-NEXT: ret float [[TMP6]]
22 ;
23 %res = atomicrmw fadd float* %ptr, float %value seq_cst
24 ret float %res
25 }
26
27 define float @test_atomicrmw_fsub_f32(float* %ptr, float %value) {
28 ; CHECK-LABEL: @test_atomicrmw_fsub_f32(
29 ; CHECK-NEXT: fence seq_cst
30 ; CHECK-NEXT: [[TMP1:%.*]] = load float, float* [[PTR:%.*]], align 4
31 ; CHECK-NEXT: br label [[ATOMICRMW_START:%.*]]
32 ; CHECK: atomicrmw.start:
33 ; CHECK-NEXT: [[LOADED:%.*]] = phi float [ [[TMP1]], [[TMP0:%.*]] ], [ [[TMP6:%.*]], [[ATOMICRMW_START]] ]
34 ; CHECK-NEXT: [[NEW:%.*]] = fsub float [[LOADED]], [[VALUE:%.*]]
35 ; CHECK-NEXT: [[TMP2:%.*]] = bitcast float* [[PTR]] to i32*
36 ; CHECK-NEXT: [[TMP3:%.*]] = bitcast float [[NEW]] to i32
37 ; CHECK-NEXT: [[TMP4:%.*]] = bitcast float [[LOADED]] to i32
38 ; CHECK-NEXT: [[TMP5:%.*]] = cmpxchg i32* [[TMP2]], i32 [[TMP4]], i32 [[TMP3]] monotonic monotonic
39 ; CHECK-NEXT: [[SUCCESS:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1
40 ; CHECK-NEXT: [[NEWLOADED:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0
41 ; CHECK-NEXT: [[TMP6]] = bitcast i32 [[NEWLOADED]] to float
42 ; CHECK-NEXT: br i1 [[SUCCESS]], label [[ATOMICRMW_END:%.*]], label [[ATOMICRMW_START]]
43 ; CHECK: atomicrmw.end:
44 ; CHECK-NEXT: fence seq_cst
45 ; CHECK-NEXT: ret float [[TMP6]]
46 ;
47 %res = atomicrmw fsub float* %ptr, float %value seq_cst
48 ret float %res
49 }
50
0 if not 'Mips' in config.root.targets:
1 config.unsupported = True
0 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
1 ; RUN: opt -S -mtriple=riscv32-- -atomic-expand %s | FileCheck %s
2
3 define float @test_atomicrmw_fadd_f32(float* %ptr, float %value) {
4 ; CHECK-LABEL: @test_atomicrmw_fadd_f32(
5 ; CHECK-NEXT: [[TMP1:%.*]] = load float, float* [[PTR:%.*]], align 4
6 ; CHECK-NEXT: br label [[ATOMICRMW_START:%.*]]
7 ; CHECK: atomicrmw.start:
8 ; CHECK-NEXT: [[LOADED:%.*]] = phi float [ [[TMP1]], [[TMP0:%.*]] ], [ [[TMP6:%.*]], [[ATOMICRMW_START]] ]
9 ; CHECK-NEXT: [[NEW:%.*]] = fadd float [[LOADED]], [[VALUE:%.*]]
10 ; CHECK-NEXT: [[TMP2:%.*]] = bitcast float* [[PTR]] to i32*
11 ; CHECK-NEXT: [[TMP3:%.*]] = bitcast float [[NEW]] to i32
12 ; CHECK-NEXT: [[TMP4:%.*]] = bitcast float [[LOADED]] to i32
13 ; CHECK-NEXT: [[TMP5:%.*]] = cmpxchg i32* [[TMP2]], i32 [[TMP4]], i32 [[TMP3]] seq_cst seq_cst
14 ; CHECK-NEXT: [[SUCCESS:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1
15 ; CHECK-NEXT: [[NEWLOADED:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0
16 ; CHECK-NEXT: [[TMP6]] = bitcast i32 [[NEWLOADED]] to float
17 ; CHECK-NEXT: br i1 [[SUCCESS]], label [[ATOMICRMW_END:%.*]], label [[ATOMICRMW_START]]
18 ; CHECK: atomicrmw.end:
19 ; CHECK-NEXT: ret float [[TMP6]]
20 ;
21 %res = atomicrmw fadd float* %ptr, float %value seq_cst
22 ret float %res
23 }
24
25 define float @test_atomicrmw_fsub_f32(float* %ptr, float %value) {
26 ; CHECK-LABEL: @test_atomicrmw_fsub_f32(
27 ; CHECK-NEXT: [[TMP1:%.*]] = load float, float* [[PTR:%.*]], align 4
28 ; CHECK-NEXT: br label [[ATOMIxbCRMW_START:%.*]]
29 ; CHECK: atomicrmw.start:
30 ; CHECK-NEXT: [[LOADED:%.*]] = phi float [ [[TMP1]], [[TMP0:%.*]] ], [ [[TMP6:%.*]], [[ATOMICRMW_START]] ]
31 ; CHECK-NEXT: [[NEW:%.*]] = fsub float [[LOADED]], [[VALUE:%.*]]
32 ; CHECK-NEXT: [[TMP2:%.*]] = bitcast float* [[PTR]] to i32*
33 ; CHECK-NEXT: [[TMP3:%.*]] = bitcast float [[NEW]] to i32
34 ; CHECK-NEXT: [[TMP4:%.*]] = bitcast float [[LOADED]] to i32
35 ; CHECK-NEXT: [[TMP5:%.*]] = cmpxchg i32* [[TMP2]], i32 [[TMP4]], i32 [[TMP3]] seq_cst seq_cst
36 ; CHECK-NEXT: [[SUCCESS:%.*]] = extractvalue { i32, i1 } [[TMP5]], 1
37 ; CHECK-NEXT: [[NEWLOADED:%.*]] = extractvalue { i32, i1 } [[TMP5]], 0
38 ; CHECK-NEXT: [[TMP6]] = bitcast i32 [[NEWLOADED]] to float
39 ; CHECK-NEXT: br i1 [[SUCCESS]], label [[ATOMICRMW_END:%.*]], label [[ATOMICRMW_START]]
40 ; CHECK: atomicrmw.end:
41 ; CHECK-NEXT: ret float [[TMP6]]
42 ;
43 %res = atomicrmw fsub float* %ptr, float %value seq_cst
44 ret float %res
45 }
46
0 config.suffixes = ['.ll']
1
2 targets = set(config.root.targets_to_build.split())
3 if not 'RISCV' in targets:
4 config.unsupported = True