xref: /llvm-project/llvm/lib/Frontend/Atomic/Atomic.cpp (revision 24fc8f01a40310e91838ab742b4940369786ba90)
1 //===--- Atomic.cpp - Codegen of atomic operations ------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "llvm/Frontend/Atomic/Atomic.h"
10 #include "llvm/IR/DerivedTypes.h"
11 #include "llvm/IR/IRBuilder.h"
12 #include <utility>
13 
14 using namespace llvm;
15 
16 bool AtomicInfo::shouldCastToInt(Type *ValTy, bool CmpXchg) {
17   if (ValTy->isFloatingPointTy())
18     return ValTy->isX86_FP80Ty() || CmpXchg;
19   return !ValTy->isIntegerTy() && !ValTy->isPointerTy();
20 }
21 
22 Value *AtomicInfo::EmitAtomicLoadOp(AtomicOrdering AO, bool IsVolatile,
23                                     bool CmpXchg) {
24   Value *Ptr = getAtomicPointer();
25   Type *AtomicTy = Ty;
26   if (shouldCastToInt(Ty, CmpXchg))
27     AtomicTy = IntegerType::get(getLLVMContext(), AtomicSizeInBits);
28   LoadInst *Load =
29       Builder->CreateAlignedLoad(AtomicTy, Ptr, AtomicAlign, "atomic-load");
30   Load->setAtomic(AO);
31   if (IsVolatile)
32     Load->setVolatile(true);
33   decorateWithTBAA(Load);
34   return Load;
35 }
36 
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();
45 
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);
54   return Call;
55 }
56 
57 std::pair<Value *, Value *> AtomicInfo::EmitAtomicCompareExchangeLibcall(
58     Value *ExpectedVal, Value *DesiredVal, AtomicOrdering Success,
59     AtomicOrdering Failure) {
60   LLVMContext &ctx = getLLVMContext();
61 
62   // __atomic_compare_exchange's expected and desired are passed by pointers
63   // FIXME: types
64 
65   // TODO: Get from llvm::TargetMachine / clang::TargetInfo
66   // if clang shares this codegen in future
67   constexpr uint64_t IntBits = 32;
68 
69   // bool __atomic_compare_exchange(size_t size, void *obj, void *expected,
70   //  void *desired, int success, int failure);
71 
72   Value *Args[6] = {
73       getAtomicSizeValue(),
74       getAtomicPointer(),
75       ExpectedVal,
76       DesiredVal,
77       Constant::getIntegerValue(IntegerType::get(ctx, IntBits),
78                                 APInt(IntBits, static_cast<uint64_t>(Success),
79                                       /*signed=*/true)),
80       Constant::getIntegerValue(IntegerType::get(ctx, IntBits),
81                                 APInt(IntBits, static_cast<uint64_t>(Failure),
82                                       /*signed=*/true)),
83   };
84   auto Result = EmitAtomicLibcall("__atomic_compare_exchange",
85                                   IntegerType::getInt1Ty(ctx), Args);
86   return std::make_pair(ExpectedVal, Result);
87 }
88 
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);
97 
98   // Other decoration.
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);
104 }
105 
106 std::pair<LoadInst *, AllocaInst *>
107 AtomicInfo::EmitAtomicLoadLibcall(AtomicOrdering AO) {
108   LLVMContext &Ctx = getLLVMContext();
109   Type *SizedIntTy = Type::getIntNTy(Ctx, getAtomicSizeInBits());
110   Type *ResultTy;
111   SmallVector<Value *, 6> Args;
112   AttributeList Attr;
113   Module *M = Builder->GetInsertBlock()->getModule();
114   const DataLayout &DL = M->getDataLayout();
115   Args.push_back(
116       ConstantInt::get(DL.getIntPtrType(Ctx), this->getAtomicSizeInBits() / 8));
117 
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);
129 
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),
141       AllocaResult);
142 }
143 
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,
149                                             Failure);
150 
151   auto Res = EmitAtomicCompareExchangeOp(ExpectedVal, DesiredVal, Success,
152                                          Failure, IsVolatile, IsWeak);
153   return Res;
154 }
155