Skip to content

Commit

Permalink
[CIR][CIRGen] Support for builtin __atomic_thread_fence
Browse files Browse the repository at this point in the history
Resolves llvm#1274

Implements atomic thread fence synchronization primitive
corresponding to `atomic.thread_fence` CIR.
  • Loading branch information
Rajveer100 committed Jan 28, 2025
1 parent 3c3b096 commit ca75a57
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 1 deletion.
41 changes: 41 additions & 0 deletions clang/include/clang/CIR/Dialect/IR/CIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -5409,6 +5409,47 @@ def AtomicCmpXchg : CIR_Op<"atomic.cmp_xchg",
let hasVerifier = 0;
}

def MemScope_SingleThread : I32EnumAttrCase<"MemScope_SingleThread",
0, "single_thread">;
def MemScope_System : I32EnumAttrCase<"MemScope_System",
1, "system">;

def MemScopeKind : I32EnumAttr<
"MemScopeKind",
"Memory Scope Enumeration",
[MemScope_SingleThread, MemScope_System]> {
let cppNamespace = "::cir";
}

def AtomicFence : CIR_Op<"atomic.fence"> {
let summary = "Atomic thread fence";
let description = [{
C/C++ Atomic thread fence synchronization primitive. Implements the builtin
`__atomic_thread_fence` which enforces memory ordering constraints across
threads within the specified synchronization scope.

This handles all variations including:
- `__atomic_thread_fence`
- `__atomic_signal_fence`
- `__c11_atomic_thread_fence`
- `__c11_atomic_signal_fence`

Example:


}];
let results = (outs);
let arguments = (ins Arg<MemScopeKind, "sync scope">:$sync_scope,
Arg<MemOrder, "memory order">:$ordering);

let assemblyFormat = [{
`(` `sync_scope` `=` $sync_scope `,`
`ordering` `=` $ordering `)` attr-dict
}];

let hasVerifier = 0;
}

def SignBitOp : CIR_Op<"signbit", [Pure]> {
let summary = "Checks the sign of a floating-point number";
let description = [{
Expand Down
62 changes: 61 additions & 1 deletion clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,10 @@
#include "CIRGenCstEmitter.h"
#include "CIRGenFunction.h"
#include "CIRGenModule.h"
#include "CIRGenValue.h"
#include "TargetInfo.h"
#include "clang/AST/Expr.h"
#include "clang/CIR/Dialect/IR/CIROpsEnums.h"
#include "clang/CIR/MissingFeatures.h"

// TODO(cir): we shouldn't need this but we currently reuse intrinsic IDs for
Expand All @@ -30,6 +33,7 @@
#include "clang/Frontend/FrontendDiagnostic.h"

#include "mlir/Dialect/Func/IR/FuncOps.h"
#include "mlir/IR/BuiltinAttributes.h"
#include "mlir/IR/Value.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"
#include "llvm/Support/ErrorHandling.h"
Expand Down Expand Up @@ -330,6 +334,58 @@ static mlir::Value MakeAtomicCmpXchgValue(CIRGenFunction &cgf,
return returnBool ? op.getResult(1) : op.getResult(0);
}

static mlir::Value MakeAtomicFenceValue(CIRGenFunction &cgf,
const CallExpr *expr,
cir::MemScopeKind syncScope) {
QualType typ = expr->getType();
auto &builder = cgf.getBuilder();

auto intType =
expr->getArg(0)->getType()->getPointeeType()->isUnsignedIntegerType()
? builder.getUIntNTy(cgf.getContext().getTypeSize(typ))
: builder.getSIntNTy(cgf.getContext().getTypeSize(typ));

auto orderingVal =
emitToInt(cgf, cgf.emitScalarExpr(expr->getArg(1)), typ, intType);
auto orderingAttr =
orderingVal.getDefiningOp()->getAttrOfType<mlir::IntegerAttr>("value");

cir::MemOrder ordering;
switch (orderingAttr.getInt()) {
case 0: {
ordering = cir::MemOrder::Relaxed;
break;
}
case 1: {
ordering = cir::MemOrder::Consume;
break;
}
case 2: {
ordering = cir::MemOrder::Acquire;
break;
}
case 3: {
ordering = cir::MemOrder::Release;
break;
}
case 4: {
ordering = cir::MemOrder::AcquireRelease;
break;
}
case 5: {
ordering = cir::MemOrder::SequentiallyConsistent;
break;
}
default:
llvm_unreachable("invalid memory ordering scope");
}

builder.create<cir::AtomicFence>(cgf.getLoc(expr->getSourceRange()),
syncScope, ordering);

return mlir::Value();
}

static bool
typeRequiresBuiltinLaunderImp(const ASTContext &astContext, QualType ty,
llvm::SmallPtrSetImpl<const Decl *> &seen) {
Expand Down Expand Up @@ -1840,10 +1896,14 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
llvm_unreachable("BI__atomic_clear NYI");

case Builtin::BI__atomic_thread_fence:
return RValue::get(
MakeAtomicFenceValue(*this, E, cir::MemScopeKind::MemScope_System));
case Builtin::BI__atomic_signal_fence:
return RValue::get(MakeAtomicFenceValue(
*this, E, cir::MemScopeKind::MemScope_SingleThread));
case Builtin::BI__c11_atomic_thread_fence:
case Builtin::BI__c11_atomic_signal_fence:
llvm_unreachable("BI__atomic_thread_fence like NYI");
llvm_unreachable("BI__c11_atomic_thread_fence like NYI");

case Builtin::BI__builtin_signbit:
case Builtin::BI__builtin_signbitf:
Expand Down
11 changes: 11 additions & 0 deletions clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "mlir/IR/MLIRContext.h"
#include "mlir/Interfaces/DataLayoutInterfaces.h"
#include "mlir/Transforms/DialectConversion.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"

namespace cir {
namespace direct {
Expand Down Expand Up @@ -820,6 +821,16 @@ class CIRToLLVMAtomicFetchLowering
mlir::ConversionPatternRewriter &) const override;
};

// class CIRToLLVMAtomicFenceLowering
// : public mlir::OpConversionPattern<cir::AtomicFence> {
// public:
// using mlir::OpConversionPattern<cir::AtomicFence>::OpConversionPattern;
//
// mlir::LogicalResult
// matchAndRewrite(cir::AtomicFence op, OpAdaptor,
// mlir::ConversionPatternRewriter &) const override;
// };

class CIRToLLVMByteswapOpLowering
: public mlir::OpConversionPattern<cir::ByteswapOp> {
public:
Expand Down

0 comments on commit ca75a57

Please sign in to comment.