https://github.com/akash-manna-sky created https://github.com/llvm/llvm-project/pull/237565
Fixes #119126 The type guard in the `__builtin_constant_p` lowering uses `isFloatingType()`, which is also true for `_Complex` types, so a complex argument the constant evaluator couldn't fold reaches `EmitScalarExpr` and trips its `hasScalarEvaluationKind` assert. Complex arguments now take their own path: emit the value with `EmitComplexExpr` and AND the `llvm.is.constant` results for the real and imaginary parts, which matches what the constant evaluator and GCC already do for complex values. Assisted-by: LLM Tools >From e31ff90b24bc8b89d46b954d05e58cd244042108 Mon Sep 17 00:00:00 2001 From: Akash Manna <[email protected]> Date: Tue, 27 Oct 2026 18:40:16 +0530 Subject: [PATCH] Fixes #119126 The type guard in the `__builtin_constant_p` lowering uses `isFloatingType()`, which is also true for `_Complex` types, so a complex argument the constant evaluator couldn't fold reaches `EmitScalarExpr` and trips its `hasScalarEvaluationKind` assert. Complex arguments now take their own path: emit the value with `EmitComplexExpr` and AND the `llvm.is.constant` results for the real and imaginary parts, which matches what the constant evaluator and GCC already do for complex values. LLM tools were used for this contribution. --- clang/docs/ReleaseNotes.md | 1 + clang/lib/CodeGen/CGBuiltin.cpp | 32 ++++-- clang/test/CodeGen/builtin-constant-p.c | 105 +++++++++++++++++++ clang/test/CodeGenCXX/builtin-constant-p.cpp | 10 ++ 4 files changed, 138 insertions(+), 10 deletions(-) diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md index e6b71ba2a0b565..78ef817b380557 100644 --- a/clang/docs/ReleaseNotes.md +++ b/clang/docs/ReleaseNotes.md @@ -783,6 +783,7 @@ features cannot lower the translation-unit ABI level; - Fix a crash when using `__builtin_assume_aligned` with dynamic allocations during constant evaluation. (#GH173767) - Fixed a crash on an invalid pointer argument to `__builtin_assume_aligned`. (#GH194289) +- Fixed a crash when `__builtin_constant_p` is applied to a `_Complex` value that could not be constant folded. (#GH119126) - Fixed a crash when constant-evaluating `__builtin_align_up`, `__builtin_align_down`, or `__builtin_is_aligned` with pointers without an underlying object. Null pointers are handled as aligned values, while other base-less pointers are rejected during constant diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index e154b9e752fd5c..1587389bb3117f 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -4092,7 +4092,8 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, 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() && + if (!ArgType->isIntegralOrEnumerationType() && + !ArgType->isRealFloatingType() && !ArgType->isAnyComplexType() && !ArgType->isObjCObjectPointerType() && !ArgType->isBlockPointerType()) // Per the GCC documentation, only numeric constants are recognized after // inlining. @@ -4103,16 +4104,27 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID, // side-effects. return RValue::get(ConstantInt::get(ResultType, 0)); - Value *ArgValue = EmitScalarExpr(Arg); - if (ArgType->isObjCObjectPointerType()) { - // Convert Objective-C objects to id because we cannot distinguish between - // LLVM types for Obj-C classes as they are opaque. - ArgType = CGM.getContext().getObjCIdType(); - ArgValue = Builder.CreateBitCast(ArgValue, ConvertType(ArgType)); + Value *Result; + if (ArgType->isAnyComplexType()) { + // A complex value is constant when both of its components are. + ComplexPairTy ArgValue = EmitComplexExpr(Arg); + Function *F = + CGM.getIntrinsic(Intrinsic::is_constant, ArgValue.first->getType()); + Value *Real = Builder.CreateCall(F, ArgValue.first); + Value *Imag = Builder.CreateCall(F, ArgValue.second); + Result = Builder.CreateAnd(Real, Imag); + } else { + Value *ArgValue = EmitScalarExpr(Arg); + if (ArgType->isObjCObjectPointerType()) { + // Convert Objective-C objects to id because we cannot distinguish + // between LLVM types for Obj-C classes as they are opaque. + ArgType = CGM.getContext().getObjCIdType(); + ArgValue = Builder.CreateBitCast(ArgValue, ConvertType(ArgType)); + } + Function *F = + CGM.getIntrinsic(Intrinsic::is_constant, ConvertType(ArgType)); + Result = Builder.CreateCall(F, ArgValue); } - Function *F = - CGM.getIntrinsic(Intrinsic::is_constant, ConvertType(ArgType)); - Value *Result = Builder.CreateCall(F, ArgValue); if (Result->getType() != ResultType) Result = Builder.CreateIntCast(Result, ResultType, /*isSigned*/false); return RValue::get(Result); diff --git a/clang/test/CodeGen/builtin-constant-p.c b/clang/test/CodeGen/builtin-constant-p.c index 07288069a5e3ad..085ae9aae52330 100644 --- a/clang/test/CodeGen/builtin-constant-p.c +++ b/clang/test/CodeGen/builtin-constant-p.c @@ -153,3 +153,108 @@ void test15(void) { int a, b; (void)__builtin_constant_p((a = b, test15_f())); } + +/* --- Complex types (GH119126) */ + +__complex double test_complex_cond(void) { + // CHECK-LABEL: test_complex_cond + // CHECK: [[R:%.*]] = call i1 @llvm.is.constant.f64(double %f.real) + // CHECK: [[I:%.*]] = call i1 @llvm.is.constant.f64(double %f.imag) + // CHECK: and i1 [[R]], [[I]] + __complex double f; + return (__builtin_constant_p(f) ? f : 0); +} + +int test_complex_float(_Complex float x) { + // CHECK-LABEL: test_complex_float + // CHECK: [[R:%.*]] = call i1 @llvm.is.constant.f32(float %x.real) + // CHECK: [[I:%.*]] = call i1 @llvm.is.constant.f32(float %x.imag) + // CHECK: [[AND:%.*]] = and i1 [[R]], [[I]] + // CHECK: zext i1 [[AND]] to i32 + int r = __builtin_constant_p(x); + return r; +} + +int test_complex_long_double(_Complex long double x) { + // CHECK-LABEL: test_complex_long_double + // CHECK: [[R:%.*]] = call i1 @llvm.is.constant.f80(x86_fp80 %x.real) + // CHECK: [[I:%.*]] = call i1 @llvm.is.constant.f80(x86_fp80 %x.imag) + // CHECK: and i1 [[R]], [[I]] + return __builtin_constant_p(x); +} + +int test_complex_float16(_Complex _Float16 x) { + // CHECK-LABEL: test_complex_float16 + // CHECK: [[R:%.*]] = call i1 @llvm.is.constant.f16(half %x.real) + // CHECK: [[I:%.*]] = call i1 @llvm.is.constant.f16(half %x.imag) + // CHECK: and i1 [[R]], [[I]] + return __builtin_constant_p(x); +} + +int test_complex_int(_Complex int x) { + // CHECK-LABEL: test_complex_int + // CHECK: [[R:%.*]] = call i1 @llvm.is.constant.i32(i32 %x.real) + // CHECK: [[I:%.*]] = call i1 @llvm.is.constant.i32(i32 %x.imag) + // CHECK: and i1 [[R]], [[I]] + return __builtin_constant_p(x); +} + +int test_complex_const1(void) { + // CHECK-LABEL: test_complex_const1 + // CHECK: ret i32 1 + return __builtin_constant_p(1.0i); +} + +int test_complex_const2(void) { + // CHECK-LABEL: test_complex_const2 + // CHECK: ret i32 1 + return __builtin_constant_p(__builtin_complex(1.0f, 2.0f)); +} + +const _Complex long double c_cld = __builtin_complex(1.0L, 2.0L); + +int test_complex_const3(void) { + // CHECK-LABEL: test_complex_const3 + // CHECK: ret i32 1 + return __builtin_constant_p(c_cld); +} + +_Complex double test_complex_f(void); + +int test_complex_side_effect(void) { + // CHECK-LABEL: test_complex_side_effect + // CHECK-NOT: test_complex_f + // CHECK-NOT: llvm.is.constant + // CHECK: ret i32 0 + return __builtin_constant_p(test_complex_f()); +} + +/* --- Scalar controls */ + +int test_double(double x) { + // CHECK-LABEL: test_double + // CHECK: call i1 @llvm.is.constant.f64(double % + // CHECK-NOT: and i1 + // CHECK: ret i32 + return __builtin_constant_p(x); +} + +enum test_enum_t { TEST_ENUM_A }; + +int test_enum(enum test_enum_t x) { + // CHECK-LABEL: test_enum + // CHECK: call i1 @llvm.is.constant.i32(i32 % + return __builtin_constant_p(x); +} + +int test_bitint(_BitInt(37) x) { + // CHECK-LABEL: test_bitint + // CHECK: call i1 @llvm.is.constant.i37(i37 % + return __builtin_constant_p(x); +} + +int test_pointer(int *p) { + // CHECK-LABEL: test_pointer + // CHECK: ret i32 0 + return __builtin_constant_p(p); +} diff --git a/clang/test/CodeGenCXX/builtin-constant-p.cpp b/clang/test/CodeGenCXX/builtin-constant-p.cpp index 39416b94375fe5..f57db922bdc56a 100644 --- a/clang/test/CodeGenCXX/builtin-constant-p.cpp +++ b/clang/test/CodeGenCXX/builtin-constant-p.cpp @@ -47,3 +47,13 @@ bool bcp_stmt_expr_2(int n) { // CHECK-NOT: } // CHECK: ret i1 false } + +// GH119126: a complex argument was emitted as a scalar. +// CHECK-LABEL: define {{.*}} @_Z8gh119126v() +// CHECK: [[R:%.*]] = call i1 @llvm.is.constant.f64(double %f.real) +// CHECK: [[I:%.*]] = call i1 @llvm.is.constant.f64(double %f.imag) +// CHECK: and i1 [[R]], [[I]] +__complex double gh119126() { + __complex double f; + return (__builtin_constant_p(f) ? f : 0); +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
