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