[clang] [CIR] Support __builtin_nondeterministic_value (PR #206149)

Letu Ren via cfe-commits cfe-commits at lists.llvm.org
Fri Jun 26 22:41:28 PDT 2026


https://github.com/FantasqueX updated https://github.com/llvm/llvm-project/pull/206149

>From 82ba70ea162025cc038d8910edebdbb7c263da00 Mon Sep 17 00:00:00 2001
From: Letu Ren <fantasquex at gmail.com>
Date: Sat, 27 Jun 2026 02:42:44 +0800
Subject: [PATCH] [CIR] Support __builtin_nondeterministic_value

---
 clang/include/clang/CIR/Dialect/IR/CIROps.td  | 29 ++++++++
 clang/lib/CIR/CodeGen/CIRGenBuilder.h         |  4 ++
 clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp       |  9 ++-
 .../builtin-nondeterministic-value.c          | 68 +++++++++++++++++++
 4 files changed, 108 insertions(+), 2 deletions(-)
 create mode 100644 clang/test/CIR/CodeGenBuiltins/builtin-nondeterministic-value.c

diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 7d1c48b994b27..1d113df57d784 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -2026,6 +2026,35 @@ def CIR_FNegOp : CIR_UnaryOp<"fneg", CIR_AnyFloatOrVecOfFloatType> {
   let llvmOp = "FNegOp";
 }
 
+//===----------------------------------------------------------------------===//
+// FreezeOp
+//===----------------------------------------------------------------------===//
+
+def CIR_FreezeOp : CIR_Op<"freeze", [Pure, SameOperandsAndResultType]> {
+  let summary = "Stop propagation of undef and poison values";
+  let description = [{
+    The `cir.freeze` operation takes a single operand and returns a value of the
+    same type. If the operand is a poison or undef value, `cir.freeze` returns
+    an arbitrary, but fixed, value of the operand type. Otherwise it returns
+    the operand unchanged.
+
+    Example:
+
+    ```mlir
+    %1 = cir.freeze %0 : !s32i
+    ```
+  }];
+
+  let arguments = (ins CIR_AnyType:$input);
+  let results = (outs CIR_AnyType:$result);
+
+  let assemblyFormat = [{
+    $input `:` type($input) attr-dict
+  }];
+
+  let llvmOp = "FreezeOp";
+}
+
 //===----------------------------------------------------------------------===//
 // BrCondOp
 //===----------------------------------------------------------------------===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index cc1ff1e32521f..5547c3b5f579c 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -851,6 +851,10 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
     return createVecShuffle(loc, vec1, poison, mask);
   }
 
+  mlir::Value createFreeze(mlir::Location loc, mlir::Value value) {
+    return cir::FreezeOp::create(*this, loc, value);
+  }
+
   template <typename... Operands>
   mlir::Value emitIntrinsicCallOp(mlir::Location loc, const llvm::StringRef str,
                                   const mlir::Type &resTy, Operands &&...op) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index 3b8149411e7c4..d094ea5543f5a 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -1636,8 +1636,13 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID,
         builder.createIsFPClass(loc, v, cir::FPClassTest(test)),
         convertType(e->getType())));
   }
-  case Builtin::BI__builtin_nondeterministic_value:
-    return errorBuiltinNYI(*this, e, builtinID);
+  case Builtin::BI__builtin_nondeterministic_value: {
+    mlir::Type ty = convertType(e->getArg(0)->getType());
+    mlir::Value result =
+        cir::ConstantOp::create(builder, loc, ty, cir::PoisonAttr::get(ty));
+    result = builder.createFreeze(loc, result);
+    return RValue::get(result);
+  }
   case Builtin::BI__builtin_elementwise_abs: {
     mlir::Type cirTy = convertType(e->getArg(0)->getType());
     bool isIntTy = cir::isIntOrVectorOfIntType(cirTy);
diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-nondeterministic-value.c b/clang/test/CIR/CodeGenBuiltins/builtin-nondeterministic-value.c
new file mode 100644
index 0000000000000..d7d9224fc0440
--- /dev/null
+++ b/clang/test/CIR/CodeGenBuiltins/builtin-nondeterministic-value.c
@@ -0,0 +1,68 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
+// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
+// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll
+// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM
+
+typedef float float4 __attribute__((ext_vector_type(4)));
+
+// TODO: the bool4 (ext_vector_type _Bool) case from the classic CodeGen test is
+// omitted here: CIR does not yet implement storing ext-vector-bool types
+// (emitStoreOfScalar ExtVectorBoolType is NYI). The cir.freeze lowering itself
+// works for <N x !cir.bool>; only the surrounding store is unsupported.
+
+int clang_nondet_i(int x) {
+  return __builtin_nondeterministic_value(x);
+}
+
+// CIR-LABEL: cir.func {{.*}}@clang_nondet_i
+// CIR: %[[POISON:.*]] = cir.const #cir.poison : !s32i
+// CIR: %[[RES:.*]] = cir.freeze %[[POISON]] : !s32i
+
+// LLVM-LABEL: @clang_nondet_i
+// LLVM: %[[RES:.*]] = freeze i32 poison
+
+float clang_nondet_f(float x) {
+  return __builtin_nondeterministic_value(x);
+}
+
+// CIR-LABEL: cir.func {{.*}}@clang_nondet_f
+// CIR: %[[POISON:.*]] = cir.const #cir.poison : !cir.float
+// CIR: %[[RES:.*]] = cir.freeze %[[POISON]] : !cir.float
+
+// LLVM-LABEL: @clang_nondet_f
+// LLVM: %[[RES:.*]] = freeze float poison
+
+double clang_nondet_d(double x) {
+  return __builtin_nondeterministic_value(x);
+}
+
+// CIR-LABEL: cir.func {{.*}}@clang_nondet_d
+// CIR: %[[POISON:.*]] = cir.const #cir.poison : !cir.double
+// CIR: %[[RES:.*]] = cir.freeze %[[POISON]] : !cir.double
+
+// LLVM-LABEL: @clang_nondet_d
+// LLVM: %[[RES:.*]] = freeze double poison
+
+_Bool clang_nondet_b(_Bool x) {
+  return __builtin_nondeterministic_value(x);
+}
+
+// CIR-LABEL: cir.func {{.*}}@clang_nondet_b
+// CIR: %[[POISON:.*]] = cir.const #cir.poison : !cir.bool
+// CIR: %[[RES:.*]] = cir.freeze %[[POISON]] : !cir.bool
+
+// LLVM-LABEL: @clang_nondet_b
+// LLVM: %[[RES:.*]] = freeze i1 poison
+
+void clang_nondet_fv(void) {
+  float4 x = __builtin_nondeterministic_value(x);
+}
+
+// CIR-LABEL: cir.func {{.*}}@clang_nondet_fv
+// CIR: %[[POISON:.*]] = cir.const #cir.poison : !cir.vector<4 x !cir.float>
+// CIR: %[[RES:.*]] = cir.freeze %[[POISON]] : !cir.vector<4 x !cir.float>
+
+// LLVM-LABEL: @clang_nondet_fv
+// LLVM: %[[RES:.*]] = freeze <4 x float> poison



More information about the cfe-commits mailing list