diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 16258513239d9..5d0913dae3308 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -3043,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 -> !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 //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 4e6a5ee7ee210..b7219063c9d43 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -199,6 +199,43 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, return RValue::get( builder.createBitcast(allocaAddr, builder.getVoidPtrTy())); } + + case Builtin::BI__builtin_constant_p: { + 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(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()) + // 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: 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 //===----------------------------------------------------------------------===//