[llvm] 8708089 - [SPIR-V] Add atomic_flag builtin implementation

Michal Paszkowski via llvm-commits llvm-commits at lists.llvm.org
Wed Dec 21 14:00:46 PST 2022


Author: Michal Paszkowski
Date: 2022-12-21T22:59:18+01:00
New Revision: 8708089896767fe8bcaf95b24ff7b472d928a65f

URL: https://github.com/llvm/llvm-project/commit/8708089896767fe8bcaf95b24ff7b472d928a65f
DIFF: https://github.com/llvm/llvm-project/commit/8708089896767fe8bcaf95b24ff7b472d928a65f.diff

LOG: [SPIR-V] Add atomic_flag builtin implementation

This change provides implementation details for atomic_flag builtins and
adds an extended atomic_flag.ll test from the LLVM SPIR-V Translator.

Differential Revision: https://reviews.llvm.org/D136310

Added: 
    llvm/test/CodeGen/SPIRV/transcoding/atomic_flag.ll

Modified: 
    llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
    llvm/lib/Target/SPIRV/SPIRVBuiltins.td

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
index 3ebb60b58ced5..89c25e750a52a 100644
--- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.cpp
@@ -416,6 +416,36 @@ static Register buildConstantIntReg(uint64_t Val, MachineIRBuilder &MIRBuilder,
   return GR->buildConstantInt(Val, MIRBuilder, IntType);
 }
 
+static Register buildScopeReg(Register CLScopeRegister,
+                              MachineIRBuilder &MIRBuilder,
+                              SPIRVGlobalRegistry *GR,
+                              const MachineRegisterInfo *MRI) {
+  auto CLScope =
+      static_cast<SPIRV::CLMemoryScope>(getIConstVal(CLScopeRegister, MRI));
+  SPIRV::Scope::Scope Scope = getSPIRVScope(CLScope);
+
+  if (CLScope == static_cast<unsigned>(Scope))
+    return CLScopeRegister;
+
+  return buildConstantIntReg(Scope, MIRBuilder, GR);
+}
+
+static Register buildMemSemanticsReg(Register SemanticsRegister,
+                                     Register PtrRegister,
+                                     const MachineRegisterInfo *MRI,
+                                     SPIRVGlobalRegistry *GR) {
+  std::memory_order Order =
+      static_cast<std::memory_order>(getIConstVal(SemanticsRegister, MRI));
+  unsigned Semantics =
+      getSPIRVMemSemantics(Order) |
+      getMemSemanticsForStorageClass(GR->getPointerStorageClass(PtrRegister));
+
+  if (Order == Semantics)
+    return SemanticsRegister;
+
+  return Register();
+}
+
 /// Helper function for translating atomic init to OpStore.
 static bool buildAtomicInitInst(const SPIRV::IncomingCall *Call,
                                 MachineIRBuilder &MIRBuilder) {
@@ -585,31 +615,26 @@ static bool buildAtomicRMWInst(const SPIRV::IncomingCall *Call, unsigned Opcode,
                                MachineIRBuilder &MIRBuilder,
                                SPIRVGlobalRegistry *GR) {
   const MachineRegisterInfo *MRI = MIRBuilder.getMRI();
-  Register ScopeRegister;
   SPIRV::Scope::Scope Scope = SPIRV::Scope::Workgroup;
+  Register ScopeRegister;
+
   if (Call->Arguments.size() >= 4) {
-    assert(Call->Arguments.size() == 4 && "Extra args for explicit atomic RMW");
-    auto CLScope = static_cast<SPIRV::CLMemoryScope>(
-        getIConstVal(Call->Arguments[3], MRI));
-    Scope = getSPIRVScope(CLScope);
-    if (CLScope == static_cast<unsigned>(Scope))
-      ScopeRegister = Call->Arguments[3];
+    assert(Call->Arguments.size() == 4 &&
+           "Too many args for explicit atomic RMW");
+    ScopeRegister = buildScopeReg(Call->Arguments[3], MIRBuilder, GR, MRI);
   }
+
   if (!ScopeRegister.isValid())
     ScopeRegister = buildConstantIntReg(Scope, MIRBuilder, GR);
 
   Register PtrRegister = Call->Arguments[0];
-  Register MemSemanticsReg;
   unsigned Semantics = SPIRV::MemorySemantics::None;
-  if (Call->Arguments.size() >= 3) {
-    std::memory_order Order =
-        static_cast<std::memory_order>(getIConstVal(Call->Arguments[2], MRI));
-    Semantics =
-        getSPIRVMemSemantics(Order) |
-        getMemSemanticsForStorageClass(GR->getPointerStorageClass(PtrRegister));
-    if (Order == Semantics)
-      MemSemanticsReg = Call->Arguments[2];
-  }
+  Register MemSemanticsReg;
+
+  if (Call->Arguments.size() >= 3)
+    MemSemanticsReg =
+        buildMemSemanticsReg(Call->Arguments[2], PtrRegister, MRI, GR);
+
   if (!MemSemanticsReg.isValid())
     MemSemanticsReg = buildConstantIntReg(Semantics, MIRBuilder, GR);
 
@@ -623,6 +648,47 @@ static bool buildAtomicRMWInst(const SPIRV::IncomingCall *Call, unsigned Opcode,
   return true;
 }
 
+/// Helper function for building atomic flag instructions (e.g.
+/// OpAtomicFlagTestAndSet).
+static bool buildAtomicFlagInst(const SPIRV::IncomingCall *Call,
+                                unsigned Opcode, MachineIRBuilder &MIRBuilder,
+                                SPIRVGlobalRegistry *GR) {
+  const MachineRegisterInfo *MRI = MIRBuilder.getMRI();
+
+  Register PtrRegister = Call->Arguments[0];
+  unsigned Semantics = SPIRV::MemorySemantics::SequentiallyConsistent;
+  Register MemSemanticsReg;
+
+  if (Call->Arguments.size() >= 2)
+    MemSemanticsReg =
+        buildMemSemanticsReg(Call->Arguments[1], PtrRegister, MRI, GR);
+
+  if (!MemSemanticsReg.isValid())
+    MemSemanticsReg = buildConstantIntReg(Semantics, MIRBuilder, GR);
+
+  assert((Opcode != SPIRV::OpAtomicFlagClear ||
+          (Semantics != SPIRV::MemorySemantics::Acquire &&
+           Semantics != SPIRV::MemorySemantics::AcquireRelease)) &&
+         "Invalid memory order argument!");
+
+  SPIRV::Scope::Scope Scope = SPIRV::Scope::Device;
+  Register ScopeRegister;
+
+  if (Call->Arguments.size() >= 3)
+    ScopeRegister = buildScopeReg(Call->Arguments[2], MIRBuilder, GR, MRI);
+
+  if (!ScopeRegister.isValid())
+    ScopeRegister = buildConstantIntReg(Scope, MIRBuilder, GR);
+
+  auto MIB = MIRBuilder.buildInstr(Opcode);
+  if (Opcode == SPIRV::OpAtomicFlagTestAndSet)
+    MIB.addDef(Call->ReturnRegister)
+        .addUse(GR->getSPIRVTypeID(Call->ReturnType));
+
+  MIB.addUse(PtrRegister).addUse(ScopeRegister).addUse(MemSemanticsReg);
+  return true;
+}
+
 /// Helper function for building barriers, i.e., memory/control ordering
 /// operations.
 static bool buildBarrierInst(const SPIRV::IncomingCall *Call, unsigned Opcode,
@@ -992,6 +1058,9 @@ static bool generateAtomicInst(const SPIRV::IncomingCall *Call,
     return buildAtomicRMWInst(Call, Opcode, MIRBuilder, GR);
   case SPIRV::OpMemoryBarrier:
     return buildBarrierInst(Call, SPIRV::OpMemoryBarrier, MIRBuilder, GR);
+  case SPIRV::OpAtomicFlagTestAndSet:
+  case SPIRV::OpAtomicFlagClear:
+    return buildAtomicFlagInst(Call, Opcode, MIRBuilder, GR);
   default:
     return false;
   }

diff  --git a/llvm/lib/Target/SPIRV/SPIRVBuiltins.td b/llvm/lib/Target/SPIRV/SPIRVBuiltins.td
index c82354bb39f43..3c430709215de 100644
--- a/llvm/lib/Target/SPIRV/SPIRVBuiltins.td
+++ b/llvm/lib/Target/SPIRV/SPIRVBuiltins.td
@@ -527,6 +527,10 @@ defm : DemangledNativeBuiltin<"atomic_fetch_sub_explicit", OpenCL_std, Atomic, 4
 defm : DemangledNativeBuiltin<"atomic_fetch_or_explicit", OpenCL_std, Atomic, 4, 6, OpAtomicOr>;
 defm : DemangledNativeBuiltin<"atomic_fetch_xor_explicit", OpenCL_std, Atomic, 4, 6, OpAtomicXor>;
 defm : DemangledNativeBuiltin<"atomic_fetch_and_explicit", OpenCL_std, Atomic, 4, 6, OpAtomicAnd>;
+defm : DemangledNativeBuiltin<"atomic_flag_test_and_set", OpenCL_std, Atomic, 1, 1, OpAtomicFlagTestAndSet>;
+defm : DemangledNativeBuiltin<"atomic_flag_test_and_set_explicit", OpenCL_std, Atomic, 2, 3, OpAtomicFlagTestAndSet>;
+defm : DemangledNativeBuiltin<"atomic_flag_clear", OpenCL_std, Atomic, 1, 1, OpAtomicFlagClear>;
+defm : DemangledNativeBuiltin<"atomic_flag_clear_explicit", OpenCL_std, Atomic, 2, 3, OpAtomicFlagClear>;
 
 // Barrier builtin records:
 defm : DemangledNativeBuiltin<"barrier", OpenCL_std, Barrier, 1, 3, OpControlBarrier>;

diff  --git a/llvm/test/CodeGen/SPIRV/transcoding/atomic_flag.ll b/llvm/test/CodeGen/SPIRV/transcoding/atomic_flag.ll
new file mode 100644
index 0000000000000..3c563d373f1bd
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/transcoding/atomic_flag.ll
@@ -0,0 +1,40 @@
+; RUN: llc -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s
+
+;; Types:
+; CHECK-DAG:  %[[#INT:]] = OpTypeInt 32
+; CHECK-DAG:  %[[#BOOL:]] = OpTypeBool
+;; Constants:
+; CHECK-DAG:  %[[#SEQ_CONSI_SEMAN:]] = OpConstant %[[#INT]] 16
+; CHECK-DAG:  %[[#DEVICE_SCOPE:]] = OpConstant %[[#INT]] 1
+; CHECK-DAG:  %[[#WORKGROUP_SCOPE:]] = OpConstant %[[#INT]] 2
+;; Instructions:
+; CHECK-DAG:  %[[#PARAM:]] = OpFunctionParameter %[[#]]
+; CHECK:      %[[#]] = OpAtomicFlagTestAndSet %[[#BOOL]] %[[#PARAM]] %[[#DEVICE_SCOPE]] %[[#SEQ_CONSI_SEMAN]]
+; CHECK:      %[[#]] = OpAtomicFlagTestAndSet %[[#BOOL]] %[[#PARAM]] %[[#DEVICE_SCOPE]] %[[#SEQ_CONSI_SEMAN]]
+; CHECK:      %[[#]] = OpAtomicFlagTestAndSet %[[#BOOL]] %[[#PARAM]] %[[#WORKGROUP_SCOPE]] %[[#SEQ_CONSI_SEMAN]]
+; CHECK:      OpAtomicFlagClear %[[#PARAM]] %[[#DEVICE_SCOPE]] %[[#SEQ_CONSI_SEMAN]]
+; CHECK:      OpAtomicFlagClear %[[#PARAM]] %[[#DEVICE_SCOPE]] %[[#SEQ_CONSI_SEMAN]]
+; CHECK:      OpAtomicFlagClear %[[#PARAM]] %[[#WORKGROUP_SCOPE]] %[[#SEQ_CONSI_SEMAN]]
+
+define spir_kernel void @testAtomicFlag(ptr %object) {
+entry:
+  %call1 = call spir_func zeroext i1 @_Z24atomic_flag_test_and_setPU3AS4VU7_Atomici(ptr %object)
+  %call2 = call spir_func zeroext i1 @_Z33atomic_flag_test_and_set_explicitPU3AS4VU7_Atomici12memory_order(ptr %object, i32 5)
+  %call5 = call spir_func zeroext i1 @_Z33atomic_flag_test_and_set_explicitPU3AS4VU7_Atomici12memory_order12memory_scope(ptr %object, i32 5, i32 1)
+  call spir_func void @_Z17atomic_flag_clearPU3AS4VU7_Atomici(ptr %object)
+  call spir_func void @_Z26atomic_flag_clear_explicitPU3AS4VU7_Atomici12memory_order(ptr %object, i32 5)
+  call spir_func void @_Z26atomic_flag_clear_explicitPU3AS4VU7_Atomici12memory_order12memory_scope(ptr %object, i32 5, i32 1)
+  ret void
+}
+
+declare spir_func zeroext i1 @_Z24atomic_flag_test_and_setPU3AS4VU7_Atomici(ptr)
+
+declare spir_func zeroext i1 @_Z33atomic_flag_test_and_set_explicitPU3AS4VU7_Atomici12memory_order(ptr, i32)
+
+declare spir_func zeroext i1 @_Z33atomic_flag_test_and_set_explicitPU3AS4VU7_Atomici12memory_order12memory_scope(ptr, i32, i32)
+
+declare spir_func void @_Z17atomic_flag_clearPU3AS4VU7_Atomici(ptr)
+
+declare spir_func void @_Z26atomic_flag_clear_explicitPU3AS4VU7_Atomici12memory_order(ptr, i32)
+
+declare spir_func void @_Z26atomic_flag_clear_explicitPU3AS4VU7_Atomici12memory_order12memory_scope(ptr, i32, i32)


        


More information about the llvm-commits mailing list