[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