Skip to content

[llvm][OpenMP][NFC] Cleanup AtomicInfo #119199

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 23, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
202 changes: 36 additions & 166 deletions llvm/include/llvm/Frontend/Atomic/Atomic.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
//===--- Atomic.h - Codegen of atomic operations
//---------------------------===//
//===--- Atomic.h - Codegen of atomic operations ------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
Expand All @@ -10,46 +9,39 @@
#ifndef LLVM_FRONTEND_ATOMIC_ATOMIC_H
#define LLVM_FRONTEND_ATOMIC_ATOMIC_H

#include "llvm/ADT/DenseMap.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Instructions.h"
#include "llvm/IR/Intrinsics.h"
#include "llvm/IR/IRBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/IR/Operator.h"
#include "llvm/IR/RuntimeLibcalls.h"

namespace llvm {

template <typename IRBuilderTy> struct AtomicInfo {

IRBuilderTy *Builder;
class AtomicInfo {
protected:
IRBuilderBase *Builder;
Type *Ty;
uint64_t AtomicSizeInBits;
uint64_t ValueSizeInBits;
llvm::Align AtomicAlign;
llvm::Align ValueAlign;
Align AtomicAlign;
Align ValueAlign;
bool UseLibcall;

public:
AtomicInfo(IRBuilderTy *Builder, Type *Ty, uint64_t AtomicSizeInBits,
uint64_t ValueSizeInBits, llvm::Align AtomicAlign,
llvm::Align ValueAlign, bool UseLibcall)
AtomicInfo(IRBuilderBase *Builder, Type *Ty, uint64_t AtomicSizeInBits,
uint64_t ValueSizeInBits, Align AtomicAlign, Align ValueAlign,
bool UseLibcall)
: Builder(Builder), Ty(Ty), AtomicSizeInBits(AtomicSizeInBits),
ValueSizeInBits(ValueSizeInBits), AtomicAlign(AtomicAlign),
ValueAlign(ValueAlign), UseLibcall(UseLibcall) {}

virtual ~AtomicInfo() = default;

llvm::Align getAtomicAlignment() const { return AtomicAlign; }
Align getAtomicAlignment() const { return AtomicAlign; }
uint64_t getAtomicSizeInBits() const { return AtomicSizeInBits; }
uint64_t getValueSizeInBits() const { return ValueSizeInBits; }
bool shouldUseLibcall() const { return UseLibcall; }
llvm::Type *getAtomicTy() const { return Ty; }
Type *getAtomicTy() const { return Ty; }

virtual llvm::Value *getAtomicPointer() const = 0;
virtual Value *getAtomicPointer() const = 0;
virtual void decorateWithTBAA(Instruction *I) = 0;
virtual llvm::AllocaInst *CreateAlloca(llvm::Type *Ty,
const llvm::Twine &Name) const = 0;
virtual AllocaInst *CreateAlloca(Type *Ty, const Twine &Name) const = 0;

/*
* Is the atomic size larger than the underlying value type?
Expand All @@ -62,90 +54,28 @@ template <typename IRBuilderTy> struct AtomicInfo {

LLVMContext &getLLVMContext() const { return Builder->getContext(); }

static bool shouldCastToInt(llvm::Type *ValTy, bool CmpXchg) {
if (ValTy->isFloatingPointTy())
return ValTy->isX86_FP80Ty() || CmpXchg;
return !ValTy->isIntegerTy() && !ValTy->isPointerTy();
}
bool shouldCastToInt(Type *ValTy, bool CmpXchg);

llvm::Value *EmitAtomicLoadOp(llvm::AtomicOrdering AO, bool IsVolatile,
bool CmpXchg = false) {
Value *Ptr = getAtomicPointer();
Type *AtomicTy = Ty;
if (shouldCastToInt(Ty, CmpXchg))
AtomicTy = llvm::IntegerType::get(getLLVMContext(), AtomicSizeInBits);
LoadInst *Load =
Builder->CreateAlignedLoad(AtomicTy, Ptr, AtomicAlign, "atomic-load");
Load->setAtomic(AO);
if (IsVolatile)
Load->setVolatile(true);
decorateWithTBAA(Load);
return Load;
}
Value *EmitAtomicLoadOp(AtomicOrdering AO, bool IsVolatile,
bool CmpXchg = false);

static CallInst *EmitAtomicLibcall(IRBuilderTy *Builder, StringRef fnName,
Type *ResultType, ArrayRef<Value *> Args) {
LLVMContext &ctx = Builder->getContext();
SmallVector<Type *, 6> ArgTys;
for (Value *Arg : Args)
ArgTys.push_back(Arg->getType());
FunctionType *FnType = FunctionType::get(ResultType, ArgTys, false);
Module *M = Builder->GetInsertBlock()->getModule();

// TODO: Use llvm::TargetLowering for Libcall ABI
llvm::AttrBuilder fnAttrBuilder(ctx);
fnAttrBuilder.addAttribute(llvm::Attribute::NoUnwind);
fnAttrBuilder.addAttribute(llvm::Attribute::WillReturn);
llvm::AttributeList fnAttrs = llvm::AttributeList::get(
ctx, llvm::AttributeList::FunctionIndex, fnAttrBuilder);
FunctionCallee LibcallFn = M->getOrInsertFunction(fnName, FnType, fnAttrs);
CallInst *Call = Builder->CreateCall(LibcallFn, Args);
return Call;
}
CallInst *EmitAtomicLibcall(StringRef fnName, Type *ResultType,
ArrayRef<Value *> Args);

llvm::Value *getAtomicSizeValue() const {
Value *getAtomicSizeValue() const {
LLVMContext &ctx = getLLVMContext();

// TODO: Get from llvm::TargetMachine / clang::TargetInfo
// if clang shares this codegen in future
// if clang shares this codegen in future
constexpr uint16_t SizeTBits = 64;
constexpr uint16_t BitsPerByte = 8;
return llvm::ConstantInt::get(llvm::IntegerType::get(ctx, SizeTBits),
AtomicSizeInBits / BitsPerByte);
return ConstantInt::get(IntegerType::get(ctx, SizeTBits),
AtomicSizeInBits / BitsPerByte);
}

std::pair<llvm::Value *, llvm::Value *> EmitAtomicCompareExchangeLibcall(
llvm::Value *ExpectedVal, llvm::Value *DesiredVal,
llvm::AtomicOrdering Success, llvm::AtomicOrdering Failure) {
LLVMContext &ctx = getLLVMContext();

// __atomic_compare_exchange's expected and desired are passed by pointers
// FIXME: types

// TODO: Get from llvm::TargetMachine / clang::TargetInfo
// if clang shares this codegen in future
constexpr uint64_t IntBits = 32;

// bool __atomic_compare_exchange(size_t size, void *obj, void *expected,
// void *desired, int success, int failure);
llvm::Value *Args[6] = {
getAtomicSizeValue(),
getAtomicPointer(),
ExpectedVal,
DesiredVal,
llvm::Constant::getIntegerValue(
llvm::IntegerType::get(ctx, IntBits),
llvm::APInt(IntBits, static_cast<uint64_t>(Success),
/*signed=*/true)),
llvm::Constant::getIntegerValue(
llvm::IntegerType::get(ctx, IntBits),
llvm::APInt(IntBits, static_cast<uint64_t>(Failure),
/*signed=*/true)),
};
auto Result = EmitAtomicLibcall(Builder, "__atomic_compare_exchange",
llvm::IntegerType::getInt1Ty(ctx), Args);
return std::make_pair(ExpectedVal, Result);
}
std::pair<Value *, Value *>
EmitAtomicCompareExchangeLibcall(Value *ExpectedVal, Value *DesiredVal,
AtomicOrdering Success,
AtomicOrdering Failure);

Value *castToAtomicIntPointer(Value *addr) const {
return addr; // opaque pointer
Expand All @@ -155,77 +85,17 @@ template <typename IRBuilderTy> struct AtomicInfo {
return castToAtomicIntPointer(getAtomicPointer());
}

std::pair<llvm::Value *, llvm::Value *>
EmitAtomicCompareExchangeOp(llvm::Value *ExpectedVal, llvm::Value *DesiredVal,
llvm::AtomicOrdering Success,
llvm::AtomicOrdering Failure,
bool IsVolatile = false, bool IsWeak = false) {
// Do the atomic store.
Value *Addr = getAtomicAddressAsAtomicIntPointer();
auto *Inst = Builder->CreateAtomicCmpXchg(Addr, ExpectedVal, DesiredVal,
getAtomicAlignment(), Success,
Failure, llvm::SyncScope::System);
// Other decoration.
Inst->setVolatile(IsVolatile);
Inst->setWeak(IsWeak);

auto *PreviousVal = Builder->CreateExtractValue(Inst, /*Idxs=*/0);
auto *SuccessFailureVal = Builder->CreateExtractValue(Inst, /*Idxs=*/1);
return std::make_pair(PreviousVal, SuccessFailureVal);
}
std::pair<Value *, Value *>
EmitAtomicCompareExchangeOp(Value *ExpectedVal, Value *DesiredVal,
AtomicOrdering Success, AtomicOrdering Failure,
bool IsVolatile = false, bool IsWeak = false);

std::pair<llvm::Value *, llvm::Value *>
EmitAtomicCompareExchange(llvm::Value *ExpectedVal, llvm::Value *DesiredVal,
llvm::AtomicOrdering Success,
llvm::AtomicOrdering Failure, bool IsVolatile,
bool IsWeak) {
if (shouldUseLibcall())
return EmitAtomicCompareExchangeLibcall(ExpectedVal, DesiredVal, Success,
Failure);

auto Res = EmitAtomicCompareExchangeOp(ExpectedVal, DesiredVal, Success,
Failure, IsVolatile, IsWeak);
return Res;
}
std::pair<Value *, Value *>
EmitAtomicCompareExchange(Value *ExpectedVal, Value *DesiredVal,
AtomicOrdering Success, AtomicOrdering Failure,
bool IsVolatile, bool IsWeak);

// void __atomic_load(size_t size, void *mem, void *return, int order);
std::pair<llvm::LoadInst *, llvm::AllocaInst *>
EmitAtomicLoadLibcall(llvm::AtomicOrdering AO) {
LLVMContext &Ctx = getLLVMContext();
Type *SizedIntTy = Type::getIntNTy(Ctx, getAtomicSizeInBits());
Type *ResultTy;
SmallVector<Value *, 6> Args;
AttributeList Attr;
Module *M = Builder->GetInsertBlock()->getModule();
const DataLayout &DL = M->getDataLayout();
Args.push_back(ConstantInt::get(DL.getIntPtrType(Ctx),
this->getAtomicSizeInBits() / 8));

Value *PtrVal = getAtomicPointer();
PtrVal = Builder->CreateAddrSpaceCast(PtrVal, PointerType::getUnqual(Ctx));
Args.push_back(PtrVal);
AllocaInst *AllocaResult =
CreateAlloca(Ty, getAtomicPointer()->getName() + "atomic.temp.load");
const Align AllocaAlignment = DL.getPrefTypeAlign(SizedIntTy);
AllocaResult->setAlignment(AllocaAlignment);
Args.push_back(AllocaResult);
Constant *OrderingVal =
ConstantInt::get(Type::getInt32Ty(Ctx), (int)toCABI(AO));
Args.push_back(OrderingVal);

ResultTy = Type::getVoidTy(Ctx);
SmallVector<Type *, 6> ArgTys;
for (Value *Arg : Args)
ArgTys.push_back(Arg->getType());
FunctionType *FnType = FunctionType::get(ResultTy, ArgTys, false);
FunctionCallee LibcallFn =
M->getOrInsertFunction("__atomic_load", FnType, Attr);
CallInst *Call = Builder->CreateCall(LibcallFn, Args);
Call->setAttributes(Attr);
return std::make_pair(
Builder->CreateAlignedLoad(Ty, AllocaResult, AllocaAlignment),
AllocaResult);
}
std::pair<LoadInst *, AllocaInst *> EmitAtomicLoadLibcall(AtomicOrdering AO);
};
} // end namespace llvm

Expand Down
16 changes: 3 additions & 13 deletions llvm/include/llvm/Frontend/OpenMP/OMPIRBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -480,16 +480,15 @@ class OpenMPIRBuilder {
T(Triple(M.getTargetTriple())) {}
~OpenMPIRBuilder();

class AtomicInfo : public llvm::AtomicInfo<IRBuilder<>> {
class AtomicInfo : public llvm::AtomicInfo {
llvm::Value *AtomicVar;

public:
AtomicInfo(IRBuilder<> *Builder, llvm::Type *Ty, uint64_t AtomicSizeInBits,
uint64_t ValueSizeInBits, llvm::Align AtomicAlign,
llvm::Align ValueAlign, bool UseLibcall, llvm::Value *AtomicVar)
: llvm::AtomicInfo<IRBuilder<>>(Builder, Ty, AtomicSizeInBits,
ValueSizeInBits, AtomicAlign,
ValueAlign, UseLibcall),
: llvm::AtomicInfo(Builder, Ty, AtomicSizeInBits, ValueSizeInBits,
AtomicAlign, ValueAlign, UseLibcall),
AtomicVar(AtomicVar) {}

llvm::Value *getAtomicPointer() const override { return AtomicVar; }
Expand Down Expand Up @@ -3095,15 +3094,6 @@ class OpenMPIRBuilder {
AtomicUpdateCallbackTy &UpdateOp, bool VolatileX,
bool IsXBinopExpr);

std::pair<llvm::LoadInst *, llvm::AllocaInst *>
EmitAtomicLoadLibcall(Value *X, Type *XElemTy, llvm::AtomicOrdering AO,
uint64_t AtomicSizeInBits);

std::pair<llvm::Value *, llvm::Value *> EmitAtomicCompareExchangeLibcall(
Value *X, Type *XElemTy, uint64_t AtomicSizeInBits,
llvm::Value *ExpectedVal, llvm::Value *DesiredVal,
llvm::AtomicOrdering Success, llvm::AtomicOrdering Failure);

/// Emit the binary op. described by \p RMWOp, using \p Src1 and \p Src2 .
///
/// \Return The instruction
Expand Down
Loading
Loading