https://github.com/spamprx updated https://github.com/llvm/llvm-project/pull/166832
>From 227f9ad624e570353abff8de7a09b276e9c6b4e2 Mon Sep 17 00:00:00 2001 From: spamprx <[email protected]> Date: Fri, 7 Nov 2025 00:55:26 +0530 Subject: [PATCH 1/3] feat: included support for is_constant builtin --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 38 ++++++++++++++++++++ clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 25 +++++++++++++ clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 19 ++++++++++ 3 files changed, 82 insertions(+) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 2b361ed0982c6..9765684a1cd72 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -4052,6 +4052,44 @@ def CIR_ExpectOp : CIR_Op<"expect", [ }]; } +//===----------------------------------------------------------------------===// +// IsConstantOp +//===----------------------------------------------------------------------===// + +def CIR_IsConstantOp : CIR_Op<"is_constant", [Pure]> { + let summary = "Check if a value is a compile-time constant"; + let description = [{ + The `cir.is_constant` operation checks whether its input value is a + compile-time constant. This operation models the `__builtin_constant_p` + builtin function. + + The operation takes a single operand of any CIR type and returns a signed + 32-bit integer. The result is 1 if the operand is a compile-time constant, + and 0 otherwise. + + If the value can be determined to be constant at compile time, this + operation may be folded to a constant value. Otherwise, it will be lowered + to the `llvm.is.constant` intrinsic. + + Example: + + ```mlir + %0 = cir.is_constant %expr : i32 -> !s32i + %1 = cir.is_constant %ptr : !cir.ptr<i32> -> !s32i + ``` + }]; + + let arguments = (ins CIR_AnyType:$value); + let results = (outs CIR_SInt32:$result); + + let assemblyFormat = [{ + $value `:` type($value) `->` type($result) attr-dict + }]; + + let hasFolder = 1; + let hasLLVMLowering = false; +} + //===----------------------------------------------------------------------===// // PrefetchOp //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index e35100ffe4b6b..8777ff16f068f 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -199,6 +199,31 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, return RValue::get( builder.createBitcast(allocaAddr, builder.getVoidPtrTy())); } + + case Builtin::BI__builtin_constant_p: { + auto loc = getLoc(e->getSourceRange()); + + Expr::EvalResult evalResult; + + // Try to evaluate at compile time first + if (e->getArg(0)->EvaluateAsRValue(evalResult, getContext()) && + !evalResult.hasSideEffects()) { + // Expression is a compile-time constant, return 1 + llvm::APInt apInt(32, 1); + llvm::APSInt apSInt(apInt, /*isUnsigned=*/false); + return RValue::get(builder.getConstInt(loc, apSInt)); + } + + // Expression cannot be evaluated at compile time, emit runtime check + mlir::Value argValue = emitScalarExpr(e->getArg(0)); + mlir::Type resultType = builder.getSInt32Ty(); + auto isConstantOp = cir::IsConstantOp::create(builder, loc, resultType, argValue); + mlir::Value resultValue = isConstantOp.getResult(); + mlir::Type exprTy = convertType(e->getType()); + if (exprTy != resultValue.getType()) + resultValue = builder.createIntCast(resultValue, exprTy); + return RValue::get(resultValue); + } case Builtin::BIcos: case Builtin::BIcosf: diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 7ba03ce40140c..de23514cf5a79 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -2117,6 +2117,25 @@ OpFoldResult cir::UnaryOp::fold(FoldAdaptor adaptor) { return {}; } +//===----------------------------------------------------------------------===// +// IsConstantOp Definitions +//===----------------------------------------------------------------------===// + +OpFoldResult cir::IsConstantOp::fold(FoldAdaptor adaptor) { + // If the input value is a constant attribute, return 1 (true) + mlir::Attribute value = adaptor.getValue(); + if (value) { + // The value is a compile-time constant, so return 1 + mlir::Type resultType = getResult().getType(); + llvm::APInt apInt(32, 1); + llvm::APSInt apSInt(apInt, /*isUnsigned=*/false); + return cir::IntAttr::get(resultType, apSInt); + } + + // If the input is not a constant, we cannot fold + return {}; +} + //===----------------------------------------------------------------------===// // CopyOp Definitions //===----------------------------------------------------------------------===// >From f2d9b64ec396de9a57366fa826284bd652128222 Mon Sep 17 00:00:00 2001 From: siddu0660 <[email protected]> Date: Fri, 7 Nov 2025 01:18:51 +0530 Subject: [PATCH 2/3] feat: updated TableGen code for BinOpOverFlow --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 41 ++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 9765684a1cd72..44b5fb484510a 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -1702,6 +1702,47 @@ def CIR_BinOp : CIR_Op<"binop", [ }]; } +//===----------------------------------------------------------------------===// +// BinOpOverflow +//===----------------------------------------------------------------------===// + +def CIR_BinOpOverflow : CIR_Op<"binop.overflow", [Pure]> { + let summary = "Binary operations with overflow detection"; + let description = [{ + cir.binop.overflow performs the binary operation according to + the specified opcode kind (add, sub, or mul) and returns both + the result and an overflow flag. + + It requires two input operands and returns two results: + - The result of the operation (same type as operands) + - An overflow flag (boolean type) + + The operation supports both signed and unsigned integer types. + For signed types, overflow is detected when the result cannot + be represented in the result type. For unsigned types, overflow + is detected when the result wraps around. + + ```mlir + %result, %overflow = cir.binop.overflow(add, %1, %2) : !s32i -> (!s32i, !bool) + %result, %overflow = cir.binop.overflow(sub, %3, %4) : !u32i -> (!u32i, !bool) + %result, %overflow = cir.binop.overflow(mul, %5, %6) : !s64i -> (!s64i, !bool) + ``` + }]; + + let arguments = (ins + CIR_BinOpKind:$kind, + CIR_AnyType:$lhs, CIR_AnyType:$rhs + ); + + let results = (outs CIR_AnyType:$result, CIR_BoolType:$overflow); + + let assemblyFormat = [{ + `(` $kind `,` $lhs `,` $rhs `)` `:` type($lhs) `->` `(` type($result) `,` type($overflow) `)` attr-dict + }]; + + let hasVerifier = 1; +} + //===----------------------------------------------------------------------===// // ShiftOp //===----------------------------------------------------------------------===// >From 267c6baecc025b7020469101665997019cf80606 Mon Sep 17 00:00:00 2001 From: spamprx <[email protected]> Date: Fri, 7 Nov 2025 17:25:48 +0530 Subject: [PATCH 3/3] Remove redundant CIR_BinOpOverflow and implement CIR_IsConstantOp in CIRGenBuiltin --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 117 ++++++------------- clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 56 +++++---- 2 files changed, 72 insertions(+), 101 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 63d31d36fe933..5d0913dae3308 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -1702,47 +1702,6 @@ def CIR_BinOp : CIR_Op<"binop", [ }]; } -//===----------------------------------------------------------------------===// -// BinOpOverflow -//===----------------------------------------------------------------------===// - -def CIR_BinOpOverflow : CIR_Op<"binop.overflow", [Pure]> { - let summary = "Binary operations with overflow detection"; - let description = [{ - cir.binop.overflow performs the binary operation according to - the specified opcode kind (add, sub, or mul) and returns both - the result and an overflow flag. - - It requires two input operands and returns two results: - - The result of the operation (same type as operands) - - An overflow flag (boolean type) - - The operation supports both signed and unsigned integer types. - For signed types, overflow is detected when the result cannot - be represented in the result type. For unsigned types, overflow - is detected when the result wraps around. - - ```mlir - %result, %overflow = cir.binop.overflow(add, %1, %2) : !s32i -> (!s32i, !bool) - %result, %overflow = cir.binop.overflow(sub, %3, %4) : !u32i -> (!u32i, !bool) - %result, %overflow = cir.binop.overflow(mul, %5, %6) : !s64i -> (!s64i, !bool) - ``` - }]; - - let arguments = (ins - CIR_BinOpKind:$kind, - CIR_AnyType:$lhs, CIR_AnyType:$rhs - ); - - let results = (outs CIR_AnyType:$result, CIR_BoolType:$overflow); - - let assemblyFormat = [{ - `(` $kind `,` $lhs `,` $rhs `)` `:` type($lhs) `->` `(` type($result) `,` type($overflow) `)` attr-dict - }]; - - let hasVerifier = 1; -} - //===----------------------------------------------------------------------===// // ShiftOp //===----------------------------------------------------------------------===// @@ -3084,6 +3043,44 @@ def CIR_ArrayDtor : CIR_ArrayInitDestroy<"array.dtor"> { }]; } +//===----------------------------------------------------------------------===// +// IsConstantOp +//===----------------------------------------------------------------------===// + +def CIR_IsConstantOp : CIR_Op<"is_constant", [Pure]> { + let summary = "Check if a value is a compile-time constant"; + let description = [{ + The `cir.is_constant` operation checks whether its input value is a + compile-time constant. This operation models the `__builtin_constant_p` + builtin function. + + The operation takes a single operand of any CIR type and returns a signed + 32-bit integer. The result is 1 if the operand is a compile-time constant, + and 0 otherwise. + + If the value can be determined to be constant at compile time, this + operation may be folded to a constant value. Otherwise, it will be lowered + to the `llvm.is.constant` intrinsic. + + Example: + + ```mlir + %0 = cir.is_constant %expr : i32 -> !s32i + %1 = cir.is_constant %ptr : !cir.ptr<i32> -> !s32i + ``` + }]; + + let arguments = (ins CIR_AnyType:$value); + let results = (outs CIR_BoolType:$result); + + let assemblyFormat = [{ + `(` $value `:` type($value) `)` `:` type($result) attr-dict + }]; + + // let hasFolder = 1; + // let hasLLVMLowering = false; +} + //===----------------------------------------------------------------------===// // VecCreate //===----------------------------------------------------------------------===// @@ -4093,44 +4090,6 @@ def CIR_ExpectOp : CIR_Op<"expect", [ }]; } -//===----------------------------------------------------------------------===// -// IsConstantOp -//===----------------------------------------------------------------------===// - -def CIR_IsConstantOp : CIR_Op<"is_constant", [Pure]> { - let summary = "Check if a value is a compile-time constant"; - let description = [{ - The `cir.is_constant` operation checks whether its input value is a - compile-time constant. This operation models the `__builtin_constant_p` - builtin function. - - The operation takes a single operand of any CIR type and returns a signed - 32-bit integer. The result is 1 if the operand is a compile-time constant, - and 0 otherwise. - - If the value can be determined to be constant at compile time, this - operation may be folded to a constant value. Otherwise, it will be lowered - to the `llvm.is.constant` intrinsic. - - Example: - - ```mlir - %0 = cir.is_constant %expr : i32 -> !s32i - %1 = cir.is_constant %ptr : !cir.ptr<i32> -> !s32i - ``` - }]; - - let arguments = (ins CIR_AnyType:$value); - let results = (outs CIR_SInt32:$result); - - let assemblyFormat = [{ - $value `:` type($value) `->` type($result) attr-dict - }]; - - let hasFolder = 1; - let hasLLVMLowering = false; -} - //===----------------------------------------------------------------------===// // PrefetchOp //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 6ef4ee3dfe612..b7219063c9d43 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -201,28 +201,40 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, } case Builtin::BI__builtin_constant_p: { - auto loc = getLoc(e->getSourceRange()); - - Expr::EvalResult evalResult; - - // Try to evaluate at compile time first - if (e->getArg(0)->EvaluateAsRValue(evalResult, getContext()) && - !evalResult.hasSideEffects()) { - // Expression is a compile-time constant, return 1 - llvm::APInt apInt(32, 1); - llvm::APSInt apSInt(apInt, /*isUnsigned=*/false); - return RValue::get(builder.getConstInt(loc, apSInt)); - } - - // Expression cannot be evaluated at compile time, emit runtime check - mlir::Value argValue = emitScalarExpr(e->getArg(0)); - mlir::Type resultType = builder.getSInt32Ty(); - auto isConstantOp = cir::IsConstantOp::create(builder, loc, resultType, argValue); - mlir::Value resultValue = isConstantOp.getResult(); - mlir::Type exprTy = convertType(e->getType()); - if (exprTy != resultValue.getType()) - resultValue = builder.createIntCast(resultValue, exprTy); - return RValue::get(resultValue); + mlir::Location loc = getLoc(e->getSourceRange()); + 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<cir::IntType>(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<cir::IntType>(ResultType), 0)); + + mlir::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.getASTContext().getObjCIdType(); + 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::BIcos: _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
