[clang] [CIR] Upstream support for builtin_constant_p (PR #170354)

2025-12-02 Thread Andy Kaylor via cfe-commits

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)

2025-12-02 Thread Andy Kaylor via cfe-commits

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)

2025-12-02 Thread Andy Kaylor via cfe-commits

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)

2025-12-02 Thread Andy Kaylor via cfe-commits


@@ -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)

2025-12-02 Thread Henrich Lauko via cfe-commits


@@ -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)

2025-12-02 Thread Henrich Lauko via cfe-commits


@@ -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)

2025-12-02 Thread Henrich Lauko via cfe-commits

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)

2025-12-02 Thread Henrich Lauko via cfe-commits

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)

2025-12-02 Thread via cfe-commits

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)

2025-12-02 Thread Andy Kaylor via cfe-commits

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)

2025-12-02 Thread Andy Kaylor via cfe-commits

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