[clang] [llvm] [HLSL][DXIL] InterlockedOr and InterlockedOr64 builtins (PR #180804)

Alexander Johnston via cfe-commits cfe-commits at lists.llvm.org
Thu Apr 9 09:50:28 PDT 2026


================
@@ -301,6 +300,98 @@ static Value *handleElementwiseF32ToF16(CodeGenFunction &CGF,
   llvm_unreachable("Intrinsic F32ToF16 not supported by target architecture");
 }
 
+static Value *handleInterlockedOr(CodeGenFunction &CGF, const CallExpr *E,
+                                  const bool HasReturn) {
+  const bool Is32Bit = CGF.getContext().getTypeSize(
+                           E->getArg(E->getNumArgs() - 1)->getType()) == 32;
+  Value *HandleOp = CGF.EmitScalarExpr(E->getArg(0));
+  Value *IndexOp = CGF.EmitScalarExpr(E->getArg(1));
+  Value *StructuredBufIndexOp;
+  Value *NewValueOp;
+  Value *OldValueOp;
+  unsigned OldValueArgIdx;
+  if (E->getNumArgs() == 3) {
+    // (handle, index, newValue)
+    NewValueOp = CGF.EmitScalarExpr(E->getArg(2));
+  } else if (E->getNumArgs() == 4) {
+    if (HasReturn) {
+      // (handle, index, newValue, oldValue)
+      NewValueOp = CGF.EmitScalarExpr(E->getArg(2));
+      OldValueArgIdx = 3;
+    } else {
+      // (handle, index, index, newValue)
+      StructuredBufIndexOp = CGF.EmitScalarExpr(E->getArg(2));
+      NewValueOp = CGF.EmitScalarExpr(E->getArg(3));
+    }
+  } else {
+    // (handle, index, index, newValue, oldValue)
+    StructuredBufIndexOp = CGF.EmitScalarExpr(E->getArg(2));
+    NewValueOp = CGF.EmitScalarExpr(E->getArg(3));
+    OldValueArgIdx = 4;
+  }
+
+  switch (CGF.CGM.getTarget().getTriple().getArch()) {
+  case llvm::Triple::dxil: {
+    QualType HandleTy = E->getArg(0)->getType();
+    const HLSLAttributedResourceType *ResourceTy =
+        HandleTy->getAs<HLSLAttributedResourceType>();
+
+    // AtomicBinOp has 3 coordinate params which must be handled differently
+    // depending on the resource type being accessed.
+    // Initially poison all the coordinates then fill as required
+    Value *Poison = PoisonValue::get(CGF.Int32Ty);
+    Value *C0 = Poison;
+    Value *C1 = Poison;
+    Value *C2 = Poison;
+    if (!ResourceTy->getAttrs().RawBuffer) {
+      assert(
+          (ResourceTy->getContainedType() == CGF.getContext().IntTy ||
+           ResourceTy->getContainedType() == CGF.getContext().UnsignedIntTy ||
+           ResourceTy->getContainedType() == CGF.getContext().LongTy ||
+           ResourceTy->getContainedType() == CGF.getContext().UnsignedLongTy) &&
+          "AtomicBinOp RWBuffer must contain 32 or 64bit (unsigned) int type");
+      // RWBuffer: c0
+      C0 = IndexOp;
+
+      // RWByteAddressBuffers are output as char8_t, but as that isn't
+      // recognised by HLSL we can't use it as an attribute to define them in
+      // tests, so must also check for char ([[hlsl::contained_type(char)]])
+    } else if (ResourceTy->getContainedType() == CGF.getContext().Char8Ty ||
+               ResourceTy->getContainedType() == CGF.getContext().CharTy) {
+      // RWByteAddressBuffer: c0
+      C0 = IndexOp;
+    } else {
+      // RWStructuredBuffer: c0 and c1
+      C0 = IndexOp;
+      C1 = StructuredBufIndexOp;
+    }
----------------
Alexander-Johnston wrote:

C2 won't always be poison once we have textures, which is why I've organised it this way.
Both Texture3D and Texture2DArray will use every coordinate. (They take a vector 3 of uint where each uint is one of the coordinates, https://godbolt.org/z/jqTdzcPPf)
I'll add more to this with texture interlocked support in an upcoming patch once textures are available (no work was done towards them when I started this and it's already quite a big patch by itself).


https://github.com/llvm/llvm-project/pull/180804


More information about the cfe-commits mailing list