[clang] NFC, add a "continue" bailout in the for-loop of
[llvm-project.git] / llvm / lib / Frontend / Atomic / Atomic.cpp
blobc9f9a9dcfb702a7489c6b3f66f8182e42978c396
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 //===----------------------------------------------------------------------===//
9 #include "llvm/Frontend/Atomic/Atomic.h"
10 #include "llvm/IR/DerivedTypes.h"
11 #include "llvm/IR/IRBuilder.h"
12 #include <utility>
14 using namespace llvm;
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,
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;
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);
54 return Call;
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
63 // FIXME: types
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);
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)),
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);
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);
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));
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),
141 AllocaResult);
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);
151 auto Res = EmitAtomicCompareExchangeOp(ExpectedVal, DesiredVal, Success,
152 Failure, IsVolatile, IsWeak);
153 return Res;