1 //===--- Atomic.cpp - Codegen of atomic operations ------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "llvm/Frontend/Atomic/Atomic.h"
10 #include "llvm/IR/DerivedTypes.h"
11 #include "llvm/IR/IRBuilder.h"
16 bool AtomicInfo::shouldCastToInt(Type
*ValTy
, bool CmpXchg
) {
17 if (ValTy
->isFloatingPointTy())
18 return ValTy
->isX86_FP80Ty() || CmpXchg
;
19 return !ValTy
->isIntegerTy() && !ValTy
->isPointerTy();
22 Value
*AtomicInfo::EmitAtomicLoadOp(AtomicOrdering AO
, bool IsVolatile
,
24 Value
*Ptr
= getAtomicPointer();
26 if (shouldCastToInt(Ty
, CmpXchg
))
27 AtomicTy
= IntegerType::get(getLLVMContext(), AtomicSizeInBits
);
29 Builder
->CreateAlignedLoad(AtomicTy
, Ptr
, AtomicAlign
, "atomic-load");
32 Load
->setVolatile(true);
33 decorateWithTBAA(Load
);
37 CallInst
*AtomicInfo::EmitAtomicLibcall(StringRef fnName
, Type
*ResultType
,
38 ArrayRef
<Value
*> Args
) {
39 LLVMContext
&ctx
= Builder
->getContext();
40 SmallVector
<Type
*, 6> ArgTys
;
41 for (Value
*Arg
: Args
)
42 ArgTys
.push_back(Arg
->getType());
43 FunctionType
*FnType
= FunctionType::get(ResultType
, ArgTys
, false);
44 Module
*M
= Builder
->GetInsertBlock()->getModule();
46 // TODO: Use llvm::TargetLowering for Libcall ABI
47 AttrBuilder
fnAttrBuilder(ctx
);
48 fnAttrBuilder
.addAttribute(Attribute::NoUnwind
);
49 fnAttrBuilder
.addAttribute(Attribute::WillReturn
);
50 AttributeList fnAttrs
=
51 AttributeList::get(ctx
, AttributeList::FunctionIndex
, fnAttrBuilder
);
52 FunctionCallee LibcallFn
= M
->getOrInsertFunction(fnName
, FnType
, fnAttrs
);
53 CallInst
*Call
= Builder
->CreateCall(LibcallFn
, Args
);
57 std::pair
<Value
*, Value
*> AtomicInfo::EmitAtomicCompareExchangeLibcall(
58 Value
*ExpectedVal
, Value
*DesiredVal
, AtomicOrdering Success
,
59 AtomicOrdering Failure
) {
60 LLVMContext
&ctx
= getLLVMContext();
62 // __atomic_compare_exchange's expected and desired are passed by pointers
65 // TODO: Get from llvm::TargetMachine / clang::TargetInfo
66 // if clang shares this codegen in future
67 constexpr uint64_t IntBits
= 32;
69 // bool __atomic_compare_exchange(size_t size, void *obj, void *expected,
70 // void *desired, int success, int failure);
77 Constant::getIntegerValue(IntegerType::get(ctx
, IntBits
),
78 APInt(IntBits
, static_cast<uint64_t>(Success
),
80 Constant::getIntegerValue(IntegerType::get(ctx
, IntBits
),
81 APInt(IntBits
, static_cast<uint64_t>(Failure
),
84 auto Result
= EmitAtomicLibcall("__atomic_compare_exchange",
85 IntegerType::getInt1Ty(ctx
), Args
);
86 return std::make_pair(ExpectedVal
, Result
);
89 std::pair
<Value
*, Value
*> AtomicInfo::EmitAtomicCompareExchangeOp(
90 Value
*ExpectedVal
, Value
*DesiredVal
, AtomicOrdering Success
,
91 AtomicOrdering Failure
, bool IsVolatile
, bool IsWeak
) {
92 // Do the atomic store.
93 Value
*Addr
= getAtomicAddressAsAtomicIntPointer();
94 auto *Inst
= Builder
->CreateAtomicCmpXchg(Addr
, ExpectedVal
, DesiredVal
,
95 getAtomicAlignment(), Success
,
96 Failure
, SyncScope::System
);
99 Inst
->setVolatile(IsVolatile
);
100 Inst
->setWeak(IsWeak
);
101 auto *PreviousVal
= Builder
->CreateExtractValue(Inst
, /*Idxs=*/0);
102 auto *SuccessFailureVal
= Builder
->CreateExtractValue(Inst
, /*Idxs=*/1);
103 return std::make_pair(PreviousVal
, SuccessFailureVal
);
106 std::pair
<LoadInst
*, AllocaInst
*>
107 AtomicInfo::EmitAtomicLoadLibcall(AtomicOrdering AO
) {
108 LLVMContext
&Ctx
= getLLVMContext();
109 Type
*SizedIntTy
= Type::getIntNTy(Ctx
, getAtomicSizeInBits());
111 SmallVector
<Value
*, 6> Args
;
113 Module
*M
= Builder
->GetInsertBlock()->getModule();
114 const DataLayout
&DL
= M
->getDataLayout();
116 ConstantInt::get(DL
.getIntPtrType(Ctx
), this->getAtomicSizeInBits() / 8));
118 Value
*PtrVal
= getAtomicPointer();
119 PtrVal
= Builder
->CreateAddrSpaceCast(PtrVal
, PointerType::getUnqual(Ctx
));
120 Args
.push_back(PtrVal
);
121 AllocaInst
*AllocaResult
=
122 CreateAlloca(Ty
, getAtomicPointer()->getName() + "atomic.temp.load");
123 const Align AllocaAlignment
= DL
.getPrefTypeAlign(SizedIntTy
);
124 AllocaResult
->setAlignment(AllocaAlignment
);
125 Args
.push_back(AllocaResult
);
126 Constant
*OrderingVal
=
127 ConstantInt::get(Type::getInt32Ty(Ctx
), (int)toCABI(AO
));
128 Args
.push_back(OrderingVal
);
130 ResultTy
= Type::getVoidTy(Ctx
);
131 SmallVector
<Type
*, 6> ArgTys
;
132 for (Value
*Arg
: Args
)
133 ArgTys
.push_back(Arg
->getType());
134 FunctionType
*FnType
= FunctionType::get(ResultTy
, ArgTys
, false);
135 FunctionCallee LibcallFn
=
136 M
->getOrInsertFunction("__atomic_load", FnType
, Attr
);
137 CallInst
*Call
= Builder
->CreateCall(LibcallFn
, Args
);
138 Call
->setAttributes(Attr
);
139 return std::make_pair(
140 Builder
->CreateAlignedLoad(Ty
, AllocaResult
, AllocaAlignment
),
144 std::pair
<Value
*, Value
*> AtomicInfo::EmitAtomicCompareExchange(
145 Value
*ExpectedVal
, Value
*DesiredVal
, AtomicOrdering Success
,
146 AtomicOrdering Failure
, bool IsVolatile
, bool IsWeak
) {
147 if (shouldUseLibcall())
148 return EmitAtomicCompareExchangeLibcall(ExpectedVal
, DesiredVal
, Success
,
151 auto Res
= EmitAtomicCompareExchangeOp(ExpectedVal
, DesiredVal
, Success
,
152 Failure
, IsVolatile
, IsWeak
);