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