[clang] [CIR] Upstream support for builtin_constant_p (PR #170354)
https://github.com/andykaylor closed https://github.com/llvm/llvm-project/pull/170354 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream support for builtin_constant_p (PR #170354)
https://github.com/andykaylor auto_merge_enabled https://github.com/llvm/llvm-project/pull/170354 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream support for builtin_constant_p (PR #170354)
https://github.com/andykaylor updated
https://github.com/llvm/llvm-project/pull/170354
>From 48088ba4ccb8157519d3686e910961bc3deba39f Mon Sep 17 00:00:00 2001
From: Andy Kaylor
Date: Wed, 26 Nov 2025 09:38:08 -0800
Subject: [PATCH 1/2] [CIR] Upstream support for builtin_constant_p
This upstreams the handler for the BI__builtin_constant_p function.
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 28 ++
clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 39 +++
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 7 +
.../CIR/CodeGenBuiltins/builtin-constant-p.c | 281 ++
4 files changed, 355 insertions(+)
create mode 100644 clang/test/CIR/CodeGenBuiltins/builtin-constant-p.c
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 4b64fc56c57ad..1d41129f5e0c2 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1173,6 +1173,34 @@ def CIR_SwitchOp : CIR_Op<"switch", [
let hasLLVMLowering = false;
}
+//===--===//
+// IsConstantOp
+//===--===//
+
+def CIR_IsConstantOp : CIR_Op<"is_constant", [Pure]> {
+ let description = [{
+Returns `true` if the argument is known to be a manifest compile-time
+constant otherwise returns `false`. If the argument is a constant
expression
+which refers to a global (the address of which _is_ a constant, but not
+manifest during the compile), then the intrinsic evaluates to `false`.
+
+This is used to represent `__builtin_constant_p` in cases where the
argument
+isn't known to be constant during initial translation of the source code
but
+might be proven to be constant after later optimizations.
+
+Example:
+```
+%1 = cir.is_constant %2 : !s32i -> !cir.bool
+```
+ }];
+ let arguments = (ins CIR_AnyType:$val);
+ let results = (outs CIR_BoolType:$result);
+
+ let assemblyFormat = [{
+$val `:` qualified(type($val)) `->` qualified(type($result)) attr-dict
+ }];
+}
+
//===--===//
// SwitchFlatOp
//===--===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index e14b5f8aac337..65949ef7233f5 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -542,6 +542,45 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl
&gd, unsigned builtinID,
return emitCall(e->getCallee()->getType(), CIRGenCallee::forDirect(fnOp),
e,
returnValue);
}
+
+ case Builtin::BI__builtin_constant_p: {
+mlir::Type resultType = convertType(e->getType());
+
+const Expr *arg = e->getArg(0);
+QualType argType = arg->getType();
+// FIXME: The allowance for Obj-C pointers and block pointers is historical
+// and likely a mistake.
+if (!argType->isIntegralOrEnumerationType() && !argType->isFloatingType()
&&
+!argType->isObjCObjectPointerType() && !argType->isBlockPointerType())
{
+ // Per the GCC documentation, only numeric constants are recognized after
+ // inlining.
+ return RValue::get(
+ builder.getConstInt(getLoc(e->getSourceRange()),
+ mlir::cast(resultType), 0));
+}
+
+if (arg->HasSideEffects(getContext())) {
+ // The argument is unevaluated, so be conservative if it might have
+ // side-effects.
+ return RValue::get(
+ builder.getConstInt(getLoc(e->getSourceRange()),
+ mlir::cast(resultType), 0));
+}
+
+mlir::Value argValue = emitScalarExpr(arg);
+if (argType->isObjCObjectPointerType()) {
+ cgm.errorNYI(e->getSourceRange(),
+ "__builtin_constant_p: Obj-C object pointer");
+ return {};
+}
+argValue = builder.createBitcast(argValue, convertType(argType));
+
+mlir::Value result = cir::IsConstantOp::create(
+builder, getLoc(e->getSourceRange()), argValue);
+if (result.getType() != resultType)
+ result = builder.createBoolToInt(result, resultType);
+return RValue::get(result);
+ }
case Builtin::BI__builtin_dynamic_object_size:
case Builtin::BI__builtin_object_size: {
unsigned type =
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 8e9780754f68f..40e14474890dc 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -3979,6 +3979,13 @@ mlir::LogicalResult
CIRToLLVMGetBitfieldOpLowering::matchAndRewrite(
return mlir::success();
}
+mlir::LogicalResult CIRToLLVMIsConstantOpLowering::matchAndRewrite(
+cir::IsConstantOp op, OpAdaptor adaptor,
[clang] [CIR] Upstream support for builtin_constant_p (PR #170354)
@@ -542,6 +542,45 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl
&gd, unsigned builtinID,
return emitCall(e->getCallee()->getType(), CIRGenCallee::forDirect(fnOp),
e,
returnValue);
}
+
+ case Builtin::BI__builtin_constant_p: {
+mlir::Type resultType = convertType(e->getType());
+
+const Expr *arg = e->getArg(0);
+QualType argType = arg->getType();
+// FIXME: The allowance for Obj-C pointers and block pointers is historical
+// and likely a mistake.
+if (!argType->isIntegralOrEnumerationType() && !argType->isFloatingType()
&&
+!argType->isObjCObjectPointerType() && !argType->isBlockPointerType())
{
+ // Per the GCC documentation, only numeric constants are recognized after
+ // inlining.
+ return RValue::get(
+ builder.getConstInt(getLoc(e->getSourceRange()),
+ mlir::cast(resultType), 0));
+}
+
+if (arg->HasSideEffects(getContext())) {
+ // The argument is unevaluated, so be conservative if it might have
+ // side-effects.
+ return RValue::get(
+ builder.getConstInt(getLoc(e->getSourceRange()),
+ mlir::cast(resultType), 0));
+}
+
+mlir::Value argValue = emitScalarExpr(arg);
+if (argType->isObjCObjectPointerType()) {
+ cgm.errorNYI(e->getSourceRange(),
+ "__builtin_constant_p: Obj-C object pointer");
+ return {};
+}
+argValue = builder.createBitcast(argValue, convertType(argType));
+
+mlir::Value result = cir::IsConstantOp::create(
+builder, getLoc(e->getSourceRange()), argValue);
+if (result.getType() != resultType)
andykaylor wrote:
I think you're right. This was following the behavior of classic codegen, which
does the same check on the result type of the `llvm.is.constant` intrinsic,
which always returns `i1` so that will also always be true.
https://github.com/llvm/llvm-project/pull/170354
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream support for builtin_constant_p (PR #170354)
@@ -542,6 +542,45 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl
&gd, unsigned builtinID,
return emitCall(e->getCallee()->getType(), CIRGenCallee::forDirect(fnOp),
e,
returnValue);
}
+
+ case Builtin::BI__builtin_constant_p: {
+mlir::Type resultType = convertType(e->getType());
+
+const Expr *arg = e->getArg(0);
+QualType argType = arg->getType();
+// FIXME: The allowance for Obj-C pointers and block pointers is historical
+// and likely a mistake.
+if (!argType->isIntegralOrEnumerationType() && !argType->isFloatingType()
&&
+!argType->isObjCObjectPointerType() && !argType->isBlockPointerType())
{
+ // Per the GCC documentation, only numeric constants are recognized after
+ // inlining.
+ return RValue::get(
+ builder.getConstInt(getLoc(e->getSourceRange()),
+ mlir::cast(resultType), 0));
+}
+
+if (arg->HasSideEffects(getContext())) {
+ // The argument is unevaluated, so be conservative if it might have
+ // side-effects.
+ return RValue::get(
+ builder.getConstInt(getLoc(e->getSourceRange()),
+ mlir::cast(resultType), 0));
+}
+
+mlir::Value argValue = emitScalarExpr(arg);
+if (argType->isObjCObjectPointerType()) {
+ cgm.errorNYI(e->getSourceRange(),
+ "__builtin_constant_p: Obj-C object pointer");
+ return {};
+}
+argValue = builder.createBitcast(argValue, convertType(argType));
+
+mlir::Value result = cir::IsConstantOp::create(
+builder, getLoc(e->getSourceRange()), argValue);
+if (result.getType() != resultType)
xlauko wrote:
Isn't this always true as result is enforced to be a cir::BoolType and
resultType is cir::IntType?
https://github.com/llvm/llvm-project/pull/170354
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream support for builtin_constant_p (PR #170354)
@@ -1173,6 +1173,34 @@ def CIR_SwitchOp : CIR_Op<"switch", [
let hasLLVMLowering = false;
}
+//===--===//
+// IsConstantOp
+//===--===//
+
+def CIR_IsConstantOp : CIR_Op<"is_constant", [Pure]> {
xlauko wrote:
please add `summary`
https://github.com/llvm/llvm-project/pull/170354
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream support for builtin_constant_p (PR #170354)
https://github.com/xlauko approved this pull request. lgtm % nits https://github.com/llvm/llvm-project/pull/170354 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream support for builtin_constant_p (PR #170354)
https://github.com/xlauko edited https://github.com/llvm/llvm-project/pull/170354 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream support for builtin_constant_p (PR #170354)
llvmbot wrote:
@llvm/pr-subscribers-clangir
Author: Andy Kaylor (andykaylor)
Changes
This upstreams the handler for the BI__builtin_constant_p function.
---
Full diff: https://github.com/llvm/llvm-project/pull/170354.diff
4 Files Affected:
- (modified) clang/include/clang/CIR/Dialect/IR/CIROps.td (+28)
- (modified) clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp (+39)
- (modified) clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (+7)
- (added) clang/test/CIR/CodeGenBuiltins/builtin-constant-p.c (+281)
``diff
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 4b64fc56c57ad..1d41129f5e0c2 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1173,6 +1173,34 @@ def CIR_SwitchOp : CIR_Op<"switch", [
let hasLLVMLowering = false;
}
+//===--===//
+// IsConstantOp
+//===--===//
+
+def CIR_IsConstantOp : CIR_Op<"is_constant", [Pure]> {
+ let description = [{
+Returns `true` if the argument is known to be a manifest compile-time
+constant otherwise returns `false`. If the argument is a constant
expression
+which refers to a global (the address of which _is_ a constant, but not
+manifest during the compile), then the intrinsic evaluates to `false`.
+
+This is used to represent `__builtin_constant_p` in cases where the
argument
+isn't known to be constant during initial translation of the source code
but
+might be proven to be constant after later optimizations.
+
+Example:
+```
+%1 = cir.is_constant %2 : !s32i -> !cir.bool
+```
+ }];
+ let arguments = (ins CIR_AnyType:$val);
+ let results = (outs CIR_BoolType:$result);
+
+ let assemblyFormat = [{
+$val `:` qualified(type($val)) `->` qualified(type($result)) attr-dict
+ }];
+}
+
//===--===//
// SwitchFlatOp
//===--===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index e14b5f8aac337..65949ef7233f5 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -542,6 +542,45 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl
&gd, unsigned builtinID,
return emitCall(e->getCallee()->getType(), CIRGenCallee::forDirect(fnOp),
e,
returnValue);
}
+
+ case Builtin::BI__builtin_constant_p: {
+mlir::Type resultType = convertType(e->getType());
+
+const Expr *arg = e->getArg(0);
+QualType argType = arg->getType();
+// FIXME: The allowance for Obj-C pointers and block pointers is historical
+// and likely a mistake.
+if (!argType->isIntegralOrEnumerationType() && !argType->isFloatingType()
&&
+!argType->isObjCObjectPointerType() && !argType->isBlockPointerType())
{
+ // Per the GCC documentation, only numeric constants are recognized after
+ // inlining.
+ return RValue::get(
+ builder.getConstInt(getLoc(e->getSourceRange()),
+ mlir::cast(resultType), 0));
+}
+
+if (arg->HasSideEffects(getContext())) {
+ // The argument is unevaluated, so be conservative if it might have
+ // side-effects.
+ return RValue::get(
+ builder.getConstInt(getLoc(e->getSourceRange()),
+ mlir::cast(resultType), 0));
+}
+
+mlir::Value argValue = emitScalarExpr(arg);
+if (argType->isObjCObjectPointerType()) {
+ cgm.errorNYI(e->getSourceRange(),
+ "__builtin_constant_p: Obj-C object pointer");
+ return {};
+}
+argValue = builder.createBitcast(argValue, convertType(argType));
+
+mlir::Value result = cir::IsConstantOp::create(
+builder, getLoc(e->getSourceRange()), argValue);
+if (result.getType() != resultType)
+ result = builder.createBoolToInt(result, resultType);
+return RValue::get(result);
+ }
case Builtin::BI__builtin_dynamic_object_size:
case Builtin::BI__builtin_object_size: {
unsigned type =
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 8e9780754f68f..40e14474890dc 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -3979,6 +3979,13 @@ mlir::LogicalResult
CIRToLLVMGetBitfieldOpLowering::matchAndRewrite(
return mlir::success();
}
+mlir::LogicalResult CIRToLLVMIsConstantOpLowering::matchAndRewrite(
+cir::IsConstantOp op, OpAdaptor adaptor,
+mlir::ConversionPatternRewriter &rewriter) const {
+ rewriter.replaceOpWithNewOp(op, adaptor.getVal());
+ return mlir::success();
+}
+
mlir::LogicalResult
[clang] [CIR] Upstream support for builtin_constant_p (PR #170354)
andykaylor wrote: This replaces https://github.com/llvm/llvm-project/pull/166832 which wasn't making progress. https://github.com/llvm/llvm-project/pull/170354 ___ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [CIR] Upstream support for builtin_constant_p (PR #170354)
https://github.com/andykaylor created
https://github.com/llvm/llvm-project/pull/170354
This upstreams the handler for the BI__builtin_constant_p function.
>From 48088ba4ccb8157519d3686e910961bc3deba39f Mon Sep 17 00:00:00 2001
From: Andy Kaylor
Date: Wed, 26 Nov 2025 09:38:08 -0800
Subject: [PATCH] [CIR] Upstream support for builtin_constant_p
This upstreams the handler for the BI__builtin_constant_p function.
---
clang/include/clang/CIR/Dialect/IR/CIROps.td | 28 ++
clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 39 +++
.../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 7 +
.../CIR/CodeGenBuiltins/builtin-constant-p.c | 281 ++
4 files changed, 355 insertions(+)
create mode 100644 clang/test/CIR/CodeGenBuiltins/builtin-constant-p.c
diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td
b/clang/include/clang/CIR/Dialect/IR/CIROps.td
index 4b64fc56c57ad..1d41129f5e0c2 100644
--- a/clang/include/clang/CIR/Dialect/IR/CIROps.td
+++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td
@@ -1173,6 +1173,34 @@ def CIR_SwitchOp : CIR_Op<"switch", [
let hasLLVMLowering = false;
}
+//===--===//
+// IsConstantOp
+//===--===//
+
+def CIR_IsConstantOp : CIR_Op<"is_constant", [Pure]> {
+ let description = [{
+Returns `true` if the argument is known to be a manifest compile-time
+constant otherwise returns `false`. If the argument is a constant
expression
+which refers to a global (the address of which _is_ a constant, but not
+manifest during the compile), then the intrinsic evaluates to `false`.
+
+This is used to represent `__builtin_constant_p` in cases where the
argument
+isn't known to be constant during initial translation of the source code
but
+might be proven to be constant after later optimizations.
+
+Example:
+```
+%1 = cir.is_constant %2 : !s32i -> !cir.bool
+```
+ }];
+ let arguments = (ins CIR_AnyType:$val);
+ let results = (outs CIR_BoolType:$result);
+
+ let assemblyFormat = [{
+$val `:` qualified(type($val)) `->` qualified(type($result)) attr-dict
+ }];
+}
+
//===--===//
// SwitchFlatOp
//===--===//
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index e14b5f8aac337..65949ef7233f5 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -542,6 +542,45 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl
&gd, unsigned builtinID,
return emitCall(e->getCallee()->getType(), CIRGenCallee::forDirect(fnOp),
e,
returnValue);
}
+
+ case Builtin::BI__builtin_constant_p: {
+mlir::Type resultType = convertType(e->getType());
+
+const Expr *arg = e->getArg(0);
+QualType argType = arg->getType();
+// FIXME: The allowance for Obj-C pointers and block pointers is historical
+// and likely a mistake.
+if (!argType->isIntegralOrEnumerationType() && !argType->isFloatingType()
&&
+!argType->isObjCObjectPointerType() && !argType->isBlockPointerType())
{
+ // Per the GCC documentation, only numeric constants are recognized after
+ // inlining.
+ return RValue::get(
+ builder.getConstInt(getLoc(e->getSourceRange()),
+ mlir::cast(resultType), 0));
+}
+
+if (arg->HasSideEffects(getContext())) {
+ // The argument is unevaluated, so be conservative if it might have
+ // side-effects.
+ return RValue::get(
+ builder.getConstInt(getLoc(e->getSourceRange()),
+ mlir::cast(resultType), 0));
+}
+
+mlir::Value argValue = emitScalarExpr(arg);
+if (argType->isObjCObjectPointerType()) {
+ cgm.errorNYI(e->getSourceRange(),
+ "__builtin_constant_p: Obj-C object pointer");
+ return {};
+}
+argValue = builder.createBitcast(argValue, convertType(argType));
+
+mlir::Value result = cir::IsConstantOp::create(
+builder, getLoc(e->getSourceRange()), argValue);
+if (result.getType() != resultType)
+ result = builder.createBoolToInt(result, resultType);
+return RValue::get(result);
+ }
case Builtin::BI__builtin_dynamic_object_size:
case Builtin::BI__builtin_object_size: {
unsigned type =
diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
index 8e9780754f68f..40e14474890dc 100644
--- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
+++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
@@ -3979,6 +3979,13 @@ mlir::LogicalResult
CIRToLLVMGetBitfieldOpLowering::matchAndRewrite(
return mlir::success();
}
+mlir::LogicalResult
