From 8c7235cdfa4ed58fcff6e5e0448dab39c06f2015 Mon Sep 17 00:00:00 2001 From: bruteforceboy Date: Wed, 25 Jun 2025 13:44:25 +0300 Subject: [PATCH 01/13] add CXXCtorDtor attribute --- .../include/clang/CIR/Dialect/IR/CIRAttrs.td | 62 ++++++- clang/include/clang/CIR/Dialect/IR/CIROps.td | 172 ++++++++++++------ clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp | 31 +++- clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp | 5 +- clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp | 22 ++- clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 21 ++- clang/lib/CIR/CodeGen/CIRGenModule.cpp | 21 +++ clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 100 +++++++++- .../Dialect/Transforms/CIRCanonicalize.cpp | 4 +- .../CIR/Dialect/Transforms/CIRSimplify.cpp | 30 ++- .../CIR/Dialect/Transforms/LifetimeCheck.cpp | 16 +- .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 2 +- .../ThroughMLIR/LowerCIRLoopToSCF.cpp | 14 +- .../Lowering/ThroughMLIR/LowerCIRToMLIR.cpp | 11 +- clang/test/CIR/CodeGen/X86/bmi-builtins.c | 32 ++++ clang/test/CIR/CodeGen/X86/builtins-x86.c | 9 - clang/test/CIR/CodeGen/X86/rd-builtins.c | 35 ++++ .../CodeGen/builtin-constant-evaluated.cpp | 34 +++- clang/test/CIR/CodeGen/complex-builtins.cpp | 21 +++ clang/test/CIR/CodeGen/complex.c | 101 +++++++--- clang/test/CIR/CodeGen/ctor-alias.cpp | 2 +- clang/test/CIR/CodeGen/static.cpp | 8 +- clang/test/CIR/CodeGen/temporaries.cpp | 4 +- clang/test/CIR/CodeGen/tempref.cpp | 2 +- .../CIR/CodeGen/virtual-destructor-calls.cpp | 8 +- .../ThroughMLIR/while-with-continue.cpp | 35 ++++ .../CIR/Transforms/vector-create-fold.cir | 19 ++ clang/test/CIR/Transforms/vector-splat.cir | 16 ++ .../CIR/Transforms/vector-ternary-fold.cir | 19 ++ 29 files changed, 714 insertions(+), 142 deletions(-) create mode 100644 clang/test/CIR/CodeGen/X86/bmi-builtins.c create mode 100644 clang/test/CIR/CodeGen/X86/rd-builtins.c create mode 100644 clang/test/CIR/CodeGen/complex-builtins.cpp create mode 100644 clang/test/CIR/Transforms/vector-create-fold.cir create mode 100644 clang/test/CIR/Transforms/vector-splat.cir create mode 100644 clang/test/CIR/Transforms/vector-ternary-fold.cir diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index cad530055ef4..414c94e639ab 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -1138,9 +1138,9 @@ def ASTCallExprAttr : AST<"CallExpr", "call.expr", //===----------------------------------------------------------------------===// def CIR_VisibilityKind : CIR_I32EnumAttr<"VisibilityKind", "C/C++ visibility", [ - I32EnumAttrCase<"Default", 1, "default">, - I32EnumAttrCase<"Hidden", 2, "hidden">, - I32EnumAttrCase<"Protected", 3, "protected"> + I32EnumAttrCase<"Default", 0, "default">, + I32EnumAttrCase<"Hidden", 1, "hidden">, + I32EnumAttrCase<"Protected", 2, "protected"> ]> { let genSpecializedAttr = 0; } @@ -1155,7 +1155,8 @@ def CIR_VisibilityAttr : CIR_EnumAttr { let skipDefaultBuilders = 1; let builders = [ - AttrBuilder<(ins CArg<"VisibilityKind", "cir::VisibilityKind::Default">:$value), [{ + AttrBuilder<(ins CArg<"VisibilityKind", + "cir::VisibilityKind::Default">:$value), [{ return $_get($_ctxt, value); }]> ]; @@ -1300,6 +1301,59 @@ def GlobalDtorAttr : CIR_GlobalCtorDtor<"Dtor", "dtor", "A function with this attribute excutes before module unloading" >; +class CIR_CXXSpecialMember : CIR_Attr { + let summary = sum; + let description = desc; + let skipDefaultBuilders = 1; +} + +def CXXCtorAttr + : CIR_CXXSpecialMember< + "CXXCtor", "cxx_ctor", "Marks a function as a CXX constructor", + "Functions with this attribute are CXX constructors"> { + let parameters = (ins "mlir::Type":$type, + "bool":$is_default_constructor, + "bool":$is_copy_constructor); + let assemblyFormat = [{ + `<` + $type `,` $is_default_constructor `,` $is_copy_constructor + `>` + }]; + let builders = + [AttrBuilder<(ins "mlir::Type":$type, + "bool":$is_default_constructor, + "bool":$is_copy_constructor), [{ + return $_get($_ctxt, type, is_default_constructor, + is_copy_constructor); + }]>, + AttrBuilderWithInferredContext<(ins "mlir::Type":$type, + "bool":$is_default_constructor, + "bool":$is_copy_constructor), [{ + return $_get(type.getContext(), type, + is_default_constructor, is_copy_constructor); + }]>]; +} + +def CXXDtorAttr + : CIR_CXXSpecialMember< + "CXXDtor", "cxx_dtor", "Marks a function as a CXX destructor", + "Functions with this attribute are CXX destructors"> { + let parameters = (ins "mlir::Type":$type); + let assemblyFormat = [{ + `<` + $type + `>` + }]; + let builders = + [AttrBuilder<(ins "mlir::Type":$type), [{ + return $_get($_ctxt, type); + }]>, + AttrBuilderWithInferredContext<(ins "mlir::Type":$type), [{ + return $_get(type.getContext(), type); + }]>]; +} + def BitfieldInfoAttr : CIR_Attr<"BitfieldInfo", "bitfield_info"> { let summary = "Represents a bit field info"; let description = [{ diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index c58d86850c6f..50ea3af4239d 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -87,32 +87,78 @@ class CIR_Op traits = []> : //===----------------------------------------------------------------------===// def CIR_CastKind : CIR_I32EnumAttr<"CastKind", "cast kind", [ - // The enumaration value isn't in sync with clang. - I32EnumAttrCase<"int_to_bool", 0>, - I32EnumAttrCase<"array_to_ptrdecay", 1>, - I32EnumAttrCase<"integral", 2>, - I32EnumAttrCase<"bitcast", 3>, - I32EnumAttrCase<"floating", 4>, - I32EnumAttrCase<"ptr_to_bool", 5>, - I32EnumAttrCase<"float_to_int", 6>, - I32EnumAttrCase<"int_to_ptr", 7>, - I32EnumAttrCase<"ptr_to_int", 8>, - I32EnumAttrCase<"float_to_bool", 9>, - I32EnumAttrCase<"bool_to_int", 10>, - I32EnumAttrCase<"int_to_float", 11>, - I32EnumAttrCase<"bool_to_float", 12>, - I32EnumAttrCase<"address_space", 13>, - I32EnumAttrCase<"float_to_complex", 14>, - I32EnumAttrCase<"int_to_complex", 15>, - I32EnumAttrCase<"float_complex_to_real", 16>, - I32EnumAttrCase<"int_complex_to_real", 17>, - I32EnumAttrCase<"float_complex_to_bool", 18>, - I32EnumAttrCase<"int_complex_to_bool", 19>, - I32EnumAttrCase<"float_complex", 20>, - I32EnumAttrCase<"float_complex_to_int_complex", 21>, - I32EnumAttrCase<"int_complex", 22>, - I32EnumAttrCase<"int_complex_to_float_complex", 23>, - I32EnumAttrCase<"member_ptr_to_bool", 24> + I32EnumAttrCase<"bitcast", 1>, + // CK_LValueBitCast + // CK_LValueToRValueBitCast + // CK_LValueToRValue + // CK_NoOp + // CK_BaseToDerived + // CK_DerivedToBase + // CK_UncheckedDerivedToBase + // CK_Dynamic + // CK_ToUnion + I32EnumAttrCase<"array_to_ptrdecay", 11>, + // CK_FunctionToPointerDecay + // CK_NullToPointer + // CK_NullToMemberPointer + // CK_BaseToDerivedMemberPointer + // CK_DerivedToBaseMemberPointer + I32EnumAttrCase<"member_ptr_to_bool", 17>, + // CK_ReinterpretMemberPointer + // CK_UserDefinedConversion + // CK_ConstructorConversion + I32EnumAttrCase<"int_to_ptr", 21>, + I32EnumAttrCase<"ptr_to_int", 22>, + I32EnumAttrCase<"ptr_to_bool", 23>, + // CK_ToVoid + // CK_MatrixCast + // CK_VectorSplat + I32EnumAttrCase<"integral", 27>, + I32EnumAttrCase<"int_to_bool", 28>, + I32EnumAttrCase<"int_to_float", 29>, + // CK_FloatingToFixedPoint + // CK_FixedPointToFloating + // CK_FixedPointCast + // CK_FixedPointToIntegral + // CK_IntegralToFixedPoint + // CK_FixedPointToBoolean + I32EnumAttrCase<"float_to_int", 36>, + I32EnumAttrCase<"float_to_bool", 37>, + I32EnumAttrCase<"bool_to_int", 38>, + I32EnumAttrCase<"floating", 39>, + // CK_CPointerToObjCPointerCast + // CK_BlockPointerToObjCPointerCast + // CK_AnyPointerToBlockPointerCast + // CK_ObjCObjectLValueCast + I32EnumAttrCase<"float_to_complex", 44>, + I32EnumAttrCase<"float_complex_to_real", 45>, + I32EnumAttrCase<"float_complex_to_bool", 46>, + I32EnumAttrCase<"float_complex", 47>, + I32EnumAttrCase<"float_complex_to_int_complex", 48>, + I32EnumAttrCase<"int_to_complex", 49>, + I32EnumAttrCase<"int_complex_to_real", 50>, + I32EnumAttrCase<"int_complex_to_bool", 51>, + I32EnumAttrCase<"int_complex", 52>, + I32EnumAttrCase<"int_complex_to_float_complex", 53>, + // CK_ARCProduceObject + // CK_ARCConsumeObject + // CK_ARCReclaimReturnedObject + // CK_ARCExtendBlockObject + // CK_AtomicToNonAtomic + // CK_NonAtomicToAtomic + // CK_CopyAndAutoreleaseBlockObject + // CK_BuiltinFnToFnPtr + // CK_ZeroToOCLOpaqueType + I32EnumAttrCase<"address_space", 63>, + // CK_IntToOCLSampler + // CK_HLSLVectorTruncation + // CK_HLSLArrayRValue + // CK_HLSLElementwiseCast + // CK_HLSLAggregateSplatCast + + // Enums below are specific to CIR and don't have a correspondence to classic + // codegen: + I32EnumAttrCase<"bool_to_float", 1000>, ]>; def CastOp : CIR_Op<"cast", @@ -121,39 +167,48 @@ def CastOp : CIR_Op<"cast", // FIXME: not all conversions are free of side effects. let summary = "Conversion between values of different types"; let description = [{ - Apply C/C++ usual conversions rules between values. Currently supported kinds: + Apply the usual C/C++ conversion rules between values. This operation models + a subset of conversions as defined in Clang's `OperationKinds.def` + (`llvm-project/clang/include/clang/AST/OperationKinds.def`). + + Note: not all conversions are implemented using `cir.cast`. For instance, + lvalue-to-rvalue conversion is modeled as a `cir.load` instead. Currently + supported kinds: - - `array_to_ptrdecay` - `bitcast` + - `array_to_ptrdecay` + - `member_ptr_to_bool + - `int_to_ptr` + - `ptr_to_int` + - `ptr_to_bool` - `integral` - `int_to_bool` - `int_to_float` - - `floating` - `float_to_int` - `float_to_bool` - - `ptr_to_int` - - `ptr_to_bool` - `bool_to_int` - - `bool_to_float` - - `address_space` + - `floating` - `float_to_complex` - - `int_to_complex` - `float_complex_to_real` - - `int_complex_to_real` - `float_complex_to_bool` - - `int_complex_to_bool` - `float_complex` - `float_complex_to_int_complex` + - `int_to_complex` + - `int_complex_to_real` + - `int_complex_to_bool` - `int_complex` - `int_complex_to_float_complex` + - `address_space` + + CIR also supports some additional conversions that are not part of the classic + Clang codegen: + + - `bool_to_float` - This is effectively a subset of the rules from - `llvm-project/clang/include/clang/AST/OperationKinds.def`; but note that some - of the conversions aren't implemented in terms of `cir.cast`, `lvalue-to-rvalue` - for instance is modeled as a regular `cir.load`. + Example: ```mlir - %4 = cir.cast (int_to_bool, %3 : i32), !cir.bool + %4 = cir.cast(int_to_bool, %3 : i32), !cir.bool ... %x = cir.cast(array_to_ptrdecay, %0 : !cir.ptr>), !cir.ptr ``` @@ -1846,10 +1901,10 @@ def CmpThreeWayOp : CIR_Op<"cmp3way", [Pure, SameTypeOperands]> { //===----------------------------------------------------------------------===// def CIR_CaseOpKind : CIR_I32EnumAttr<"CaseOpKind", "case kind", [ - I32EnumAttrCase<"Default", 1, "default">, - I32EnumAttrCase<"Equal", 2, "equal">, - I32EnumAttrCase<"Anyof", 3, "anyof">, - I32EnumAttrCase<"Range", 4, "range"> + I32EnumAttrCase<"Default", 0, "default">, + I32EnumAttrCase<"Equal", 1, "equal">, + I32EnumAttrCase<"Anyof", 2, "anyof">, + I32EnumAttrCase<"Range", 3, "range"> ]>; def CaseOp : CIR_Op<"case", [ @@ -3107,6 +3162,7 @@ def VecCreateOp : CIR_Op<"vec.create", [Pure]> { }]; let hasVerifier = 1; + let hasFolder = 1; } //===----------------------------------------------------------------------===// @@ -3169,7 +3225,7 @@ def VecCmpOp : CIR_Op<"vec.cmp", [Pure, SameTypeOperands]> { //===----------------------------------------------------------------------===// def VecTernaryOp : CIR_Op<"vec.ternary", - [Pure, AllTypesMatch<["result", "vec1", "vec2"]>]> { + [Pure, AllTypesMatch<["result", "lhs", "rhs"]>]> { let summary = "The `cond ? a : b` ternary operator for vector types"; let description = [{ The `cir.vec.ternary` operation represents the C/C++ ternary operator, @@ -3188,16 +3244,18 @@ def VecTernaryOp : CIR_Op<"vec.ternary", let arguments = (ins CIR_VectorOfIntType:$cond, - CIR_VectorType:$vec1, - CIR_VectorType:$vec2 + CIR_VectorType:$lhs, + CIR_VectorType:$rhs ); let results = (outs CIR_VectorType:$result); let assemblyFormat = [{ - `(` $cond `,` $vec1 `,` $vec2 `)` `:` qualified(type($cond)) `,` - qualified(type($vec1)) attr-dict + `(` $cond `,` $lhs `,` $rhs `)` `:` qualified(type($cond)) `,` + qualified(type($lhs)) attr-dict }]; + let hasVerifier = 1; + let hasFolder = 1; } //===----------------------------------------------------------------------===// @@ -3595,7 +3653,9 @@ def FuncOp : CIR_Op<"func", [ OptionalAttr:$global_ctor, OptionalAttr:$global_dtor, OptionalAttr:$annotations, - OptionalAttr:$ast + OptionalAttr:$ast, + OptionalAttr:$cxx_ctor, + OptionalAttr:$cxx_dtor ); let regions = (region AnyRegion:$body); @@ -3765,11 +3825,11 @@ def DeleteArrayOp : CIR_Op<"delete.array">, //===----------------------------------------------------------------------===// def CIR_SideEffect : CIR_I32EnumAttr< - "SideEffect", "allowed side effects of a function",[ - I32EnumAttrCase<"All", 1, "all">, - I32EnumAttrCase<"Pure", 2, "pure">, - I32EnumAttrCase<"Const", 3, "const"> - ]> { + "SideEffect", "allowed side effects of a function", [ + I32EnumAttrCase<"All", 0, "all">, + I32EnumAttrCase<"Pure", 1, "pure">, + I32EnumAttrCase<"Const", 2, "const"> +]> { let description = [{ The side effect attribute specifies the possible side effects of the callee of a call operation. This is an enumeration attribute and all possible diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp index 42f61fed74fb..5bd9f83c6b78 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltinX86.cpp @@ -145,19 +145,46 @@ mlir::Value CIRGenFunction::emitX86BuiltinExpr(unsigned BuiltinID, .getResult(); } case X86::BI__builtin_ia32_rdtscp: { - llvm_unreachable("__rdtscp NYI"); + // For rdtscp, we need to create a proper struct type to hold {i64, i32} + cir::RecordType resTy = builder.getAnonRecordTy( + {builder.getUInt64Ty(), builder.getUInt32Ty()}, false, false); + + auto call = builder + .create( + getLoc(E->getExprLoc()), + builder.getStringAttr("x86.rdtscp"), resTy) + .getResult(); + + // Store processor ID in address param + mlir::Value pID = builder.create( + getLoc(E->getExprLoc()), builder.getUInt32Ty(), call, 1); + builder.create(getLoc(E->getExprLoc()), pID, Ops[0]); + + // Return the timestamp at index 0 + return builder.create(getLoc(E->getExprLoc()), + builder.getUInt64Ty(), call, 0); } case X86::BI__builtin_ia32_lzcnt_u16: case X86::BI__builtin_ia32_lzcnt_u32: case X86::BI__builtin_ia32_lzcnt_u64: { mlir::Value V = builder.create( getLoc(E->getExprLoc()), cir::BoolAttr::get(&getMLIRContext(), false)); - return builder .create( getLoc(E->getExprLoc()), builder.getStringAttr("ctlz"), Ops[0].getType(), mlir::ValueRange{Ops[0], V}) .getResult(); } + case X86::BI__builtin_ia32_tzcnt_u16: + case X86::BI__builtin_ia32_tzcnt_u32: + case X86::BI__builtin_ia32_tzcnt_u64: { + mlir::Value V = builder.create( + getLoc(E->getExprLoc()), cir::BoolAttr::get(&getMLIRContext(), false)); + return builder + .create( + getLoc(E->getExprLoc()), builder.getStringAttr("cttz"), + Ops[0].getType(), mlir::ValueRange{Ops[0], V}) + .getResult(); + } } } diff --git a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp index 9c5708067402..1ed9b100411d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprComplex.cpp @@ -313,7 +313,10 @@ class ComplexExprEmitter : public StmtVisitor { VisitAbstractConditionalOperator(const AbstractConditionalOperator *CO) { llvm_unreachable("NYI"); } - mlir::Value VisitChooseExpr(ChooseExpr *CE) { llvm_unreachable("NYI"); } + + mlir::Value VisitChooseExpr(ChooseExpr *CE) { + return Visit(CE->getChosenSubExpr()); + } mlir::Value VisitInitListExpr(InitListExpr *E); diff --git a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp index 799d80d66a86..3a6cdd712d7d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp @@ -772,7 +772,11 @@ class ScalarExprEmitter : public StmtVisitor { mlir::Value VisitBlockExpr(const BlockExpr *E) { llvm_unreachable("NYI"); } mlir::Value VisitAbstractConditionalOperator(const AbstractConditionalOperator *E); - mlir::Value VisitChooseExpr(ChooseExpr *E) { llvm_unreachable("NYI"); } + + mlir::Value VisitChooseExpr(ChooseExpr *E) { + return Visit(E->getChosenSubExpr()); + } + mlir::Value VisitVAArgExpr(VAArgExpr *VE); mlir::Value VisitObjCStringLiteral(const ObjCStringLiteral *E) { llvm_unreachable("NYI"); @@ -2050,9 +2054,11 @@ mlir::Value ScalarExprEmitter::VisitReal(const UnaryOperator *E) { // If it's an l-value, load through the appropriate subobject l-value. // Note that we have to ask E because Op might be an l-value that // this won't work for, e.g. an Obj-C property. - if (E->isGLValue()) - return CGF.emitLoadOfLValue(CGF.emitLValue(E), E->getExprLoc()) - .getScalarVal(); + if (E->isGLValue()) { + mlir::Location Loc = CGF.getLoc(E->getExprLoc()); + mlir::Value Complex = CGF.emitComplexExpr(Op); + return CGF.builder.createComplexReal(Loc, Complex); + } // Otherwise, calculate and project. llvm_unreachable("NYI"); } @@ -2068,9 +2074,11 @@ mlir::Value ScalarExprEmitter::VisitImag(const UnaryOperator *E) { // If it's an l-value, load through the appropriate subobject l-value. // Note that we have to ask E because Op might be an l-value that // this won't work for, e.g. an Obj-C property. - if (E->isGLValue()) - return CGF.emitLoadOfLValue(CGF.emitLValue(E), E->getExprLoc()) - .getScalarVal(); + if (E->isGLValue()) { + mlir::Location Loc = CGF.getLoc(E->getExprLoc()); + mlir::Value Complex = CGF.emitComplexExpr(Op); + return CGF.builder.createComplexImag(Loc, Complex); + } // Otherwise, calculate and project. llvm_unreachable("NYI"); } diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index a65d02821de4..691a5b97d674 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -764,12 +764,25 @@ cir::FuncOp CIRGenFunction::generateCode(clang::GlobalDecl gd, cir::FuncOp fn, // Generate the body of the function. // TODO: PGO.assignRegionCounters assert(!cir::MissingFeatures::shouldInstrumentFunction()); - if (isa(fd)) + if (isa(fd)) { + auto dtor = dyn_cast(fd); + auto cxxDtor = cir::CXXDtorAttr::get( + &getMLIRContext(), + convertType(getContext().getRecordType(dtor->getParent()))); + fn.setCxxDtorAttr(cxxDtor); + emitDestructorBody(args); - else if (isa(fd)) + } else if (isa(fd)) { + auto ctor = dyn_cast(fd); + auto cxxCtor = cir::CXXCtorAttr::get( + &getMLIRContext(), + convertType(getContext().getRecordType(ctor->getParent())), + ctor->isDefaultConstructor(), ctor->isCopyConstructor()); + fn.setCxxCtorAttr(cxxCtor); + emitConstructorBody(args); - else if (getLangOpts().CUDA && !getLangOpts().CUDAIsDevice && - fd->hasAttr()) + } else if (getLangOpts().CUDA && !getLangOpts().CUDAIsDevice && + fd->hasAttr()) CGM.getCUDARuntime().emitDeviceStub(*this, fn, args); else if (isa(fd) && cast(fd)->isLambdaStaticInvoker()) { diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 09d2609cd7b3..655f2d614083 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -2739,6 +2739,27 @@ cir::FuncOp CIRGenModule::createCIRFunction(mlir::Location loc, StringRef name, f.setExtraAttrsAttr( cir::ExtraFuncAttributesAttr::get(builder.getDictionaryAttr({}))); + if (fd) { + CIRGenFunction cgf{*this, builder}; + + if (isa(fd)) { + auto dtor = dyn_cast(fd); + auto cxxDtor = cir::CXXDtorAttr::get( + &getMLIRContext(), + convertType(cgf.getContext().getRecordType(dtor->getParent()))); + f.setCxxDtorAttr(cxxDtor); + } + + if (isa(fd)) { + auto ctor = dyn_cast(fd); + auto cxxCtor = cir::CXXCtorAttr::get( + &getMLIRContext(), + convertType(cgf.getContext().getRecordType(ctor->getParent())), + ctor->isDefaultConstructor(), ctor->isCopyConstructor()); + f.setCxxCtorAttr(cxxCtor); + } + } + if (!curCGF) theModule.push_back(f); } diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 814a3e2091f6..697a5107b0be 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -1011,6 +1011,16 @@ void cir::StoreOp::setAtomic(cir::MemOrder order) { // VecCreateOp //===----------------------------------------------------------------------===// +OpFoldResult cir::VecCreateOp::fold(FoldAdaptor adaptor) { + if (llvm::any_of(getElements(), [](mlir::Value value) { + return !mlir::isa(value.getDefiningOp()); + })) + return {}; + + return cir::ConstVectorAttr::get( + getType(), mlir::ArrayAttr::get(getContext(), adaptor.getElements())); +} + LogicalResult cir::VecCreateOp::verify() { // Verify that the number of arguments matches the number of elements in the // vector, and that the type of all the arguments matches the type of the @@ -1036,16 +1046,48 @@ LogicalResult cir::VecCreateOp::verify() { // VecTernaryOp //===----------------------------------------------------------------------===// +OpFoldResult cir::VecTernaryOp::fold(FoldAdaptor adaptor) { + mlir::Attribute cond = adaptor.getCond(); + mlir::Attribute lhs = adaptor.getLhs(); + mlir::Attribute rhs = adaptor.getRhs(); + + if (!mlir::isa_and_nonnull(cond) || + !mlir::isa_and_nonnull(lhs) || + !mlir::isa_and_nonnull(rhs)) + return {}; + auto condVec = mlir::cast(cond); + auto lhsVec = mlir::cast(lhs); + auto rhsVec = mlir::cast(rhs); + + mlir::ArrayAttr condElts = condVec.getElts(); + + SmallVector elements; + elements.reserve(condElts.size()); + + for (const auto &[idx, condAttr] : + llvm::enumerate(condElts.getAsRange())) { + if (condAttr.getSInt()) { + elements.push_back(lhsVec.getElts()[idx]); + } else { + elements.push_back(rhsVec.getElts()[idx]); + } + } + + cir::VectorType vecTy = getLhs().getType(); + return cir::ConstVectorAttr::get( + vecTy, mlir::ArrayAttr::get(getContext(), elements)); +} + LogicalResult cir::VecTernaryOp::verify() { // Verify that the condition operand has the same number of elements as the // other operands. (The automatic verification already checked that all // operands are vector types and that the second and third operands are the // same type.) if (mlir::cast(getCond().getType()).getSize() != - getVec1().getType().getSize()) { + getLhs().getType().getSize()) { return emitOpError() << ": the number of elements in " - << getCond().getType() << " and " - << getVec1().getType() << " don't match"; + << getCond().getType() << " and " << getLhs().getType() + << " don't match"; } return success(); } @@ -2324,6 +2366,8 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) { auto visibilityNameAttr = getGlobalVisibilityAttrName(state.name); auto dsoLocalNameAttr = getDsoLocalAttrName(state.name); auto annotationsNameAttr = getAnnotationsAttrName(state.name); + auto cxxCtorAttr = getCxxCtorAttrName(state.name); + auto cxxDtorAttr = getCxxDtorAttrName(state.name); if (::mlir::succeeded(parser.parseOptionalKeyword(builtinNameAttr.strref()))) state.addAttribute(builtinNameAttr, parser.getBuilder().getUnitAttr()); if (::mlir::succeeded( @@ -2404,6 +2448,41 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) { state.addAttribute(annotationsNameAttr, annotations); } + // Add CXXSpecialMember attributes. + if (mlir::succeeded(parser.parseOptionalKeyword("ctor"))) { + if (parser.parseLess().failed()) + return failure(); + + mlir::Type type; + bool defaultCtor = false, copyCtor = false; + if (parser.parseType(type).failed()) + return failure(); + if (mlir::succeeded(parser.parseOptionalComma())) + if (mlir::succeeded(parser.parseOptionalKeyword("default_ctor"))) + defaultCtor = true; + if (mlir::succeeded(parser.parseOptionalComma())) + if (mlir::succeeded(parser.parseOptionalKeyword("copy_ctor"))) + copyCtor = true; + if (parser.parseGreater().failed()) + return failure(); + + state.addAttribute(cxxCtorAttr, + CXXCtorAttr::get(type, defaultCtor, copyCtor)); + } + + if (mlir::succeeded(parser.parseOptionalKeyword("dtor"))) { + if (parser.parseLess().failed()) + return failure(); + + mlir::Type type; + if (parser.parseType(type).failed()) + return failure(); + if (parser.parseGreater().failed()) + return failure(); + + state.addAttribute(cxxDtorAttr, CXXDtorAttr::get(type)); + } + // If additional attributes are present, parse them. if (parser.parseOptionalAttrDictWithKeyword(state.attributes)) return failure(); @@ -2584,6 +2663,19 @@ void cir::FuncOp::print(OpAsmPrinter &p) { p.printAttribute(annotations); } + if (auto cxxCtor = getCxxCtorAttr()) { + p << " ctor<" << cxxCtor.getType(); + if (cxxCtor.getIsDefaultConstructor()) + p << ", default_ctor"; + if (cxxCtor.getIsCopyConstructor()) + p << ", copy_ctor"; + p << '>'; + } + + if (auto cxxDtor = getCxxDtorAttr()) { + p << " dtor<" << cxxDtor.getType() << ">"; + } + function_interface_impl::printFunctionAttributes( p, *this, // These are all omitted since they are custom printed already. @@ -2594,7 +2686,7 @@ void cir::FuncOp::print(OpAsmPrinter &p) { getCallingConvAttrName(), getNoProtoAttrName(), getSymVisibilityAttrName(), getArgAttrsAttrName(), getResAttrsAttrName(), getComdatAttrName(), getGlobalVisibilityAttrName(), - getAnnotationsAttrName()}); + getAnnotationsAttrName(), getCxxCtorAttrName(), getCxxDtorAttrName()}); if (auto aliaseeName = getAliasee()) { p << " alias("; diff --git a/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp b/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp index f849b6cc08f8..c24e1872bd54 100644 --- a/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp +++ b/clang/lib/CIR/Dialect/Transforms/CIRCanonicalize.cpp @@ -179,8 +179,8 @@ void CIRCanonicalizePass::runOnOperation() { // CastOp, UnaryOp and VecExtractOp are here to perform a manual `fold` in // applyOpPatternsGreedily. if (isa(op)) + ComplexCreateOp, ComplexRealOp, ComplexImagOp, CallOp, VecCreateOp, + VecExtractOp, VecTernaryOp>(op)) ops.push_back(op); }); diff --git a/clang/lib/CIR/Dialect/Transforms/CIRSimplify.cpp b/clang/lib/CIR/Dialect/Transforms/CIRSimplify.cpp index 4cc0021ee287..7913a0ccebac 100644 --- a/clang/lib/CIR/Dialect/Transforms/CIRSimplify.cpp +++ b/clang/lib/CIR/Dialect/Transforms/CIRSimplify.cpp @@ -141,6 +141,31 @@ struct SimplifySelect : public OpRewritePattern { } }; +struct SimplifyVecSplat : public OpRewritePattern { + using OpRewritePattern::OpRewritePattern; + LogicalResult matchAndRewrite(VecSplatOp op, + PatternRewriter &rewriter) const override { + mlir::Value splatValue = op.getValue(); + auto constant = + mlir::dyn_cast_if_present(splatValue.getDefiningOp()); + if (!constant) + return mlir::failure(); + + auto value = constant.getValue(); + if (!mlir::isa_and_nonnull(value) && + !mlir::isa_and_nonnull(value)) + return mlir::failure(); + + cir::VectorType resultType = op.getResult().getType(); + SmallVector elements(resultType.getSize(), value); + auto constVecAttr = cir::ConstVectorAttr::get( + resultType, mlir::ArrayAttr::get(getContext(), elements)); + + rewriter.replaceOpWithNewOp(op, constVecAttr); + return mlir::success(); + } +}; + //===----------------------------------------------------------------------===// // CIRSimplifyPass //===----------------------------------------------------------------------===// @@ -155,7 +180,8 @@ void populateMergeCleanupPatterns(RewritePatternSet &patterns) { // clang-format off patterns.add< SimplifyTernary, - SimplifySelect + SimplifySelect, + SimplifyVecSplat >(patterns.getContext()); // clang-format on } @@ -168,7 +194,7 @@ void CIRSimplifyPass::runOnOperation() { // Collect operations to apply patterns. llvm::SmallVector ops; getOperation()->walk([&](Operation *op) { - if (isa(op)) + if (isa(op)) ops.push_back(op); }); diff --git a/clang/lib/CIR/Dialect/Transforms/LifetimeCheck.cpp b/clang/lib/CIR/Dialect/Transforms/LifetimeCheck.cpp index af909005b4a0..0f27c910a21b 100644 --- a/clang/lib/CIR/Dialect/Transforms/LifetimeCheck.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LifetimeCheck.cpp @@ -76,7 +76,7 @@ struct LifetimeCheckPass : public LifetimeCheckBase { void checkLambdaCaptureStore(StoreOp storeOp); void trackCallToCoroutine(CallOp callOp); - void checkCtor(CallOp callOp, ASTCXXConstructorDeclInterface ctor); + void checkCtor(CallOp callOp, cir::CXXCtorAttr ctor); void checkMoveAssignment(CallOp callOp, ASTCXXMethodDeclInterface m); void checkCopyAssignment(CallOp callOp, ASTCXXMethodDeclInterface m); void checkNonConstUseOfOwner(mlir::Value ownerAddr, mlir::Location loc); @@ -1549,8 +1549,7 @@ bool LifetimeCheckPass::isCtorInitPointerFromOwner(CallOp callOp) { return false; } -void LifetimeCheckPass::checkCtor(CallOp callOp, - ASTCXXConstructorDeclInterface ctor) { +void LifetimeCheckPass::checkCtor(CallOp callOp, cir::CXXCtorAttr ctor) { // TODO: zero init // 2.4.2 if the initialization is default initialization or zero // initialization, example: @@ -1559,7 +1558,7 @@ void LifetimeCheckPass::checkCtor(CallOp callOp, // string_view p; // // both results in pset(p) == {null} - if (ctor.isDefaultConstructor()) { + if (ctor.getIsDefaultConstructor()) { // First argument passed is always the alloca for the 'this' ptr. // Currently two possible actions: @@ -1583,7 +1582,7 @@ void LifetimeCheckPass::checkCtor(CallOp callOp, } // User defined copy ctor calls ... - if (ctor.isCopyConstructor()) { + if (ctor.getIsCopyConstructor()) { llvm_unreachable("NYI"); } @@ -1788,8 +1787,11 @@ void LifetimeCheckPass::checkCall(CallOp callOp) { // From this point on only owner and pointer class methods handling, // starting from special methods. - if (auto ctor = dyn_cast(methodDecl)) - return checkCtor(callOp, ctor); + if (auto fnName = callOp.getCallee()) { + auto calleeFuncOp = getCalleeFromSymbol(theModule, *fnName); + if (calleeFuncOp && calleeFuncOp.getCxxCtorAttr()) + return checkCtor(callOp, calleeFuncOp.getCxxCtorAttr()); + } if (methodDecl.isMoveAssignmentOperator()) return checkMoveAssignment(callOp, methodDecl); if (methodDecl.isCopyAssignmentOperator()) diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index 9e4c916882d3..da5c7d1782cf 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -2008,7 +2008,7 @@ mlir::LogicalResult CIRToLLVMVecTernaryOpLowering::matchAndRewrite( op.getCond().getLoc(), typeConverter->convertType(op.getCond().getType()))); rewriter.replaceOpWithNewOp( - op, bitVec, adaptor.getVec1(), adaptor.getVec2()); + op, bitVec, adaptor.getLhs(), adaptor.getRhs()); return mlir::success(); } diff --git a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRLoopToSCF.cpp b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRLoopToSCF.cpp index 01be972711b1..b7afcb9019f1 100644 --- a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRLoopToSCF.cpp +++ b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRLoopToSCF.cpp @@ -25,7 +25,6 @@ #include "clang/CIR/Dialect/IR/CIRTypes.h" #include "clang/CIR/LowerToMLIR.h" #include "llvm/ADT/TypeSwitch.h" -#include "llvm/IR/Module.h" using namespace cir; using namespace llvm; @@ -483,6 +482,19 @@ class CIRWhileOpLowering : public mlir::OpConversionPattern { return; for (auto continueOp : continues) { + bool nested = false; + // When there is another loop between this WhileOp and the ContinueOp, + // we shouldn't change that loop instead. + for (mlir::Operation *parent = continueOp->getParentOp(); + parent != whileOp; parent = parent->getParentOp()) { + if (isa(parent)) { + nested = true; + break; + } + } + if (nested) + continue; + // When the ContinueOp is under an IfOp, a direct replacement of // `scf.yield` won't work: the yield would jump out of that IfOp instead. // We might need to change the WhileOp itself to achieve the same effect. diff --git a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp index 71752bb19c25..5800773e715b 100644 --- a/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp +++ b/clang/lib/CIR/Lowering/ThroughMLIR/LowerCIRToMLIR.cpp @@ -1552,7 +1552,11 @@ void ConvertCIRToMLIRPass::runOnOperation() { mlir::scf::SCFDialect, mlir::cf::ControlFlowDialect, mlir::math::MathDialect, mlir::vector::VectorDialect, mlir::LLVM::LLVMDialect>(); - target.addIllegalDialect(); + // We cannot mark cir dialect as illegal before conversion. + // The conversion of WhileOp relies on partially preserving operations from + // cir dialect, for example the `cir.continue`. If we marked cir as illegal + // here, then MLIR would think any remaining `cir.continue` indicates a + // failure, which is not what we want. if (failed(applyPartialConversion(module, target, std::move(patterns)))) signalPassFailure(); @@ -1616,8 +1620,9 @@ mlir::ModuleOp lowerFromCIRToMLIR(mlir::ModuleOp theModule, auto result = !mlir::failed(pm.run(theModule)); if (!result) - report_fatal_error( - "The pass manager failed to lower CIR to MLIR standard dialects!"); + theModule.dump(), + report_fatal_error( + "The pass manager failed to lower CIR to MLIR standard dialects!"); // Now that we ran all the lowering passes, verify the final output. if (theModule.verify().failed()) report_fatal_error( diff --git a/clang/test/CIR/CodeGen/X86/bmi-builtins.c b/clang/test/CIR/CodeGen/X86/bmi-builtins.c new file mode 100644 index 000000000000..52d555bcd59f --- /dev/null +++ b/clang/test/CIR/CodeGen/X86/bmi-builtins.c @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -ffreestanding -triple x86_64-unknown-linux -Wno-implicit-function-declaration -fclangir -emit-cir -o %t.cir %s +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -ffreestanding -triple x86_64-unknown-linux -Wno-implicit-function-declaration -fclangir -emit-llvm -o %t.ll %s +// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s + +#include + +unsigned short test__tzcnt_u16(unsigned short __X) { + // CIR-LABEL: __tzcnt_u16 + // LLVM-LABEL: __tzcnt_u16 + return __tzcnt_u16(__X); + // CIR: {{%.*}} = cir.llvm.intrinsic "cttz" {{%.*}} : (!u16i, !cir.bool) -> !u16i + // LLVM: i16 @llvm.cttz.i16(i16 %{{.*}}, i1 false) +} + +unsigned int test__tzcnt_u32(unsigned int __X) { + // CIR-LABEL: __tzcnt_u32 + // LLVM-LABEL: __tzcnt_u32 + return __tzcnt_u32(__X); + // CIR: {{%.*}} = cir.llvm.intrinsic "cttz" {{%.*}} : (!u32i, !cir.bool) -> !u32i + // LLVM: i32 @llvm.cttz.i32(i32 %{{.*}}, i1 false) +} + +#ifdef __x86_64__ +unsigned long long test__tzcnt_u64(unsigned long long __X) { + // CIR-LABEL: __tzcnt_u64 + // LLVM-LABEL: __tzcnt_u64 + return __tzcnt_u64(__X); + // CIR: {{%.*}} = cir.llvm.intrinsic "cttz" {{%.*}} : (!u64i, !cir.bool) -> !u64i + // LLVM: i64 @llvm.cttz.i64(i64 %{{.*}}, i1 false) +} +#endif \ No newline at end of file diff --git a/clang/test/CIR/CodeGen/X86/builtins-x86.c b/clang/test/CIR/CodeGen/X86/builtins-x86.c index eeebec717bcd..c8d00aaf3bf2 100644 --- a/clang/test/CIR/CodeGen/X86/builtins-x86.c +++ b/clang/test/CIR/CodeGen/X86/builtins-x86.c @@ -45,12 +45,3 @@ void test_mm_sfence() { // CIR: {{%.*}} = cir.llvm.intrinsic "x86.sse.sfence" : () -> !void // LLVM: call void @llvm.x86.sse.sfence() } - -unsigned long long test_rdtsc() { - // CIR-LABEL: @test_rdtsc - // LLVM-LABEL: @test_rdtsc - return __rdtsc(); - // CIR: {{%.*}} = cir.llvm.intrinsic "x86.rdtsc" : () -> !u64i - // LLVM: call i64 @llvm.x86.rdtsc -} - diff --git a/clang/test/CIR/CodeGen/X86/rd-builtins.c b/clang/test/CIR/CodeGen/X86/rd-builtins.c new file mode 100644 index 000000000000..8f8902199b10 --- /dev/null +++ b/clang/test/CIR/CodeGen/X86/rd-builtins.c @@ -0,0 +1,35 @@ +// RUN: %clang_cc1 -ffreestanding -triple x86_64-unknown-linux -Wno-implicit-function-declaration -fclangir -emit-cir -o %t.cir %s +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -ffreestanding -triple x86_64-unknown-linux -Wno-implicit-function-declaration -fclangir -emit-llvm -o %t.ll %s +// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s + +// This test mimics clang/test/CodeGen/X86/rd-builtins.c, which eventually +// CIR shall be able to support fully. + +#include + +unsigned long long test_rdtsc() { + // CIR-LABEL: @test_rdtsc + // LLVM-LABEL: @test_rdtsc + return __rdtsc(); + // CIR: {{%.*}} = cir.llvm.intrinsic "x86.rdtsc" : () -> !u64i + // LLVM: call i64 @llvm.x86.rdtsc +} + +unsigned long long test_rdtscp(unsigned int *a) { + + return __rdtscp(a); + + // CIR-LABEL: @__rdtscp + // CIR: [[RDTSCP:%.*]] = cir.llvm.intrinsic "x86.rdtscp" : () -> !rec_anon_struct + // CIR: [[TSC_AUX:%.*]] = cir.extract_member [[RDTSCP]][1] : !rec_anon_struct -> !u32i + // CIR: cir.store [[TSC_AUX]], %{{.*}} : !u32i, !cir.ptr + // CIR: {{%.*}} = cir.extract_member [[RDTSCP]][0] : !rec_anon_struct -> !u64i + + // LLVM: @test_rdtscp + // LLVM: [[RDTSCP:%.*]] = call { i64, i32 } @llvm.x86.rdtscp + // LLVM: [[TSC_AUX:%.*]] = extractvalue { i64, i32 } [[RDTSCP]], 1 + // LLVM: store i32 [[TSC_AUX]], ptr %{{.*}} + // LLVM: [[TSC:%.*]] = extractvalue { i64, i32 } [[RDTSCP]], 0 +} + diff --git a/clang/test/CIR/CodeGen/builtin-constant-evaluated.cpp b/clang/test/CIR/CodeGen/builtin-constant-evaluated.cpp index c83a21f6708d..9d4d97994d67 100644 --- a/clang/test/CIR/CodeGen/builtin-constant-evaluated.cpp +++ b/clang/test/CIR/CodeGen/builtin-constant-evaluated.cpp @@ -1,12 +1,34 @@ // RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir // RUN: FileCheck %s --check-prefix=CIR --input-file=%t.cir -auto func() { +auto func() -> int { return __builtin_strcmp("", ""); // CIR: cir.func dso_local @_Z4funcv() - // CIR-NEXT: %0 = cir.alloca !s32i, !cir.ptr, ["__retval"] {alignment = 4 : i64} - // CIR-NEXT: %1 = cir.const #cir.int<0> : !s32i - // CIR-NEXT: cir.store %1, %0 : !s32i, !cir.ptr - // CIR-NEXT: %2 = cir.load{{.*}} %0 : !cir.ptr, !s32i - // CIR-NEXT: cir.return %2 : !s32i + // CIR-NEXT: %[[RET_VAL:.*]] = cir.alloca !s32i, !cir.ptr, ["__retval"] {alignment = 4 : i64} + // CIR-NEXT: %[[VAL:.*]] = cir.const #cir.int<0> : !s32i + // CIR-NEXT: cir.store %[[VAL]], %[[RET_VAL]] : !s32i, !cir.ptr + // CIR-NEXT: %[[TMP:.*]] = cir.load{{.*}} %0 : !cir.ptr, !s32i + // CIR-NEXT: cir.return %[[TMP]] : !s32i +} + +auto func2() -> int { + return __builtin_choose_expr(true, 1, 2); + + // CIR: cir.func dso_local @_Z5func2v() + // CIR-NEXT: %[[RET_VAL:.*]] = cir.alloca !s32i, !cir.ptr, ["__retval"] + // CIR-NEXT: %[[VAL:.*]] = cir.const #cir.int<1> : !s32i + // CIR-NEXT: cir.store %[[VAL]], %[[RET_VAL]] : !s32i, !cir.ptr + // CIR-NEXT: %[[TMP:.*]] = cir.load %[[RET_VAL]] : !cir.ptr, !s32i + // CIR-NEXT: cir.return %[[TMP]] : !s32i +} + +auto func3() -> int { + return __builtin_choose_expr(false, 1, 2); + + // CIR: cir.func dso_local @_Z5func3v() + // CIR-NEXT: %[[RET_VAL:.*]] = cir.alloca !s32i, !cir.ptr, ["__retval"] + // CIR-NEXT: %[[VAL:.*]] = cir.const #cir.int<2> : !s32i + // CIR-NEXT: cir.store %[[VAL]], %[[RET_VAL]] : !s32i, !cir.ptr + // CIR-NEXT: %[[TMP:.*]] = cir.load %[[RET_VAL]] : !cir.ptr, !s32i + // CIR-NEXT: cir.return %[[TMP]] : !s32i } diff --git a/clang/test/CIR/CodeGen/complex-builtins.cpp b/clang/test/CIR/CodeGen/complex-builtins.cpp new file mode 100644 index 000000000000..d0f47751a4d0 --- /dev/null +++ b/clang/test/CIR/CodeGen/complex-builtins.cpp @@ -0,0 +1,21 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM + +void complex_choose_expr() { + int _Complex a; + int _Complex b; + int _Complex r = __builtin_choose_expr(true, a, b); +} + +// CIR: %[[COMPLEX_A:.*]] = cir.alloca !cir.complex, !cir.ptr>, ["a"] +// CIR: %[[RESULT:.*]] = cir.alloca !cir.complex, !cir.ptr>, ["r", init] +// CIR: %[[TMP_A:.*]] = cir.load{{.*}} %[[COMPLEX_A]] : !cir.ptr>, !cir.complex +// CIR: cir.store{{.*}} %[[TMP_A]], %[[RESULT]] : !cir.complex, !cir.ptr> + +// LLVM: %[[COMPLEX_A:.*]] = alloca { i32, i32 }, i64 1, align 4 +// LLVM: %[[COMPLEX_B:.*]] = alloca { i32, i32 }, i64 1, align 4 +// LLVM: %[[RESULT:.*]] = alloca { i32, i32 }, i64 1, align 4 +// LLVM: %[[TMP_A:.*]] = load { i32, i32 }, ptr %[[COMPLEX_A]], align 4 +// LLVM: store { i32, i32 } %[[TMP_A]], ptr %[[RESULT]], align 4 diff --git a/clang/test/CIR/CodeGen/complex.c b/clang/test/CIR/CodeGen/complex.c index 9b19b39c578f..f3a2c6d8573a 100644 --- a/clang/test/CIR/CodeGen/complex.c +++ b/clang/test/CIR/CodeGen/complex.c @@ -261,25 +261,55 @@ void extract_real() { // CHECK-BEFORE: cir.func // CHECK-BEFORE: %[[#C_PTR:]] = cir.get_global @c : !cir.ptr> -// CHECK-BEFORE-NEXT: %[[#REAL_PTR:]] = cir.complex.real_ptr %[[#C_PTR]] : !cir.ptr> -> !cir.ptr -// CHECK-BEFORE-NEXT: %{{.+}} = cir.load{{.*}} %[[#REAL_PTR]] : !cir.ptr, !cir.double +// CHECK-BEFORE-NEXT: %[[COMPLEX:.*]] = cir.load{{.*}} %[[#C_PTR]] : !cir.ptr>, !cir.complex +// CHECK-BEFORE-NEXT: %[[#REAL:]] = cir.complex.real %[[COMPLEX]] : !cir.complex -> !cir.double // CHECK-BEFORE: %[[#CI_PTR:]] = cir.get_global @ci : !cir.ptr> -// CHECK-BEFORE-NEXT: %[[#REAL_PTR:]] = cir.complex.real_ptr %[[#CI_PTR]] : !cir.ptr> -> !cir.ptr -// CHECK-BEFORE-NEXT: %{{.+}} = cir.load{{.*}} %[[#REAL_PTR]] : !cir.ptr, !s32i +// CHECK-BEFORE-NEXT: %[[COMPLEX:.*]] = cir.load{{.*}} %[[#CI_PTR]] : !cir.ptr>, !cir.complex +// CHECK-BEFORE-NEXT: %[[#REAL:]] = cir.complex.real %[[COMPLEX]] : !cir.complex -> !s32i // CHECK-BEFORE: } // CHECK-AFTER: cir.func // CHECK-AFTER: %[[#C_PTR:]] = cir.get_global @c : !cir.ptr> -// CHECK-AFTER-NEXT: %[[#REAL_PTR:]] = cir.complex.real_ptr %[[#C_PTR]] : !cir.ptr> -> !cir.ptr -// CHECK-AFTER-NEXT: %{{.+}} = cir.load{{.*}} %[[#REAL_PTR]] : !cir.ptr, !cir.double +// CHECK-AFTER-NEXT: %[[COMPLEX:.*]] = cir.load{{.*}} %[[#C_PTR]] : !cir.ptr>, !cir.complex +// CHECK-AFTER-NEXT: %[[#REAL:]] = cir.complex.real %[[COMPLEX]] : !cir.complex -> !cir.double // CHECK-AFTER: %[[#CI_PTR:]] = cir.get_global @ci : !cir.ptr> -// CHECK-AFTER-NEXT: %[[#REAL_PTR:]] = cir.complex.real_ptr %[[#CI_PTR]] : !cir.ptr> -> !cir.ptr -// CHECK-AFTER-NEXT: %{{.+}} = cir.load{{.*}} %[[#REAL_PTR]] : !cir.ptr, !s32i +// CHECK-AFTER-NEXT: %[[COMPLEX:.*]] = cir.load{{.*}} %[[#CI_PTR]] : !cir.ptr>, !cir.complex +// CHECK-AFTER-NEXT: %[[#REAL:]] = cir.complex.real %[[COMPLEX]] : !cir.complex -> !s32i // CHECK-AFTER: } // LLVM: define dso_local void @extract_real() -// LLVM: %{{.+}} = load double, ptr @c, align 8 -// LLVM: %{{.+}} = load i32, ptr @ci, align 4 +// LLVM: %[[COMPLEX_D:.*]] = load { double, double }, ptr @c, align 8 +// LLVM: %[[R1:.*]] = extractvalue { double, double } %[[COMPLEX_D]], 0 +// LLVM: %[[COMPLEX_I:.*]] = load { i32, i32 }, ptr @ci, align 4 +// LLVM: %[[R2:.*]] = extractvalue { i32, i32 } %[[COMPLEX_I]], 0 +// LLVM: } + +int extract_real_and_add(int _Complex a, int _Complex b) { + return __real__ a + __real__ b; +} + +// CHECK-BEFORE: cir.func +// CHECK-BEFORE: %[[COMPLEX_A:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr>, !cir.complex +// CHECK-BEFORE-NEXT: %[[REAL_A:.*]] = cir.complex.real %[[COMPLEX_A]] : !cir.complex -> !s32i +// CHECK-BEFORE-NEXT: %[[COMPLEX_B:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr>, !cir.complex +// CHECK-BEFORE-NEXT: %[[REAL_B:.*]] = cir.complex.real %[[COMPLEX_B]] : !cir.complex -> !s32i +// CHECK-BEFORE-NEXT: %[[ADD:.*]] = cir.binop(add, %[[REAL_A]], %[[REAL_B]]) nsw : !s32i +// CHECK-BEFORE: } + +// CHECK-AFTER: cir.func +// CHECK-AFTER: %[[COMPLEX_A:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr>, !cir.complex +// CHECK-AFTER-NEXT: %[[REAL_A:.*]] = cir.complex.real %[[COMPLEX_A]] : !cir.complex -> !s32i +// CHECK-AFTER-NEXT: %[[COMPLEX_B:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr>, !cir.complex +// CHECK-AFTER-NEXT: %[[REAL_B:.*]] = cir.complex.real %[[COMPLEX_B]] : !cir.complex -> !s32i +// CHECK-AFTER-NEXT: %[[ADD:.*]] = cir.binop(add, %[[REAL_A]], %[[REAL_B]]) nsw : !s32i +// CHECK-AFTER: } + +// LLVM: define dso_local i32 @extract_real_and_add +// LLVM: %[[COMPLEX_A:.*]] = load { i32, i32 }, ptr {{.*}}, align 4 +// LLVM: %[[REAL_A:.*]] = extractvalue { i32, i32 } %[[COMPLEX_A]], 0 +// LLVM: %[[COMPLEX_B:.*]] = load { i32, i32 }, ptr {{.*}}, align 4 +// LLVM: %[[REAL_B:.*]] = extractvalue { i32, i32 } %[[COMPLEX_B]], 0 +// LLVM: %10 = add nsw i32 %[[REAL_A]], %[[REAL_B]] // LLVM: } void imag_ptr() { @@ -314,26 +344,55 @@ void extract_imag() { // CHECK-BEFORE: cir.func // CHECK-BEFORE: %[[#C_PTR:]] = cir.get_global @c : !cir.ptr> -// CHECK-BEFORE-NEXT: %[[#IMAG_PTR:]] = cir.complex.imag_ptr %[[#C_PTR]] : !cir.ptr> -> !cir.ptr -// CHECK-BEFORE-NEXT: %{{.+}} = cir.load{{.*}} %[[#IMAG_PTR]] : !cir.ptr, !cir.double +// CHECK-BEFORE-NEXT: %[[COMPLEX:.*]] = cir.load{{.*}} %[[#C_PTR]] : !cir.ptr>, !cir.complex +// CHECK-BEFORE-NEXT: %[[#IMAG:]] = cir.complex.imag %[[COMPLEX]] : !cir.complex -> !cir.double // CHECK-BEFORE: %[[#CI_PTR:]] = cir.get_global @ci : !cir.ptr> -// CHECK-BEFORE-NEXT: %[[#IMAG_PTR:]] = cir.complex.imag_ptr %[[#CI_PTR]] : !cir.ptr> -> !cir.ptr -// CHECK-BEFORE-NEXT: %{{.+}} = cir.load{{.*}} %[[#IMAG_PTR]] : !cir.ptr, !s32i +// CHECK-BEFORE-NEXT: %[[COMPLEX:.*]] = cir.load{{.*}} %[[#CI_PTR]] : !cir.ptr>, !cir.complex +// CHECK-BEFORE-NEXT: %[[#IMAG:]] = cir.complex.imag %[[COMPLEX]] : !cir.complex -> !s32i // CHECK-BEFORE: } // CHECK-AFTER: cir.func // CHECK-AFTER: %[[#C_PTR:]] = cir.get_global @c : !cir.ptr> -// CHECK-AFTER-NEXT: %[[#IMAG_PTR:]] = cir.complex.imag_ptr %[[#C_PTR]] : !cir.ptr> -> !cir.ptr -// CHECK-AFTER-NEXT: %{{.+}} = cir.load{{.*}} %[[#IMAG_PTR]] : !cir.ptr, !cir.double +// CHECK-AFTER-NEXT: %[[COMPLEX:.*]] = cir.load{{.*}} %[[#C_PTR]] : !cir.ptr>, !cir.complex +// CHECK-AFTER-NEXT: %[[#IMAG:]] = cir.complex.imag %[[COMPLEX]] : !cir.complex -> !cir.double // CHECK-AFTER: %[[#CI_PTR:]] = cir.get_global @ci : !cir.ptr> -// CHECK-AFTER-NEXT: %[[#IMAG_PTR:]] = cir.complex.imag_ptr %[[#CI_PTR]] : !cir.ptr> -> !cir.ptr -// CHECK-AFTER-NEXT: %{{.+}} = cir.load{{.*}} %[[#IMAG_PTR]] : !cir.ptr, !s32i +// CHECK-AFTER-NEXT: %[[COMPLEX:.*]] = cir.load{{.*}} %[[#CI_PTR]] : !cir.ptr>, !cir.complex +// CHECK-AFTER-NEXT: %[[#IMAG:]] = cir.complex.imag %[[COMPLEX]] : !cir.complex -> !s32i // CHECK-AFTER: } -// Note: GEP emitted by cir might not be the same as LLVM, due to constant folding. // LLVM: define dso_local void @extract_imag() -// LLVM: %{{.+}} = load double, ptr getelementptr inbounds nuw (i8, ptr @c, i64 8), align 8 -// LLVM: %{{.+}} = load i32, ptr getelementptr inbounds nuw (i8, ptr @ci, i64 4), align 4 +// LLVM: %[[COMPLEX_D:.*]] = load { double, double }, ptr @c, align 8 +// LLVM: %[[I1:.*]] = extractvalue { double, double } %[[COMPLEX_D]], 1 +// LLVM: %[[COMPLEX_I:.*]] = load { i32, i32 }, ptr @ci, align 4 +// LLVM: %[[I2:.*]] = extractvalue { i32, i32 } %[[COMPLEX_I]], 1 +// LLVM: } + +int extract_imag_and_add(int _Complex a, int _Complex b) { + return __imag__ a + __imag__ b; +} + +// CHECK-BEFORE: cir.func +// CHECK-BEFORE: %[[COMPLEX_A:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr>, !cir.complex +// CHECK-BEFORE-NEXT: %[[IMAG_A:.*]] = cir.complex.imag %[[COMPLEX_A]] : !cir.complex -> !s32i +// CHECK-BEFORE-NEXT: %[[COMPLEX_B:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr>, !cir.complex +// CHECK-BEFORE-NEXT: %[[IMAG_B:.*]] = cir.complex.imag %[[COMPLEX_B]] : !cir.complex -> !s32i +// CHECK-BEFORE-NEXT: %[[ADD:.*]] = cir.binop(add, %[[IMAG_A]], %[[IMAG_B]]) nsw : !s32i +// CHECK-BEFORE: } + +// CHECK-AFTER: cir.func +// CHECK-AFTER: %[[COMPLEX_A:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr>, !cir.complex +// CHECK-AFTER-NEXT: %[[IMAG_A:.*]] = cir.complex.imag %[[COMPLEX_A]] : !cir.complex -> !s32i +// CHECK-AFTER-NEXT: %[[COMPLEX_B:.*]] = cir.load{{.*}} {{.*}} : !cir.ptr>, !cir.complex +// CHECK-AFTER-NEXT: %[[IMAG_B:.*]] = cir.complex.imag %[[COMPLEX_B]] : !cir.complex -> !s32i +// CHECK-AFTER-NEXT: %[[ADD:.*]] = cir.binop(add, %[[IMAG_A]], %[[IMAG_B]]) nsw : !s32i +// CHECK-AFTER: } + +// LLVM: define dso_local i32 @extract_imag_and_add +// LLVM: %[[COMPLEX_A:.*]] = load { i32, i32 }, ptr {{.*}}, align 4 +// LLVM: %[[IMAG_A:.*]] = extractvalue { i32, i32 } %[[COMPLEX_A]], 1 +// LLVM: %[[COMPLEX_B:.*]] = load { i32, i32 }, ptr {{.*}}, align 4 +// LLVM: %[[IMAG_B:.*]] = extractvalue { i32, i32 } %[[COMPLEX_B]], 1 +// LLVM: %10 = add nsw i32 %[[IMAG_A]], %[[IMAG_B]] // LLVM: } void complex_with_empty_init() { int _Complex c = {}; } diff --git a/clang/test/CIR/CodeGen/ctor-alias.cpp b/clang/test/CIR/CodeGen/ctor-alias.cpp index 4afbdc12b3c1..19a475ea9556 100644 --- a/clang/test/CIR/CodeGen/ctor-alias.cpp +++ b/clang/test/CIR/CodeGen/ctor-alias.cpp @@ -37,4 +37,4 @@ B::B() { // CHECK: %1 = cir.load %0 : !cir.ptr>, !cir.ptr // CHECK: cir.return // CHECK: } -// CHECK: cir.func private dso_local @_ZN1BC1Ev(!cir.ptr) alias(@_ZN1BC2Ev) +// CHECK: cir.func private dso_local @_ZN1BC1Ev(!cir.ptr) ctor alias(@_ZN1BC2Ev) diff --git a/clang/test/CIR/CodeGen/static.cpp b/clang/test/CIR/CodeGen/static.cpp index 1f9e839dee8c..a77bcf53e728 100644 --- a/clang/test/CIR/CodeGen/static.cpp +++ b/clang/test/CIR/CodeGen/static.cpp @@ -17,8 +17,8 @@ static Init __ioinit(true); static Init __ioinit2(false); // BEFORE: module {{.*}} { -// BEFORE-NEXT: cir.func private @_ZN4InitC1Eb(!cir.ptr, !cir.bool) -// BEFORE-NEXT: cir.func private @_ZN4InitD1Ev(!cir.ptr) +// BEFORE-NEXT: cir.func private @_ZN4InitC1Eb(!cir.ptr, !cir.bool) ctor +// BEFORE-NEXT: cir.func private @_ZN4InitD1Ev(!cir.ptr) dtor // BEFORE-NEXT: cir.global "private" internal dso_local @_ZL8__ioinit = ctor : !rec_Init { // BEFORE-NEXT: %0 = cir.get_global @_ZL8__ioinit : !cir.ptr // BEFORE-NEXT: %1 = cir.const #true @@ -41,8 +41,8 @@ static Init __ioinit2(false); // AFTER: module {{.*}} attributes {{.*}}cir.global_ctors = [#cir.global_ctor<"__cxx_global_var_init", 65536>, #cir.global_ctor<"__cxx_global_var_init.1", 65536>] // AFTER-NEXT: cir.global "private" external @__dso_handle : i8 // AFTER-NEXT: cir.func private @__cxa_atexit(!cir.ptr)>>, !cir.ptr, !cir.ptr) -// AFTER-NEXT: cir.func private @_ZN4InitC1Eb(!cir.ptr, !cir.bool) -// AFTER-NEXT: cir.func private @_ZN4InitD1Ev(!cir.ptr) +// AFTER-NEXT: cir.func private @_ZN4InitC1Eb(!cir.ptr, !cir.bool) ctor +// AFTER-NEXT: cir.func private @_ZN4InitD1Ev(!cir.ptr) dtor // AFTER-NEXT: cir.global "private" internal dso_local @_ZL8__ioinit = #cir.zero : !rec_Init {alignment = 1 : i64, ast = #cir.var.decl.ast} // AFTER-NEXT: cir.func internal private @__cxx_global_var_init() // AFTER-NEXT: %0 = cir.get_global @_ZL8__ioinit : !cir.ptr diff --git a/clang/test/CIR/CodeGen/temporaries.cpp b/clang/test/CIR/CodeGen/temporaries.cpp index 1ac0b9a35014..dfaebd4c6101 100644 --- a/clang/test/CIR/CodeGen/temporaries.cpp +++ b/clang/test/CIR/CodeGen/temporaries.cpp @@ -14,9 +14,9 @@ void f() { !E(); } -// CIR: cir.func private @_ZN1EC1Ev(!cir.ptr) extra(#fn_attr) +// CIR: cir.func private @_ZN1EC1Ev(!cir.ptr) ctor extra(#fn_attr) // CIR-NEXT: cir.func private @_ZN1EntEv(!cir.ptr) -> !rec_E -// CIR-NEXT: cir.func private @_ZN1ED1Ev(!cir.ptr) extra(#fn_attr) +// CIR-NEXT: cir.func private @_ZN1ED1Ev(!cir.ptr) dtor extra(#fn_attr) // CIR-NEXT: cir.func dso_local @_Z1fv() extra(#fn_attr1) { // CIR-NEXT: cir.scope { // CIR-NEXT: %[[ONE:[0-9]+]] = cir.alloca !rec_E, !cir.ptr, ["agg.tmp.ensured"] {alignment = 1 : i64} diff --git a/clang/test/CIR/CodeGen/tempref.cpp b/clang/test/CIR/CodeGen/tempref.cpp index 89c0e195ea99..462bd4b2ae5b 100644 --- a/clang/test/CIR/CodeGen/tempref.cpp +++ b/clang/test/CIR/CodeGen/tempref.cpp @@ -6,7 +6,7 @@ struct A { ~A(); }; A &&a = dynamic_cast(A{}); -// CHECK: cir.func private @_ZN1AD1Ev(!cir.ptr) extra(#fn_attr) +// CHECK: cir.func private @_ZN1AD1Ev(!cir.ptr) dtor extra(#fn_attr) // CHECK-NEXT: cir.global external @a = #cir.ptr : !cir.ptr {alignment = 8 : i64, ast = #cir.var.decl.ast} // CHECK-NEXT: cir.func internal private @__cxx_global_var_init() { // CHECK-NEXT: cir.scope { diff --git a/clang/test/CIR/CodeGen/virtual-destructor-calls.cpp b/clang/test/CIR/CodeGen/virtual-destructor-calls.cpp index 874a0b75ca96..a920f6831565 100644 --- a/clang/test/CIR/CodeGen/virtual-destructor-calls.cpp +++ b/clang/test/CIR/CodeGen/virtual-destructor-calls.cpp @@ -32,7 +32,7 @@ struct B : A { // LLVM: call void @_ZN1AD2Ev // Complete dtor: just an alias because there are no virtual bases. -// CIR: cir.func private dso_local @_ZN1BD1Ev(!cir.ptr) alias(@_ZN1BD2Ev) +// CIR: cir.func private dso_local @_ZN1BD1Ev(!cir.ptr) dtor alias(@_ZN1BD2Ev) // FIXME: LLVM output should be: @_ZN1BD1Ev ={{.*}} unnamed_addr alias {{.*}} @_ZN1BD2Ev // LLVM: declare dso_local void @_ZN1BD1Ev(ptr) @@ -43,11 +43,11 @@ struct B : A { // (aliases from C) // CIR: cir.func dso_local @_ZN1CD2Ev(%arg0: !cir.ptr{{.*}})) {{.*}} { -// CIR: cir.func private dso_local @_ZN1CD1Ev(!cir.ptr) alias(@_ZN1CD2Ev) +// CIR: cir.func private dso_local @_ZN1CD1Ev(!cir.ptr) dtor alias(@_ZN1CD2Ev) // CIR_O1-NOT: cir.func dso_local @_ZN1CD2Ev(%arg0: !cir.ptr{{.*}})) {{.*}} { -// CIR_O1: cir.func private dso_local @_ZN1CD2Ev(!cir.ptr) alias(@_ZN1BD2Ev) -// CIR_O1: cir.func private dso_local @_ZN1CD1Ev(!cir.ptr) alias(@_ZN1CD2Ev) +// CIR_O1: cir.func private dso_local @_ZN1CD2Ev(!cir.ptr) dtor alias(@_ZN1BD2Ev) +// CIR_O1: cir.func private dso_local @_ZN1CD1Ev(!cir.ptr) dtor alias(@_ZN1CD2Ev) // FIXME: LLVM output should be: @_ZN1CD2Ev ={{.*}} unnamed_addr alias {{.*}} @_ZN1BD2Ev // LLVM: define dso_local void @_ZN1CD2Ev(ptr diff --git a/clang/test/CIR/Lowering/ThroughMLIR/while-with-continue.cpp b/clang/test/CIR/Lowering/ThroughMLIR/while-with-continue.cpp index 07ebcfab8ac9..fa13e11b80fb 100644 --- a/clang/test/CIR/Lowering/ThroughMLIR/while-with-continue.cpp +++ b/clang/test/CIR/Lowering/ThroughMLIR/while-with-continue.cpp @@ -68,3 +68,38 @@ void while_continue_2() { // CHECK: scf.yield // CHECK: } } + +void while_continue_nested() { + int i = 0; + while (i < 10) { + while (true) { + continue; + i--; + } + i++; + } + // The continue will only work on the inner while. + + // CHECK: scf.while : () -> () { + // CHECK: %[[IV:.+]] = memref.load %alloca[] + // CHECK: %[[TEN:.+]] = arith.constant 10 + // CHECK: %[[LT:.+]] = arith.cmpi slt, %[[IV]], %[[TEN]] + // CHECK: scf.condition(%[[LT]]) + // CHECK: } do { + // CHECK: memref.alloca_scope { + // CHECK: memref.alloca_scope { + // CHECK: scf.while : () -> () { + // CHECK: %[[TRUE:.+]] = arith.constant true + // CHECK: scf.condition(%[[TRUE]]) + // CHECK: } do { + // CHECK: scf.yield + // CHECK: } + // CHECK: } + // CHECK: %[[IV2:.+]] = memref.load %alloca[] + // CHECK: %[[ONE:.+]] = arith.constant 1 + // CHECK: %[[ADD:.+]] = arith.addi %[[IV2]], %[[ONE]] + // CHECK: memref.store %[[ADD]], %alloca[] + // CHECK: } + // CHECK: scf.yield + // CHECK: } +} diff --git a/clang/test/CIR/Transforms/vector-create-fold.cir b/clang/test/CIR/Transforms/vector-create-fold.cir new file mode 100644 index 000000000000..65bc51d8c36c --- /dev/null +++ b/clang/test/CIR/Transforms/vector-create-fold.cir @@ -0,0 +1,19 @@ +// RUN: cir-opt %s -cir-canonicalize -o - | FileCheck %s + +!s32i = !cir.int + +module { + cir.func @fold_create_vector_op_test() -> !cir.vector { + %2 = cir.const #cir.int<1> : !s32i + %3 = cir.const #cir.int<2> : !s32i + %4 = cir.const #cir.int<3> : !s32i + %5 = cir.const #cir.int<4> : !s32i + %vec = cir.vec.create(%2, %3, %4, %5 : !s32i, !s32i, !s32i, !s32i) : !cir.vector + cir.return %vec : !cir.vector + } + + // CHECK: cir.func @fold_create_vector_op_test() -> !cir.vector { + // CHECK-NEXT: %[[VEC:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, + // CHECK-SAME: #cir.int<3> : !s32i, #cir.int<4> : !s32i]> : !cir.vector + // CHECK-NEXT: cir.return %[[VEC]] : !cir.vector +} diff --git a/clang/test/CIR/Transforms/vector-splat.cir b/clang/test/CIR/Transforms/vector-splat.cir new file mode 100644 index 000000000000..76195c8a289e --- /dev/null +++ b/clang/test/CIR/Transforms/vector-splat.cir @@ -0,0 +1,16 @@ +// RUN: cir-opt %s -cir-simplify -o - | FileCheck %s + +!s32i = !cir.int + +module { + cir.func @fold_splat_vector_op_test() -> !cir.vector { + %v = cir.const #cir.int<3> : !s32i + %vec = cir.vec.splat %v : !s32i, !cir.vector + cir.return %vec : !cir.vector + } + + // CHECK: cir.func @fold_splat_vector_op_test() -> !cir.vector { + // CHECK-NEXT: %0 = cir.const #cir.const_vector<[#cir.int<3> : !s32i, #cir.int<3> : !s32i, + // CHECK-SAME: #cir.int<3> : !s32i, #cir.int<3> : !s32i]> : !cir.vector + // CHECK-NEXT: cir.return %0 : !cir.vector +} diff --git a/clang/test/CIR/Transforms/vector-ternary-fold.cir b/clang/test/CIR/Transforms/vector-ternary-fold.cir new file mode 100644 index 000000000000..49ee195ad545 --- /dev/null +++ b/clang/test/CIR/Transforms/vector-ternary-fold.cir @@ -0,0 +1,19 @@ +// RUN: cir-opt %s -cir-canonicalize -o - | FileCheck %s + +!s32i = !cir.int + +module { + cir.func @vector_ternary_fold_test() -> !cir.vector { + %cond = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<0> : !s32i, #cir.int<1> : !s32i, #cir.int<0> : !s32i]> : !cir.vector + %lhs = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : !s32i, #cir.int<4> : !s32i]> : !cir.vector + %rhs = cir.const #cir.const_vector<[#cir.int<5> : !s32i, #cir.int<6> : !s32i, #cir.int<7> : !s32i, #cir.int<8> : !s32i]> : !cir.vector + %res = cir.vec.ternary(%cond, %lhs, %rhs) : !cir.vector, !cir.vector + cir.return %res : !cir.vector + } + + // [1, 0, 1, 0] ? [1, 2, 3, 4] : [5, 6, 7, 8] Will be fold to [1, 6, 3, 8] + // CHECK: cir.func @vector_ternary_fold_test() -> !cir.vector { + // CHECK-NEXT: %[[RES:.*]] = cir.const #cir.const_vector<[#cir.int<1> : !s32i, #cir.int<6> : !s32i, #cir.int<3> : !s32i, #cir.int<8> : !s32i]> : !cir.vector + // CHECK-NEXT: cir.return %[[RES]] : !cir.vector +} + From d4c51f372c18478ced5579acb2343156214b9cb9 Mon Sep 17 00:00:00 2001 From: bruteforceboy Date: Wed, 25 Jun 2025 14:47:02 +0300 Subject: [PATCH 02/13] update --- clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 6 ++---- clang/lib/CIR/CodeGen/CIRGenModule.cpp | 6 ++---- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 18 ++++++++++-------- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index 691a5b97d674..0ca0a5cdbda2 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -764,16 +764,14 @@ cir::FuncOp CIRGenFunction::generateCode(clang::GlobalDecl gd, cir::FuncOp fn, // Generate the body of the function. // TODO: PGO.assignRegionCounters assert(!cir::MissingFeatures::shouldInstrumentFunction()); - if (isa(fd)) { - auto dtor = dyn_cast(fd); + if (auto dtor = dyn_cast(fd)) { auto cxxDtor = cir::CXXDtorAttr::get( &getMLIRContext(), convertType(getContext().getRecordType(dtor->getParent()))); fn.setCxxDtorAttr(cxxDtor); emitDestructorBody(args); - } else if (isa(fd)) { - auto ctor = dyn_cast(fd); + } else if (auto ctor = dyn_cast(fd)) { auto cxxCtor = cir::CXXCtorAttr::get( &getMLIRContext(), convertType(getContext().getRecordType(ctor->getParent())), diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 655f2d614083..3d663c3b268a 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -2742,16 +2742,14 @@ cir::FuncOp CIRGenModule::createCIRFunction(mlir::Location loc, StringRef name, if (fd) { CIRGenFunction cgf{*this, builder}; - if (isa(fd)) { - auto dtor = dyn_cast(fd); + if (auto dtor = dyn_cast(fd)) { auto cxxDtor = cir::CXXDtorAttr::get( &getMLIRContext(), convertType(cgf.getContext().getRecordType(dtor->getParent()))); f.setCxxDtorAttr(cxxDtor); } - if (isa(fd)) { - auto ctor = dyn_cast(fd); + if (auto ctor = dyn_cast(fd)) { auto cxxCtor = cir::CXXCtorAttr::get( &getMLIRContext(), convertType(cgf.getContext().getRecordType(ctor->getParent())), diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 697a5107b0be..06c50ef3a42c 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -2679,14 +2679,16 @@ void cir::FuncOp::print(OpAsmPrinter &p) { function_interface_impl::printFunctionAttributes( p, *this, // These are all omitted since they are custom printed already. - {getAliaseeAttrName(), getBuiltinAttrName(), getCoroutineAttrName(), - getDsoLocalAttrName(), getExtraAttrsAttrName(), - getFunctionTypeAttrName(), getGlobalCtorAttrName(), - getGlobalDtorAttrName(), getLambdaAttrName(), getLinkageAttrName(), - getCallingConvAttrName(), getNoProtoAttrName(), - getSymVisibilityAttrName(), getArgAttrsAttrName(), getResAttrsAttrName(), - getComdatAttrName(), getGlobalVisibilityAttrName(), - getAnnotationsAttrName(), getCxxCtorAttrName(), getCxxDtorAttrName()}); + {getAliaseeAttrName(), getBuiltinAttrName(), + getCoroutineAttrName(), getDsoLocalAttrName(), + getExtraAttrsAttrName(), getFunctionTypeAttrName(), + getGlobalCtorAttrName(), getGlobalDtorAttrName(), + getLambdaAttrName(), getLinkageAttrName(), + getCallingConvAttrName(), getNoProtoAttrName(), + getSymVisibilityAttrName(), getArgAttrsAttrName(), + getResAttrsAttrName(), getComdatAttrName(), + getGlobalVisibilityAttrName(), getAnnotationsAttrName(), + getCxxCtorAttrName(), getCxxDtorAttrName()}); if (auto aliaseeName = getAliasee()) { p << " alias("; From c3480fdc5d6f0f97e27195339d55905a675f03d1 Mon Sep 17 00:00:00 2001 From: bruteforceboy Date: Wed, 25 Jun 2025 16:53:51 +0300 Subject: [PATCH 03/13] add curleys --- clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index 0ca0a5cdbda2..43b6342b3aa2 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -780,10 +780,10 @@ cir::FuncOp CIRGenFunction::generateCode(clang::GlobalDecl gd, cir::FuncOp fn, emitConstructorBody(args); } else if (getLangOpts().CUDA && !getLangOpts().CUDAIsDevice && - fd->hasAttr()) + fd->hasAttr()) { CGM.getCUDARuntime().emitDeviceStub(*this, fn, args); - else if (isa(fd) && - cast(fd)->isLambdaStaticInvoker()) { + } else if (isa(fd) && + cast(fd)->isLambdaStaticInvoker()) { // The lambda static invoker function is special, because it forwards or // clones the body of the function call operator (but is actually // static). @@ -799,8 +799,9 @@ cir::FuncOp CIRGenFunction::generateCode(clang::GlobalDecl gd, cir::FuncOp fn, fn.erase(); return nullptr; } - } else + } else { llvm_unreachable("no definition for emitted function"); + } assert(builder.getInsertionBlock() && "Should be valid"); From f10b62f16c4a3060f3794940f86b49595cddc2d7 Mon Sep 17 00:00:00 2001 From: bruteforceboy Date: Fri, 27 Jun 2025 13:10:35 +0300 Subject: [PATCH 04/13] review comments & add cir-opt --- .../include/clang/CIR/Dialect/IR/CIRAttrs.td | 21 ++++++++++++------- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 13 +++++++----- clang/test/CIR/CodeGen/ctor-alias.cpp | 2 +- clang/test/CIR/CodeGen/temporaries.cpp | 2 +- clang/test/CIR/IR/cxx-special-member.cir | 10 +++++++++ 5 files changed, 34 insertions(+), 14 deletions(-) create mode 100644 clang/test/CIR/IR/cxx-special-member.cir diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index 414c94e639ab..7f8bf93e7d6b 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -1301,17 +1301,22 @@ def GlobalDtorAttr : CIR_GlobalCtorDtor<"Dtor", "dtor", "A function with this attribute excutes before module unloading" >; -class CIR_CXXSpecialMember : CIR_Attr { +class CIR_CXXSpecialMember + : CIR_Attr { let summary = sum; - let description = desc; let skipDefaultBuilders = 1; } def CXXCtorAttr : CIR_CXXSpecialMember< - "CXXCtor", "cxx_ctor", "Marks a function as a CXX constructor", - "Functions with this attribute are CXX constructors"> { + "CXXCtor", "cxx_ctor", "Marks a function as a CXX constructor"> { + let description = [{ + Functions with this attribute are CXX constructors. + The `is_default_constructor` parameter is a boolean which is set to + true if the constructor is a default constructor and false otherwise. + The `is_copy_constructor` parameter is a boolean which is set to + true if the constructor is a copy constructor and false otherwise. + }]; let parameters = (ins "mlir::Type":$type, "bool":$is_default_constructor, "bool":$is_copy_constructor); @@ -1337,8 +1342,10 @@ def CXXCtorAttr def CXXDtorAttr : CIR_CXXSpecialMember< - "CXXDtor", "cxx_dtor", "Marks a function as a CXX destructor", - "Functions with this attribute are CXX destructors"> { + "CXXDtor", "cxx_dtor", "Marks a function as a CXX destructor"> { + let description = [{ + Functions with this attribute are CXX destructors + }]; let parameters = (ins "mlir::Type":$type); let assemblyFormat = [{ `<` diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 06c50ef3a42c..f1ade4d7e08a 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -2457,11 +2457,14 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) { bool defaultCtor = false, copyCtor = false; if (parser.parseType(type).failed()) return failure(); - if (mlir::succeeded(parser.parseOptionalComma())) - if (mlir::succeeded(parser.parseOptionalKeyword("default_ctor"))) + if (mlir::succeeded(parser.parseOptionalComma())) { + if (mlir::succeeded(parser.parseOptionalKeyword("default"))) defaultCtor = true; + if (mlir::succeeded(parser.parseOptionalKeyword("copy"))) + copyCtor = true; + } if (mlir::succeeded(parser.parseOptionalComma())) - if (mlir::succeeded(parser.parseOptionalKeyword("copy_ctor"))) + if (mlir::succeeded(parser.parseOptionalKeyword("copy"))) copyCtor = true; if (parser.parseGreater().failed()) return failure(); @@ -2666,9 +2669,9 @@ void cir::FuncOp::print(OpAsmPrinter &p) { if (auto cxxCtor = getCxxCtorAttr()) { p << " ctor<" << cxxCtor.getType(); if (cxxCtor.getIsDefaultConstructor()) - p << ", default_ctor"; + p << ", default"; if (cxxCtor.getIsCopyConstructor()) - p << ", copy_ctor"; + p << ", copy"; p << '>'; } diff --git a/clang/test/CIR/CodeGen/ctor-alias.cpp b/clang/test/CIR/CodeGen/ctor-alias.cpp index 19a475ea9556..3182541d14f3 100644 --- a/clang/test/CIR/CodeGen/ctor-alias.cpp +++ b/clang/test/CIR/CodeGen/ctor-alias.cpp @@ -37,4 +37,4 @@ B::B() { // CHECK: %1 = cir.load %0 : !cir.ptr>, !cir.ptr // CHECK: cir.return // CHECK: } -// CHECK: cir.func private dso_local @_ZN1BC1Ev(!cir.ptr) ctor alias(@_ZN1BC2Ev) +// CHECK: cir.func private dso_local @_ZN1BC1Ev(!cir.ptr) ctor alias(@_ZN1BC2Ev) diff --git a/clang/test/CIR/CodeGen/temporaries.cpp b/clang/test/CIR/CodeGen/temporaries.cpp index dfaebd4c6101..daad82a181af 100644 --- a/clang/test/CIR/CodeGen/temporaries.cpp +++ b/clang/test/CIR/CodeGen/temporaries.cpp @@ -14,7 +14,7 @@ void f() { !E(); } -// CIR: cir.func private @_ZN1EC1Ev(!cir.ptr) ctor extra(#fn_attr) +// CIR: cir.func private @_ZN1EC1Ev(!cir.ptr) ctor extra(#fn_attr) // CIR-NEXT: cir.func private @_ZN1EntEv(!cir.ptr) -> !rec_E // CIR-NEXT: cir.func private @_ZN1ED1Ev(!cir.ptr) dtor extra(#fn_attr) // CIR-NEXT: cir.func dso_local @_Z1fv() extra(#fn_attr1) { diff --git a/clang/test/CIR/IR/cxx-special-member.cir b/clang/test/CIR/IR/cxx-special-member.cir new file mode 100644 index 000000000000..bb29cee9c57a --- /dev/null +++ b/clang/test/CIR/IR/cxx-special-member.cir @@ -0,0 +1,10 @@ +// RUN: cir-opt %s + +!s32i = !cir.int +!rec_S = !cir.record +module { + cir.func private @_ZN1SC1ERKS_(!cir.ptr, !cir.ptr) ctor + cir.func private @_ZN1SC2Ei(!cir.ptr, !cir.ptr) ctor + cir.func private @_ZN1SC2Ev(!cir.ptr) ctor + cir.func private @_ZN1SD2Ev(!cir.ptr) dtor +} From f6aaa4de51212909ec868f3326e31e1ece8ec2f4 Mon Sep 17 00:00:00 2001 From: bruteforceboy Date: Fri, 27 Jun 2025 15:00:19 +0300 Subject: [PATCH 05/13] update test & improve parsing --- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 23 +++++++++++++++-------- clang/test/CIR/IR/cxx-special-member.cir | 12 +++++++++++- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 3adf574fe604..99aba9b40460 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -2454,18 +2454,25 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) { return failure(); mlir::Type type; - bool defaultCtor = false, copyCtor = false; if (parser.parseType(type).failed()) return failure(); + + bool defaultCtor = false, copyCtor = false; if (mlir::succeeded(parser.parseOptionalComma())) { - if (mlir::succeeded(parser.parseOptionalKeyword("default"))) - defaultCtor = true; - if (mlir::succeeded(parser.parseOptionalKeyword("copy"))) - copyCtor = true; + if (parser + .parseCommaSeparatedList([&]() { + if (mlir::succeeded(parser.parseOptionalKeyword("default"))) + defaultCtor = true; + else if (mlir::succeeded(parser.parseOptionalKeyword("copy"))) + copyCtor = true; + else + return failure(); + return success(); + }) + .failed()) + return failure(); } - if (mlir::succeeded(parser.parseOptionalComma())) - if (mlir::succeeded(parser.parseOptionalKeyword("copy"))) - copyCtor = true; + if (parser.parseGreater().failed()) return failure(); diff --git a/clang/test/CIR/IR/cxx-special-member.cir b/clang/test/CIR/IR/cxx-special-member.cir index bb29cee9c57a..ce2e6ac2f910 100644 --- a/clang/test/CIR/IR/cxx-special-member.cir +++ b/clang/test/CIR/IR/cxx-special-member.cir @@ -1,4 +1,5 @@ -// RUN: cir-opt %s +// RUN: cir-opt %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s !s32i = !cir.int !rec_S = !cir.record @@ -8,3 +9,12 @@ module { cir.func private @_ZN1SC2Ev(!cir.ptr) ctor cir.func private @_ZN1SD2Ev(!cir.ptr) dtor } + +// CHECK: !s32i = !cir.int +// CHECK: !rec_S = !cir.record +// CHECK: module { +// CHECK: cir.func private @_ZN1SC1ERKS_(!cir.ptr, !cir.ptr) ctor +// CHECK: cir.func private @_ZN1SC2Ei(!cir.ptr, !cir.ptr) ctor +// CHECK: cir.func private @_ZN1SC2Ev(!cir.ptr) ctor +// CHECK: cir.func private @_ZN1SD2Ev(!cir.ptr) dtor +// CHECK: } From 5de2d7a5cfd19f689e3dd626d3b503723caafaab Mon Sep 17 00:00:00 2001 From: bruteforceboy Date: Thu, 3 Jul 2025 14:58:37 +0300 Subject: [PATCH 06/13] apply review comments --- .../include/clang/CIR/Dialect/IR/CIRAttrs.td | 57 ++++++++----------- clang/include/clang/CIR/Dialect/IR/CIROps.td | 3 +- clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 13 +++-- clang/lib/CIR/CodeGen/CIRGenModule.cpp | 18 +++--- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 52 +++++++++-------- .../CIR/Dialect/Transforms/LifetimeCheck.cpp | 10 ++-- 6 files changed, 80 insertions(+), 73 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index cf319cc64825..13ca53417897 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -1301,48 +1301,39 @@ def GlobalDtorAttr : CIR_GlobalCtorDtor<"Dtor", "dtor", "A function with this attribute excutes before module unloading" >; -class CIR_CXXSpecialMember - : CIR_Attr { - let summary = sum; - let skipDefaultBuilders = 1; +def CIR_CtorKind : CIR_I32EnumAttr<"CtorKind", "CXX Constructor Kind", [ + I32EnumAttrCase<"None", 0, "none">, + I32EnumAttrCase<"Default", 1, "default">, + I32EnumAttrCase<"Copy", 2, "copy">, +]> { + let genSpecializedAttr = 0; } -def CXXCtorAttr - : CIR_CXXSpecialMember< - "CXXCtor", "cxx_ctor", "Marks a function as a CXX constructor"> { +def CIR_CXXCtorAttr + : CIR_Attr<"CXXCtor", "cxx_ctor"> { + let summary = "Marks a function as a CXX constructor"; let description = [{ Functions with this attribute are CXX constructors. - The `is_default_constructor` parameter is a boolean which is set to - true if the constructor is a default constructor and false otherwise. - The `is_copy_constructor` parameter is a boolean which is set to - true if the constructor is a copy constructor and false otherwise. + The `default` kind is used if the constructor is a default constructor. + The `copy` kind is used if the constructor is a copy constructor. }]; let parameters = (ins "mlir::Type":$type, - "bool":$is_default_constructor, - "bool":$is_copy_constructor); + EnumParameter:$ctorKind); let assemblyFormat = [{ `<` - $type `,` $is_default_constructor `,` $is_copy_constructor + $type `,` $ctorKind `>` }]; let builders = - [AttrBuilder<(ins "mlir::Type":$type, - "bool":$is_default_constructor, - "bool":$is_copy_constructor), [{ - return $_get($_ctxt, type, is_default_constructor, - is_copy_constructor); - }]>, - AttrBuilderWithInferredContext<(ins "mlir::Type":$type, - "bool":$is_default_constructor, - "bool":$is_copy_constructor), [{ - return $_get(type.getContext(), type, - is_default_constructor, is_copy_constructor); + [AttrBuilderWithInferredContext<(ins "mlir::Type":$type, + CArg<"CtorKind", "cir::CtorKind::None">:$ctorKind), [{ + return $_get(type.getContext(), type, ctorKind); }]>]; } -def CXXDtorAttr - : CIR_CXXSpecialMember< - "CXXDtor", "cxx_dtor", "Marks a function as a CXX destructor"> { +def CIR_CXXDtorAttr + : CIR_Attr<"CXXDtor", "cxx_dtor"> { + let summary = "Marks a function as a CXX destructor"; let description = [{ Functions with this attribute are CXX destructors }]; @@ -1353,14 +1344,16 @@ def CXXDtorAttr `>` }]; let builders = - [AttrBuilder<(ins "mlir::Type":$type), [{ - return $_get($_ctxt, type); - }]>, - AttrBuilderWithInferredContext<(ins "mlir::Type":$type), [{ + [AttrBuilderWithInferredContext<(ins "mlir::Type":$type), [{ return $_get(type.getContext(), type); }]>]; } +def CIR_CXXSpecialMemberAttr : AnyAttrOf<[ + CIR_CXXCtorAttr, + CIR_CXXDtorAttr +]>; + def BitfieldInfoAttr : CIR_Attr<"BitfieldInfo", "bitfield_info"> { let summary = "Represents a bit field info"; let description = [{ diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 50ea3af4239d..6e752b386c04 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -3654,8 +3654,7 @@ def FuncOp : CIR_Op<"func", [ OptionalAttr:$global_dtor, OptionalAttr:$annotations, OptionalAttr:$ast, - OptionalAttr:$cxx_ctor, - OptionalAttr:$cxx_dtor + OptionalAttr:$cxx_special_member ); let regions = (region AnyRegion:$body); diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index 43b6342b3aa2..ab2a8b51ac73 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -768,15 +768,20 @@ cir::FuncOp CIRGenFunction::generateCode(clang::GlobalDecl gd, cir::FuncOp fn, auto cxxDtor = cir::CXXDtorAttr::get( &getMLIRContext(), convertType(getContext().getRecordType(dtor->getParent()))); - fn.setCxxDtorAttr(cxxDtor); + fn.setCxxSpecialMemberAttr(cxxDtor); emitDestructorBody(args); } else if (auto ctor = dyn_cast(fd)) { + cir::CtorKind ctorKind = cir::CtorKind::None; + if (ctor->isDefaultConstructor()) + ctorKind = cir::CtorKind::Default; + if (ctor->isCopyConstructor()) + ctorKind = cir::CtorKind::Copy; + auto cxxCtor = cir::CXXCtorAttr::get( &getMLIRContext(), - convertType(getContext().getRecordType(ctor->getParent())), - ctor->isDefaultConstructor(), ctor->isCopyConstructor()); - fn.setCxxCtorAttr(cxxCtor); + convertType(getContext().getRecordType(ctor->getParent())), ctorKind); + fn.setCxxSpecialMemberAttr(cxxCtor); emitConstructorBody(args); } else if (getLangOpts().CUDA && !getLangOpts().CUDAIsDevice && diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index 3d663c3b268a..b15c6120b7ce 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -2740,21 +2740,25 @@ cir::FuncOp CIRGenModule::createCIRFunction(mlir::Location loc, StringRef name, cir::ExtraFuncAttributesAttr::get(builder.getDictionaryAttr({}))); if (fd) { - CIRGenFunction cgf{*this, builder}; - if (auto dtor = dyn_cast(fd)) { auto cxxDtor = cir::CXXDtorAttr::get( &getMLIRContext(), - convertType(cgf.getContext().getRecordType(dtor->getParent()))); - f.setCxxDtorAttr(cxxDtor); + convertType(getASTContext().getRecordType(dtor->getParent()))); + f.setCxxSpecialMemberAttr(cxxDtor); } if (auto ctor = dyn_cast(fd)) { + cir::CtorKind ctorKind = cir::CtorKind::None; + if (ctor->isDefaultConstructor()) + ctorKind = cir::CtorKind::Default; + if (ctor->isCopyConstructor()) + ctorKind = cir::CtorKind::Copy; + auto cxxCtor = cir::CXXCtorAttr::get( &getMLIRContext(), - convertType(cgf.getContext().getRecordType(ctor->getParent())), - ctor->isDefaultConstructor(), ctor->isCopyConstructor()); - f.setCxxCtorAttr(cxxCtor); + convertType(getASTContext().getRecordType(ctor->getParent())), + ctorKind); + f.setCxxSpecialMemberAttr(cxxCtor); } } diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 99aba9b40460..8d7d05598c7c 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -2366,8 +2366,8 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) { auto visibilityNameAttr = getGlobalVisibilityAttrName(state.name); auto dsoLocalNameAttr = getDsoLocalAttrName(state.name); auto annotationsNameAttr = getAnnotationsAttrName(state.name); - auto cxxCtorAttr = getCxxCtorAttrName(state.name); - auto cxxDtorAttr = getCxxDtorAttrName(state.name); + auto cxxCtorAttr = getCxxSpecialMemberAttrName(state.name); + auto cxxDtorAttr = getCxxSpecialMemberAttrName(state.name); if (::mlir::succeeded(parser.parseOptionalKeyword(builtinNameAttr.strref()))) state.addAttribute(builtinNameAttr, parser.getBuilder().getUnitAttr()); if (::mlir::succeeded( @@ -2476,8 +2476,12 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) { if (parser.parseGreater().failed()) return failure(); - state.addAttribute(cxxCtorAttr, - CXXCtorAttr::get(type, defaultCtor, copyCtor)); + cir::CtorKind ctorKind = cir::CtorKind::None; + if (defaultCtor) + ctorKind = cir::CtorKind::Default; + if (copyCtor) + ctorKind = cir::CtorKind::Copy; + state.addAttribute(cxxCtorAttr, CXXCtorAttr::get(type, ctorKind)); } if (mlir::succeeded(parser.parseOptionalKeyword("dtor"))) { @@ -2673,32 +2677,32 @@ void cir::FuncOp::print(OpAsmPrinter &p) { p.printAttribute(annotations); } - if (auto cxxCtor = getCxxCtorAttr()) { - p << " ctor<" << cxxCtor.getType(); - if (cxxCtor.getIsDefaultConstructor()) - p << ", default"; - if (cxxCtor.getIsCopyConstructor()) - p << ", copy"; - p << '>'; - } + if (getCxxSpecialMember()) { + if (auto cxxCtor = dyn_cast(*getCxxSpecialMember())) { + p << " ctor<" << cxxCtor.getType(); + if (cxxCtor.getCtorKind() == cir::CtorKind::Default) + p << ", default"; + if (cxxCtor.getCtorKind() == cir::CtorKind::Copy) + p << ", copy"; + p << '>'; + } - if (auto cxxDtor = getCxxDtorAttr()) { - p << " dtor<" << cxxDtor.getType() << ">"; + if (auto cxxDtor = dyn_cast(*getCxxSpecialMember())) { + p << " dtor<" << cxxDtor.getType() << ">"; + } } function_interface_impl::printFunctionAttributes( p, *this, // These are all omitted since they are custom printed already. - {getAliaseeAttrName(), getBuiltinAttrName(), - getCoroutineAttrName(), getDsoLocalAttrName(), - getExtraAttrsAttrName(), getFunctionTypeAttrName(), - getGlobalCtorAttrName(), getGlobalDtorAttrName(), - getLambdaAttrName(), getLinkageAttrName(), - getCallingConvAttrName(), getNoProtoAttrName(), - getSymVisibilityAttrName(), getArgAttrsAttrName(), - getResAttrsAttrName(), getComdatAttrName(), - getGlobalVisibilityAttrName(), getAnnotationsAttrName(), - getCxxCtorAttrName(), getCxxDtorAttrName()}); + {getAliaseeAttrName(), getBuiltinAttrName(), getCoroutineAttrName(), + getDsoLocalAttrName(), getExtraAttrsAttrName(), + getFunctionTypeAttrName(), getGlobalCtorAttrName(), + getGlobalDtorAttrName(), getLambdaAttrName(), getLinkageAttrName(), + getCallingConvAttrName(), getNoProtoAttrName(), + getSymVisibilityAttrName(), getArgAttrsAttrName(), getResAttrsAttrName(), + getComdatAttrName(), getGlobalVisibilityAttrName(), + getAnnotationsAttrName(), getCxxSpecialMemberAttrName()}); if (auto aliaseeName = getAliasee()) { p << " alias("; diff --git a/clang/lib/CIR/Dialect/Transforms/LifetimeCheck.cpp b/clang/lib/CIR/Dialect/Transforms/LifetimeCheck.cpp index 0f27c910a21b..8d5e2fb1efbc 100644 --- a/clang/lib/CIR/Dialect/Transforms/LifetimeCheck.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LifetimeCheck.cpp @@ -1558,7 +1558,7 @@ void LifetimeCheckPass::checkCtor(CallOp callOp, cir::CXXCtorAttr ctor) { // string_view p; // // both results in pset(p) == {null} - if (ctor.getIsDefaultConstructor()) { + if (ctor.getCtorKind() == cir::CtorKind::Default) { // First argument passed is always the alloca for the 'this' ptr. // Currently two possible actions: @@ -1582,7 +1582,7 @@ void LifetimeCheckPass::checkCtor(CallOp callOp, cir::CXXCtorAttr ctor) { } // User defined copy ctor calls ... - if (ctor.getIsCopyConstructor()) { + if (ctor.getCtorKind() == cir::CtorKind::Copy) { llvm_unreachable("NYI"); } @@ -1789,8 +1789,10 @@ void LifetimeCheckPass::checkCall(CallOp callOp) { // starting from special methods. if (auto fnName = callOp.getCallee()) { auto calleeFuncOp = getCalleeFromSymbol(theModule, *fnName); - if (calleeFuncOp && calleeFuncOp.getCxxCtorAttr()) - return checkCtor(callOp, calleeFuncOp.getCxxCtorAttr()); + if (calleeFuncOp && calleeFuncOp.getCxxSpecialMember()) + if (auto cxxCtor = + dyn_cast(*calleeFuncOp.getCxxSpecialMember())) + return checkCtor(callOp, cxxCtor); } if (methodDecl.isMoveAssignmentOperator()) return checkMoveAssignment(callOp, methodDecl); From ffe23ba25cdebae8c5378bef62d513dffd8278a7 Mon Sep 17 00:00:00 2001 From: bruteforceboy Date: Thu, 3 Jul 2025 15:13:27 +0300 Subject: [PATCH 07/13] update dialect --- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 58d87630dc85..a29109e74bb5 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -2538,8 +2538,7 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) { auto visibilityNameAttr = getGlobalVisibilityAttrName(state.name); auto dsoLocalNameAttr = getDsoLocalAttrName(state.name); auto annotationsNameAttr = getAnnotationsAttrName(state.name); - auto cxxCtorAttr = getCxxSpecialMemberAttrName(state.name); - auto cxxDtorAttr = getCxxSpecialMemberAttrName(state.name); + auto cxxSpecialMemberAttr = getCxxSpecialMemberAttrName(state.name); if (::mlir::succeeded(parser.parseOptionalKeyword(builtinNameAttr.strref()))) state.addAttribute(builtinNameAttr, parser.getBuilder().getUnitAttr()); if (::mlir::succeeded( @@ -2653,7 +2652,7 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) { ctorKind = cir::CtorKind::Default; if (copyCtor) ctorKind = cir::CtorKind::Copy; - state.addAttribute(cxxCtorAttr, CXXCtorAttr::get(type, ctorKind)); + state.addAttribute(cxxSpecialMemberAttr, CXXCtorAttr::get(type, ctorKind)); } if (mlir::succeeded(parser.parseOptionalKeyword("dtor"))) { @@ -2666,7 +2665,7 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) { if (parser.parseGreater().failed()) return failure(); - state.addAttribute(cxxDtorAttr, CXXDtorAttr::get(type)); + state.addAttribute(cxxSpecialMemberAttr, CXXDtorAttr::get(type)); } // If additional attributes are present, parse them. From d6c0f3a8b9942bab5639f43f52af8bc8c1d761b7 Mon Sep 17 00:00:00 2001 From: bruteforceboy Date: Fri, 4 Jul 2025 16:10:46 +0300 Subject: [PATCH 08/13] update printing/parsing --- .../include/clang/CIR/Dialect/IR/CIRAttrs.td | 8 +-- clang/include/clang/CIR/Dialect/IR/CIROps.td | 4 +- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 69 ++++--------------- clang/test/CIR/CodeGen/ctor-alias.cpp | 2 +- clang/test/CIR/CodeGen/static.cpp | 8 +-- clang/test/CIR/CodeGen/temporaries.cpp | 4 +- clang/test/CIR/CodeGen/tempref.cpp | 2 +- .../CIR/CodeGen/virtual-destructor-calls.cpp | 8 +-- clang/test/CIR/IR/cxx-special-member.cir | 16 ++--- 9 files changed, 38 insertions(+), 83 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index 368c91cfd640..12d2fccae289 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -1370,9 +1370,7 @@ def CIR_CXXCtorAttr let parameters = (ins "mlir::Type":$type, EnumParameter:$ctorKind); let assemblyFormat = [{ - `<` - $type `,` $ctorKind - `>` + `<` $type `,` $ctorKind `>` }]; let builders = [AttrBuilderWithInferredContext<(ins "mlir::Type":$type, @@ -1389,9 +1387,7 @@ def CIR_CXXDtorAttr }]; let parameters = (ins "mlir::Type":$type); let assemblyFormat = [{ - `<` - $type - `>` + `<` $type `>` }]; let builders = [AttrBuilderWithInferredContext<(ins "mlir::Type":$type), [{ diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index d342b72903fc..06a34bbe49a2 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -3661,8 +3661,8 @@ def FuncOp : CIR_Op<"func", [ OptionalAttr:$global_ctor, OptionalAttr:$global_dtor, OptionalAttr:$annotations, - OptionalAttr:$ast, - OptionalAttr:$cxx_special_member + OptionalAttr:$cxx_special_member, + OptionalAttr:$ast ); let regions = (region AnyRegion:$body); diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index a29109e74bb5..54cbf436793c 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -2619,53 +2619,18 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) { state.addAttribute(annotationsNameAttr, annotations); } - // Add CXXSpecialMember attributes. - if (mlir::succeeded(parser.parseOptionalKeyword("ctor"))) { + // Add CXXSpecialMember attribute. + if (mlir::succeeded(parser.parseOptionalKeyword("cxx_special_member"))) { if (parser.parseLess().failed()) return failure(); - - mlir::Type type; - if (parser.parseType(type).failed()) - return failure(); - - bool defaultCtor = false, copyCtor = false; - if (mlir::succeeded(parser.parseOptionalComma())) { - if (parser - .parseCommaSeparatedList([&]() { - if (mlir::succeeded(parser.parseOptionalKeyword("default"))) - defaultCtor = true; - else if (mlir::succeeded(parser.parseOptionalKeyword("copy"))) - copyCtor = true; - else - return failure(); - return success(); - }) - .failed()) - return failure(); - } - + cir::CXXCtorAttr ctor; + if (auto oa = parser.parseOptionalAttribute(ctor); oa.has_value()) + state.addAttribute(cxxSpecialMemberAttr, ctor); + cir::CXXDtorAttr dtor; + if (auto oa = parser.parseOptionalAttribute(dtor); oa.has_value()) + state.addAttribute(cxxSpecialMemberAttr, dtor); if (parser.parseGreater().failed()) return failure(); - - cir::CtorKind ctorKind = cir::CtorKind::None; - if (defaultCtor) - ctorKind = cir::CtorKind::Default; - if (copyCtor) - ctorKind = cir::CtorKind::Copy; - state.addAttribute(cxxSpecialMemberAttr, CXXCtorAttr::get(type, ctorKind)); - } - - if (mlir::succeeded(parser.parseOptionalKeyword("dtor"))) { - if (parser.parseLess().failed()) - return failure(); - - mlir::Type type; - if (parser.parseType(type).failed()) - return failure(); - if (parser.parseGreater().failed()) - return failure(); - - state.addAttribute(cxxSpecialMemberAttr, CXXDtorAttr::get(type)); } // If additional attributes are present, parse them. @@ -2849,18 +2814,12 @@ void cir::FuncOp::print(OpAsmPrinter &p) { } if (getCxxSpecialMember()) { - if (auto cxxCtor = dyn_cast(*getCxxSpecialMember())) { - p << " ctor<" << cxxCtor.getType(); - if (cxxCtor.getCtorKind() == cir::CtorKind::Default) - p << ", default"; - if (cxxCtor.getCtorKind() == cir::CtorKind::Copy) - p << ", copy"; - p << '>'; - } - - if (auto cxxDtor = dyn_cast(*getCxxSpecialMember())) { - p << " dtor<" << cxxDtor.getType() << ">"; - } + p << " cxx_special_member<"; + if (auto cxxCtor = dyn_cast(*getCxxSpecialMember())) + p.printAttribute(cxxCtor); + if (auto cxxDtor = dyn_cast(*getCxxSpecialMember())) + p.printAttribute(cxxDtor); + p << '>'; } function_interface_impl::printFunctionAttributes( diff --git a/clang/test/CIR/CodeGen/ctor-alias.cpp b/clang/test/CIR/CodeGen/ctor-alias.cpp index 3182541d14f3..4742fe2f13fb 100644 --- a/clang/test/CIR/CodeGen/ctor-alias.cpp +++ b/clang/test/CIR/CodeGen/ctor-alias.cpp @@ -37,4 +37,4 @@ B::B() { // CHECK: %1 = cir.load %0 : !cir.ptr>, !cir.ptr // CHECK: cir.return // CHECK: } -// CHECK: cir.func private dso_local @_ZN1BC1Ev(!cir.ptr) ctor alias(@_ZN1BC2Ev) +// CHECK: cir.func private dso_local @_ZN1BC1Ev(!cir.ptr) cxx_special_member<#cir.cxx_ctor> alias(@_ZN1BC2Ev) diff --git a/clang/test/CIR/CodeGen/static.cpp b/clang/test/CIR/CodeGen/static.cpp index a77bcf53e728..56d34df1a066 100644 --- a/clang/test/CIR/CodeGen/static.cpp +++ b/clang/test/CIR/CodeGen/static.cpp @@ -17,8 +17,8 @@ static Init __ioinit(true); static Init __ioinit2(false); // BEFORE: module {{.*}} { -// BEFORE-NEXT: cir.func private @_ZN4InitC1Eb(!cir.ptr, !cir.bool) ctor -// BEFORE-NEXT: cir.func private @_ZN4InitD1Ev(!cir.ptr) dtor +// BEFORE-NEXT: cir.func private @_ZN4InitC1Eb(!cir.ptr, !cir.bool) cxx_special_member<#cir.cxx_ctor +// BEFORE-NEXT: cir.func private @_ZN4InitD1Ev(!cir.ptr) cxx_special_member<#cir.cxx_dtor // BEFORE-NEXT: cir.global "private" internal dso_local @_ZL8__ioinit = ctor : !rec_Init { // BEFORE-NEXT: %0 = cir.get_global @_ZL8__ioinit : !cir.ptr // BEFORE-NEXT: %1 = cir.const #true @@ -41,8 +41,8 @@ static Init __ioinit2(false); // AFTER: module {{.*}} attributes {{.*}}cir.global_ctors = [#cir.global_ctor<"__cxx_global_var_init", 65536>, #cir.global_ctor<"__cxx_global_var_init.1", 65536>] // AFTER-NEXT: cir.global "private" external @__dso_handle : i8 // AFTER-NEXT: cir.func private @__cxa_atexit(!cir.ptr)>>, !cir.ptr, !cir.ptr) -// AFTER-NEXT: cir.func private @_ZN4InitC1Eb(!cir.ptr, !cir.bool) ctor -// AFTER-NEXT: cir.func private @_ZN4InitD1Ev(!cir.ptr) dtor +// AFTER-NEXT: cir.func private @_ZN4InitC1Eb(!cir.ptr, !cir.bool) cxx_special_member<#cir.cxx_ctor +// AFTER-NEXT: cir.func private @_ZN4InitD1Ev(!cir.ptr) cxx_special_member<#cir.cxx_dtor // AFTER-NEXT: cir.global "private" internal dso_local @_ZL8__ioinit = #cir.zero : !rec_Init {alignment = 1 : i64, ast = #cir.var.decl.ast} // AFTER-NEXT: cir.func internal private @__cxx_global_var_init() // AFTER-NEXT: %0 = cir.get_global @_ZL8__ioinit : !cir.ptr diff --git a/clang/test/CIR/CodeGen/temporaries.cpp b/clang/test/CIR/CodeGen/temporaries.cpp index daad82a181af..3be57b2cbfef 100644 --- a/clang/test/CIR/CodeGen/temporaries.cpp +++ b/clang/test/CIR/CodeGen/temporaries.cpp @@ -14,9 +14,9 @@ void f() { !E(); } -// CIR: cir.func private @_ZN1EC1Ev(!cir.ptr) ctor extra(#fn_attr) +// CIR: cir.func private @_ZN1EC1Ev(!cir.ptr) cxx_special_member<#cir.cxx_ctor> extra(#fn_attr) // CIR-NEXT: cir.func private @_ZN1EntEv(!cir.ptr) -> !rec_E -// CIR-NEXT: cir.func private @_ZN1ED1Ev(!cir.ptr) dtor extra(#fn_attr) +// CIR-NEXT: cir.func private @_ZN1ED1Ev(!cir.ptr) cxx_special_member<#cir.cxx_dtor> extra(#fn_attr) // CIR-NEXT: cir.func dso_local @_Z1fv() extra(#fn_attr1) { // CIR-NEXT: cir.scope { // CIR-NEXT: %[[ONE:[0-9]+]] = cir.alloca !rec_E, !cir.ptr, ["agg.tmp.ensured"] {alignment = 1 : i64} diff --git a/clang/test/CIR/CodeGen/tempref.cpp b/clang/test/CIR/CodeGen/tempref.cpp index 462bd4b2ae5b..35c4f2b16b28 100644 --- a/clang/test/CIR/CodeGen/tempref.cpp +++ b/clang/test/CIR/CodeGen/tempref.cpp @@ -6,7 +6,7 @@ struct A { ~A(); }; A &&a = dynamic_cast(A{}); -// CHECK: cir.func private @_ZN1AD1Ev(!cir.ptr) dtor extra(#fn_attr) +// CHECK: cir.func private @_ZN1AD1Ev(!cir.ptr) cxx_special_member<#cir.cxx_dtor> extra(#fn_attr) // CHECK-NEXT: cir.global external @a = #cir.ptr : !cir.ptr {alignment = 8 : i64, ast = #cir.var.decl.ast} // CHECK-NEXT: cir.func internal private @__cxx_global_var_init() { // CHECK-NEXT: cir.scope { diff --git a/clang/test/CIR/CodeGen/virtual-destructor-calls.cpp b/clang/test/CIR/CodeGen/virtual-destructor-calls.cpp index a920f6831565..51ef8674d619 100644 --- a/clang/test/CIR/CodeGen/virtual-destructor-calls.cpp +++ b/clang/test/CIR/CodeGen/virtual-destructor-calls.cpp @@ -32,7 +32,7 @@ struct B : A { // LLVM: call void @_ZN1AD2Ev // Complete dtor: just an alias because there are no virtual bases. -// CIR: cir.func private dso_local @_ZN1BD1Ev(!cir.ptr) dtor alias(@_ZN1BD2Ev) +// CIR: cir.func private dso_local @_ZN1BD1Ev(!cir.ptr) cxx_special_member<#cir.cxx_dtor> alias(@_ZN1BD2Ev) // FIXME: LLVM output should be: @_ZN1BD1Ev ={{.*}} unnamed_addr alias {{.*}} @_ZN1BD2Ev // LLVM: declare dso_local void @_ZN1BD1Ev(ptr) @@ -43,11 +43,11 @@ struct B : A { // (aliases from C) // CIR: cir.func dso_local @_ZN1CD2Ev(%arg0: !cir.ptr{{.*}})) {{.*}} { -// CIR: cir.func private dso_local @_ZN1CD1Ev(!cir.ptr) dtor alias(@_ZN1CD2Ev) +// CIR: cir.func private dso_local @_ZN1CD1Ev(!cir.ptr) cxx_special_member<#cir.cxx_dtor> alias(@_ZN1CD2Ev) // CIR_O1-NOT: cir.func dso_local @_ZN1CD2Ev(%arg0: !cir.ptr{{.*}})) {{.*}} { -// CIR_O1: cir.func private dso_local @_ZN1CD2Ev(!cir.ptr) dtor alias(@_ZN1BD2Ev) -// CIR_O1: cir.func private dso_local @_ZN1CD1Ev(!cir.ptr) dtor alias(@_ZN1CD2Ev) +// CIR_O1: cir.func private dso_local @_ZN1CD2Ev(!cir.ptr) cxx_special_member<#cir.cxx_dtor> alias(@_ZN1BD2Ev) +// CIR_O1: cir.func private dso_local @_ZN1CD1Ev(!cir.ptr) cxx_special_member<#cir.cxx_dtor> alias(@_ZN1CD2Ev) // FIXME: LLVM output should be: @_ZN1CD2Ev ={{.*}} unnamed_addr alias {{.*}} @_ZN1BD2Ev // LLVM: define dso_local void @_ZN1CD2Ev(ptr diff --git a/clang/test/CIR/IR/cxx-special-member.cir b/clang/test/CIR/IR/cxx-special-member.cir index ce2e6ac2f910..2d3251d5e1ad 100644 --- a/clang/test/CIR/IR/cxx-special-member.cir +++ b/clang/test/CIR/IR/cxx-special-member.cir @@ -4,17 +4,17 @@ !s32i = !cir.int !rec_S = !cir.record module { - cir.func private @_ZN1SC1ERKS_(!cir.ptr, !cir.ptr) ctor - cir.func private @_ZN1SC2Ei(!cir.ptr, !cir.ptr) ctor - cir.func private @_ZN1SC2Ev(!cir.ptr) ctor - cir.func private @_ZN1SD2Ev(!cir.ptr) dtor + cir.func private @_ZN1SC1ERKS_(!cir.ptr, !cir.ptr) cxx_special_member<#cir.cxx_ctor> + cir.func private @_ZN1SC2Ei(!cir.ptr, !cir.ptr) cxx_special_member<#cir.cxx_ctor> + cir.func private @_ZN1SC2Ev(!cir.ptr) cxx_special_member<#cir.cxx_ctor> + cir.func private @_ZN1SD2Ev(!cir.ptr) cxx_special_member<#cir.cxx_dtor> } // CHECK: !s32i = !cir.int // CHECK: !rec_S = !cir.record // CHECK: module { -// CHECK: cir.func private @_ZN1SC1ERKS_(!cir.ptr, !cir.ptr) ctor -// CHECK: cir.func private @_ZN1SC2Ei(!cir.ptr, !cir.ptr) ctor -// CHECK: cir.func private @_ZN1SC2Ev(!cir.ptr) ctor -// CHECK: cir.func private @_ZN1SD2Ev(!cir.ptr) dtor +// CHECK: cir.func private @_ZN1SC1ERKS_(!cir.ptr, !cir.ptr) cxx_special_member<#cir.cxx_ctor> +// CHECK: cir.func private @_ZN1SC2Ei(!cir.ptr, !cir.ptr) cxx_special_member<#cir.cxx_ctor> +// CHECK: cir.func private @_ZN1SC2Ev(!cir.ptr) cxx_special_member<#cir.cxx_ctor> +// CHECK: cir.func private @_ZN1SD2Ev(!cir.ptr) cxx_special_member<#cir.cxx_dtor> // CHECK: } From c40a840b2b86dab44129901aae4c83ac24e20b14 Mon Sep 17 00:00:00 2001 From: bruteforceboy Date: Mon, 7 Jul 2025 17:38:34 +0300 Subject: [PATCH 09/13] more review comments --- .../include/clang/CIR/Dialect/IR/CIRAttrs.td | 11 +++- clang/lib/CIR/CodeGen/CIRGenFunction.cpp | 4 +- clang/lib/CIR/CodeGen/CIRGenModule.cpp | 4 +- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 50 +++++++++++++------ clang/test/CIR/CodeGen/ctor-alias.cpp | 2 +- clang/test/CIR/CodeGen/static.cpp | 8 +-- clang/test/CIR/CodeGen/temporaries.cpp | 4 +- clang/test/CIR/CodeGen/tempref.cpp | 2 +- .../CIR/CodeGen/virtual-destructor-calls.cpp | 8 +-- clang/test/CIR/IR/cxx-special-member.cir | 16 +++--- 10 files changed, 67 insertions(+), 42 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index 12d2fccae289..bf29fc617dca 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -1352,7 +1352,7 @@ def GlobalDtorAttr : CIR_GlobalCtorDtor<"Dtor", "dtor", >; def CIR_CtorKind : CIR_I32EnumAttr<"CtorKind", "CXX Constructor Kind", [ - I32EnumAttrCase<"None", 0, "none">, + I32EnumAttrCase<"Custom", 0, "custom">, I32EnumAttrCase<"Default", 1, "default">, I32EnumAttrCase<"Copy", 2, "copy">, ]> { @@ -1364,17 +1364,21 @@ def CIR_CXXCtorAttr let summary = "Marks a function as a CXX constructor"; let description = [{ Functions with this attribute are CXX constructors. + The `custom` kind is used if the constructor is a custom constructor. The `default` kind is used if the constructor is a default constructor. The `copy` kind is used if the constructor is a copy constructor. }]; let parameters = (ins "mlir::Type":$type, EnumParameter:$ctorKind); + let assemblyFormat = [{ `<` $type `,` $ctorKind `>` }]; + // Printing and parsing also available in CIRDialect.cpp + let builders = [AttrBuilderWithInferredContext<(ins "mlir::Type":$type, - CArg<"CtorKind", "cir::CtorKind::None">:$ctorKind), [{ + CArg<"CtorKind", "cir::CtorKind::Custom">:$ctorKind), [{ return $_get(type.getContext(), type, ctorKind); }]>]; } @@ -1386,9 +1390,12 @@ def CIR_CXXDtorAttr Functions with this attribute are CXX destructors }]; let parameters = (ins "mlir::Type":$type); + let assemblyFormat = [{ `<` $type `>` }]; + // Printing and parsing also available in CIRDialect.cpp + let builders = [AttrBuilderWithInferredContext<(ins "mlir::Type":$type), [{ return $_get(type.getContext(), type); diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp index ab2a8b51ac73..c207eec7df49 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.cpp @@ -766,20 +766,18 @@ cir::FuncOp CIRGenFunction::generateCode(clang::GlobalDecl gd, cir::FuncOp fn, assert(!cir::MissingFeatures::shouldInstrumentFunction()); if (auto dtor = dyn_cast(fd)) { auto cxxDtor = cir::CXXDtorAttr::get( - &getMLIRContext(), convertType(getContext().getRecordType(dtor->getParent()))); fn.setCxxSpecialMemberAttr(cxxDtor); emitDestructorBody(args); } else if (auto ctor = dyn_cast(fd)) { - cir::CtorKind ctorKind = cir::CtorKind::None; + cir::CtorKind ctorKind = cir::CtorKind::Custom; if (ctor->isDefaultConstructor()) ctorKind = cir::CtorKind::Default; if (ctor->isCopyConstructor()) ctorKind = cir::CtorKind::Copy; auto cxxCtor = cir::CXXCtorAttr::get( - &getMLIRContext(), convertType(getContext().getRecordType(ctor->getParent())), ctorKind); fn.setCxxSpecialMemberAttr(cxxCtor); diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index b15c6120b7ce..0b936ad77f07 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -2742,20 +2742,18 @@ cir::FuncOp CIRGenModule::createCIRFunction(mlir::Location loc, StringRef name, if (fd) { if (auto dtor = dyn_cast(fd)) { auto cxxDtor = cir::CXXDtorAttr::get( - &getMLIRContext(), convertType(getASTContext().getRecordType(dtor->getParent()))); f.setCxxSpecialMemberAttr(cxxDtor); } if (auto ctor = dyn_cast(fd)) { - cir::CtorKind ctorKind = cir::CtorKind::None; + cir::CtorKind ctorKind = cir::CtorKind::Custom; if (ctor->isDefaultConstructor()) ctorKind = cir::CtorKind::Default; if (ctor->isCopyConstructor()) ctorKind = cir::CtorKind::Copy; auto cxxCtor = cir::CXXCtorAttr::get( - &getMLIRContext(), convertType(getASTContext().getRecordType(ctor->getParent())), ctorKind); f.setCxxSpecialMemberAttr(cxxCtor); diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 54cbf436793c..3ce9167bbf56 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -172,6 +172,7 @@ REGISTER_ENUM_TYPE(GlobalLinkageKind); REGISTER_ENUM_TYPE(VisibilityKind); REGISTER_ENUM_TYPE(CallingConv); REGISTER_ENUM_TYPE(SideEffect); +REGISTER_ENUM_TYPE(CtorKind); } // namespace /// Parse an enum from the keyword, or default to the provided default value. @@ -2619,18 +2620,35 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) { state.addAttribute(annotationsNameAttr, annotations); } - // Add CXXSpecialMember attribute. - if (mlir::succeeded(parser.parseOptionalKeyword("cxx_special_member"))) { + // Parse CXXSpecialMember attribute + if (mlir::succeeded(parser.parseOptionalKeyword("cxx_ctor"))) { if (parser.parseLess().failed()) return failure(); - cir::CXXCtorAttr ctor; - if (auto oa = parser.parseOptionalAttribute(ctor); oa.has_value()) - state.addAttribute(cxxSpecialMemberAttr, ctor); - cir::CXXDtorAttr dtor; - if (auto oa = parser.parseOptionalAttribute(dtor); oa.has_value()) - state.addAttribute(cxxSpecialMemberAttr, dtor); + mlir::Type type; + if (parser.parseType(type).failed()) + return failure(); + if (parser.parseComma().failed()) + return failure(); + cir::CtorKind ctorKind; + if (parseCIRKeyword(parser, ctorKind).failed()) + return failure(); + if (parser.parseGreater().failed()) + return failure(); + + state.addAttribute(cxxSpecialMemberAttr, + cir::CXXCtorAttr::get(type, ctorKind)); + } + + if (mlir::succeeded(parser.parseOptionalKeyword("cxx_dtor"))) { + if (parser.parseLess().failed()) + return failure(); + mlir::Type type; + if (parser.parseType(type).failed()) + return failure(); if (parser.parseGreater().failed()) return failure(); + + state.addAttribute(cxxSpecialMemberAttr, cir::CXXDtorAttr::get(type)); } // If additional attributes are present, parse them. @@ -2814,12 +2832,16 @@ void cir::FuncOp::print(OpAsmPrinter &p) { } if (getCxxSpecialMember()) { - p << " cxx_special_member<"; - if (auto cxxCtor = dyn_cast(*getCxxSpecialMember())) - p.printAttribute(cxxCtor); - if (auto cxxDtor = dyn_cast(*getCxxSpecialMember())) - p.printAttribute(cxxDtor); - p << '>'; + if (auto cxxCtor = dyn_cast(*getCxxSpecialMember())) { + if (cxxCtor.getCtorKind() != cir::CtorKind::Custom) + p << " cxx_ctor<" << cxxCtor.getType() << ", " << cxxCtor.getCtorKind() + << ">"; + } else if (auto cxxDtor = + dyn_cast(*getCxxSpecialMember())) { + p << " cxx_dtor<" << cxxDtor.getType() << ">"; + } else { + assert(false && "expected a CXX special member"); + } } function_interface_impl::printFunctionAttributes( diff --git a/clang/test/CIR/CodeGen/ctor-alias.cpp b/clang/test/CIR/CodeGen/ctor-alias.cpp index 4742fe2f13fb..6c5c8ad34717 100644 --- a/clang/test/CIR/CodeGen/ctor-alias.cpp +++ b/clang/test/CIR/CodeGen/ctor-alias.cpp @@ -37,4 +37,4 @@ B::B() { // CHECK: %1 = cir.load %0 : !cir.ptr>, !cir.ptr // CHECK: cir.return // CHECK: } -// CHECK: cir.func private dso_local @_ZN1BC1Ev(!cir.ptr) cxx_special_member<#cir.cxx_ctor> alias(@_ZN1BC2Ev) +// CHECK: cir.func private dso_local @_ZN1BC1Ev(!cir.ptr) cxx_ctor alias(@_ZN1BC2Ev) diff --git a/clang/test/CIR/CodeGen/static.cpp b/clang/test/CIR/CodeGen/static.cpp index 56d34df1a066..070043e6fcfa 100644 --- a/clang/test/CIR/CodeGen/static.cpp +++ b/clang/test/CIR/CodeGen/static.cpp @@ -17,8 +17,8 @@ static Init __ioinit(true); static Init __ioinit2(false); // BEFORE: module {{.*}} { -// BEFORE-NEXT: cir.func private @_ZN4InitC1Eb(!cir.ptr, !cir.bool) cxx_special_member<#cir.cxx_ctor -// BEFORE-NEXT: cir.func private @_ZN4InitD1Ev(!cir.ptr) cxx_special_member<#cir.cxx_dtor +// BEFORE-NEXT: cir.func private @_ZN4InitC1Eb(!cir.ptr, !cir.bool) +// BEFORE-NEXT: cir.func private @_ZN4InitD1Ev(!cir.ptr) cxx_dtor // BEFORE-NEXT: cir.global "private" internal dso_local @_ZL8__ioinit = ctor : !rec_Init { // BEFORE-NEXT: %0 = cir.get_global @_ZL8__ioinit : !cir.ptr // BEFORE-NEXT: %1 = cir.const #true @@ -41,8 +41,8 @@ static Init __ioinit2(false); // AFTER: module {{.*}} attributes {{.*}}cir.global_ctors = [#cir.global_ctor<"__cxx_global_var_init", 65536>, #cir.global_ctor<"__cxx_global_var_init.1", 65536>] // AFTER-NEXT: cir.global "private" external @__dso_handle : i8 // AFTER-NEXT: cir.func private @__cxa_atexit(!cir.ptr)>>, !cir.ptr, !cir.ptr) -// AFTER-NEXT: cir.func private @_ZN4InitC1Eb(!cir.ptr, !cir.bool) cxx_special_member<#cir.cxx_ctor -// AFTER-NEXT: cir.func private @_ZN4InitD1Ev(!cir.ptr) cxx_special_member<#cir.cxx_dtor +// AFTER-NEXT: cir.func private @_ZN4InitC1Eb(!cir.ptr, !cir.bool) +// AFTER-NEXT: cir.func private @_ZN4InitD1Ev(!cir.ptr) cxx_dtor // AFTER-NEXT: cir.global "private" internal dso_local @_ZL8__ioinit = #cir.zero : !rec_Init {alignment = 1 : i64, ast = #cir.var.decl.ast} // AFTER-NEXT: cir.func internal private @__cxx_global_var_init() // AFTER-NEXT: %0 = cir.get_global @_ZL8__ioinit : !cir.ptr diff --git a/clang/test/CIR/CodeGen/temporaries.cpp b/clang/test/CIR/CodeGen/temporaries.cpp index 3be57b2cbfef..2b8304c69b0f 100644 --- a/clang/test/CIR/CodeGen/temporaries.cpp +++ b/clang/test/CIR/CodeGen/temporaries.cpp @@ -14,9 +14,9 @@ void f() { !E(); } -// CIR: cir.func private @_ZN1EC1Ev(!cir.ptr) cxx_special_member<#cir.cxx_ctor> extra(#fn_attr) +// CIR: cir.func private @_ZN1EC1Ev(!cir.ptr) cxx_ctor extra(#fn_attr) // CIR-NEXT: cir.func private @_ZN1EntEv(!cir.ptr) -> !rec_E -// CIR-NEXT: cir.func private @_ZN1ED1Ev(!cir.ptr) cxx_special_member<#cir.cxx_dtor> extra(#fn_attr) +// CIR-NEXT: cir.func private @_ZN1ED1Ev(!cir.ptr) cxx_dtor extra(#fn_attr) // CIR-NEXT: cir.func dso_local @_Z1fv() extra(#fn_attr1) { // CIR-NEXT: cir.scope { // CIR-NEXT: %[[ONE:[0-9]+]] = cir.alloca !rec_E, !cir.ptr, ["agg.tmp.ensured"] {alignment = 1 : i64} diff --git a/clang/test/CIR/CodeGen/tempref.cpp b/clang/test/CIR/CodeGen/tempref.cpp index 35c4f2b16b28..ddf7cee81bc4 100644 --- a/clang/test/CIR/CodeGen/tempref.cpp +++ b/clang/test/CIR/CodeGen/tempref.cpp @@ -6,7 +6,7 @@ struct A { ~A(); }; A &&a = dynamic_cast(A{}); -// CHECK: cir.func private @_ZN1AD1Ev(!cir.ptr) cxx_special_member<#cir.cxx_dtor> extra(#fn_attr) +// CHECK: cir.func private @_ZN1AD1Ev(!cir.ptr) cxx_dtor extra(#fn_attr) // CHECK-NEXT: cir.global external @a = #cir.ptr : !cir.ptr {alignment = 8 : i64, ast = #cir.var.decl.ast} // CHECK-NEXT: cir.func internal private @__cxx_global_var_init() { // CHECK-NEXT: cir.scope { diff --git a/clang/test/CIR/CodeGen/virtual-destructor-calls.cpp b/clang/test/CIR/CodeGen/virtual-destructor-calls.cpp index 51ef8674d619..e54e335ed7d3 100644 --- a/clang/test/CIR/CodeGen/virtual-destructor-calls.cpp +++ b/clang/test/CIR/CodeGen/virtual-destructor-calls.cpp @@ -32,7 +32,7 @@ struct B : A { // LLVM: call void @_ZN1AD2Ev // Complete dtor: just an alias because there are no virtual bases. -// CIR: cir.func private dso_local @_ZN1BD1Ev(!cir.ptr) cxx_special_member<#cir.cxx_dtor> alias(@_ZN1BD2Ev) +// CIR: cir.func private dso_local @_ZN1BD1Ev(!cir.ptr) cxx_dtor alias(@_ZN1BD2Ev) // FIXME: LLVM output should be: @_ZN1BD1Ev ={{.*}} unnamed_addr alias {{.*}} @_ZN1BD2Ev // LLVM: declare dso_local void @_ZN1BD1Ev(ptr) @@ -43,11 +43,11 @@ struct B : A { // (aliases from C) // CIR: cir.func dso_local @_ZN1CD2Ev(%arg0: !cir.ptr{{.*}})) {{.*}} { -// CIR: cir.func private dso_local @_ZN1CD1Ev(!cir.ptr) cxx_special_member<#cir.cxx_dtor> alias(@_ZN1CD2Ev) +// CIR: cir.func private dso_local @_ZN1CD1Ev(!cir.ptr) cxx_dtor alias(@_ZN1CD2Ev) // CIR_O1-NOT: cir.func dso_local @_ZN1CD2Ev(%arg0: !cir.ptr{{.*}})) {{.*}} { -// CIR_O1: cir.func private dso_local @_ZN1CD2Ev(!cir.ptr) cxx_special_member<#cir.cxx_dtor> alias(@_ZN1BD2Ev) -// CIR_O1: cir.func private dso_local @_ZN1CD1Ev(!cir.ptr) cxx_special_member<#cir.cxx_dtor> alias(@_ZN1CD2Ev) +// CIR_O1: cir.func private dso_local @_ZN1CD2Ev(!cir.ptr) cxx_dtor alias(@_ZN1BD2Ev) +// CIR_O1: cir.func private dso_local @_ZN1CD1Ev(!cir.ptr) cxx_dtor alias(@_ZN1CD2Ev) // FIXME: LLVM output should be: @_ZN1CD2Ev ={{.*}} unnamed_addr alias {{.*}} @_ZN1BD2Ev // LLVM: define dso_local void @_ZN1CD2Ev(ptr diff --git a/clang/test/CIR/IR/cxx-special-member.cir b/clang/test/CIR/IR/cxx-special-member.cir index 2d3251d5e1ad..b65162147d07 100644 --- a/clang/test/CIR/IR/cxx-special-member.cir +++ b/clang/test/CIR/IR/cxx-special-member.cir @@ -4,17 +4,17 @@ !s32i = !cir.int !rec_S = !cir.record module { - cir.func private @_ZN1SC1ERKS_(!cir.ptr, !cir.ptr) cxx_special_member<#cir.cxx_ctor> - cir.func private @_ZN1SC2Ei(!cir.ptr, !cir.ptr) cxx_special_member<#cir.cxx_ctor> - cir.func private @_ZN1SC2Ev(!cir.ptr) cxx_special_member<#cir.cxx_ctor> - cir.func private @_ZN1SD2Ev(!cir.ptr) cxx_special_member<#cir.cxx_dtor> + cir.func private @_ZN1SC1ERKS_(!cir.ptr, !cir.ptr) cxx_ctor + cir.func private @_ZN1SC2Ei(!cir.ptr, !cir.ptr) + cir.func private @_ZN1SC2Ev(!cir.ptr) cxx_ctor + cir.func private @_ZN1SD2Ev(!cir.ptr) cxx_dtor } // CHECK: !s32i = !cir.int // CHECK: !rec_S = !cir.record // CHECK: module { -// CHECK: cir.func private @_ZN1SC1ERKS_(!cir.ptr, !cir.ptr) cxx_special_member<#cir.cxx_ctor> -// CHECK: cir.func private @_ZN1SC2Ei(!cir.ptr, !cir.ptr) cxx_special_member<#cir.cxx_ctor> -// CHECK: cir.func private @_ZN1SC2Ev(!cir.ptr) cxx_special_member<#cir.cxx_ctor> -// CHECK: cir.func private @_ZN1SD2Ev(!cir.ptr) cxx_special_member<#cir.cxx_dtor> +// CHECK: cir.func private @_ZN1SC1ERKS_(!cir.ptr, !cir.ptr) cxx_ctor +// CHECK: cir.func private @_ZN1SC2Ei(!cir.ptr, !cir.ptr) +// CHECK: cir.func private @_ZN1SC2Ev(!cir.ptr) cxx_ctor +// CHECK: cir.func private @_ZN1SD2Ev(!cir.ptr) cxx_dtor // CHECK: } From b7318cb43f45bd5e3c26828f8292afc1fe6d1b7e Mon Sep 17 00:00:00 2001 From: bruteforceboy Date: Wed, 16 Jul 2025 16:43:05 +0300 Subject: [PATCH 10/13] review comments --- .../include/clang/CIR/Dialect/IR/CIRAttrs.td | 22 +++++----- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 41 ++++++------------- clang/test/CIR/CodeGen/ctor-alias.cpp | 2 +- clang/test/CIR/CodeGen/static.cpp | 4 +- clang/test/CIR/CodeGen/temporaries.cpp | 4 +- clang/test/CIR/CodeGen/tempref.cpp | 2 +- .../CIR/CodeGen/virtual-destructor-calls.cpp | 8 ++-- clang/test/CIR/IR/cxx-special-member.cir | 12 +++--- 8 files changed, 39 insertions(+), 56 deletions(-) diff --git a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td index bf29fc617dca..835718d8a713 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRAttrs.td @@ -1359,8 +1359,7 @@ def CIR_CtorKind : CIR_I32EnumAttr<"CtorKind", "CXX Constructor Kind", [ let genSpecializedAttr = 0; } -def CIR_CXXCtorAttr - : CIR_Attr<"CXXCtor", "cxx_ctor"> { +def CIR_CXXCtorAttr : CIR_Attr<"CXXCtor", "cxx_ctor"> { let summary = "Marks a function as a CXX constructor"; let description = [{ Functions with this attribute are CXX constructors. @@ -1374,17 +1373,16 @@ def CIR_CXXCtorAttr let assemblyFormat = [{ `<` $type `,` $ctorKind `>` }]; - // Printing and parsing also available in CIRDialect.cpp - let builders = - [AttrBuilderWithInferredContext<(ins "mlir::Type":$type, + let builders = [ + AttrBuilderWithInferredContext<(ins "mlir::Type":$type, CArg<"CtorKind", "cir::CtorKind::Custom">:$ctorKind), [{ return $_get(type.getContext(), type, ctorKind); - }]>]; + }]> + ]; } -def CIR_CXXDtorAttr - : CIR_Attr<"CXXDtor", "cxx_dtor"> { +def CIR_CXXDtorAttr : CIR_Attr<"CXXDtor", "cxx_dtor"> { let summary = "Marks a function as a CXX destructor"; let description = [{ Functions with this attribute are CXX destructors @@ -1394,12 +1392,12 @@ def CIR_CXXDtorAttr let assemblyFormat = [{ `<` $type `>` }]; - // Printing and parsing also available in CIRDialect.cpp - let builders = - [AttrBuilderWithInferredContext<(ins "mlir::Type":$type), [{ + let builders = [ + AttrBuilderWithInferredContext<(ins "mlir::Type":$type), [{ return $_get(type.getContext(), type); - }]>]; + }]> + ]; } def CIR_CXXSpecialMemberAttr : AnyAttrOf<[ diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 3ce9167bbf56..940f8c119722 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -2621,34 +2621,17 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) { } // Parse CXXSpecialMember attribute - if (mlir::succeeded(parser.parseOptionalKeyword("cxx_ctor"))) { + if (parser.parseOptionalKeyword("special_member").succeeded()) { + cir::CXXCtorAttr ctorAttr; + cir::CXXDtorAttr dtorAttr; if (parser.parseLess().failed()) return failure(); - mlir::Type type; - if (parser.parseType(type).failed()) - return failure(); - if (parser.parseComma().failed()) - return failure(); - cir::CtorKind ctorKind; - if (parseCIRKeyword(parser, ctorKind).failed()) - return failure(); - if (parser.parseGreater().failed()) - return failure(); - - state.addAttribute(cxxSpecialMemberAttr, - cir::CXXCtorAttr::get(type, ctorKind)); - } - - if (mlir::succeeded(parser.parseOptionalKeyword("cxx_dtor"))) { - if (parser.parseLess().failed()) - return failure(); - mlir::Type type; - if (parser.parseType(type).failed()) - return failure(); + if (auto oa = parser.parseOptionalAttribute(ctorAttr); oa.has_value()) + state.addAttribute(cxxSpecialMemberAttr, ctorAttr); + if (auto oa = parser.parseOptionalAttribute(dtorAttr); oa.has_value()) + state.addAttribute(cxxSpecialMemberAttr, dtorAttr); if (parser.parseGreater().failed()) return failure(); - - state.addAttribute(cxxSpecialMemberAttr, cir::CXXDtorAttr::get(type)); } // If additional attributes are present, parse them. @@ -2833,12 +2816,14 @@ void cir::FuncOp::print(OpAsmPrinter &p) { if (getCxxSpecialMember()) { if (auto cxxCtor = dyn_cast(*getCxxSpecialMember())) { - if (cxxCtor.getCtorKind() != cir::CtorKind::Custom) - p << " cxx_ctor<" << cxxCtor.getType() << ", " << cxxCtor.getCtorKind() - << ">"; + p << " special_member<"; + p.printAttribute(cxxCtor); + p << '>'; } else if (auto cxxDtor = dyn_cast(*getCxxSpecialMember())) { - p << " cxx_dtor<" << cxxDtor.getType() << ">"; + p << " special_member<"; + p.printAttribute(cxxDtor); + p << '>'; } else { assert(false && "expected a CXX special member"); } diff --git a/clang/test/CIR/CodeGen/ctor-alias.cpp b/clang/test/CIR/CodeGen/ctor-alias.cpp index 6c5c8ad34717..5c27762bdfe3 100644 --- a/clang/test/CIR/CodeGen/ctor-alias.cpp +++ b/clang/test/CIR/CodeGen/ctor-alias.cpp @@ -37,4 +37,4 @@ B::B() { // CHECK: %1 = cir.load %0 : !cir.ptr>, !cir.ptr // CHECK: cir.return // CHECK: } -// CHECK: cir.func private dso_local @_ZN1BC1Ev(!cir.ptr) cxx_ctor alias(@_ZN1BC2Ev) +// CHECK: cir.func private dso_local @_ZN1BC1Ev(!cir.ptr) special_member<#cir.cxx_ctor> alias(@_ZN1BC2Ev) diff --git a/clang/test/CIR/CodeGen/static.cpp b/clang/test/CIR/CodeGen/static.cpp index 070043e6fcfa..6e7f649cc134 100644 --- a/clang/test/CIR/CodeGen/static.cpp +++ b/clang/test/CIR/CodeGen/static.cpp @@ -18,7 +18,7 @@ static Init __ioinit2(false); // BEFORE: module {{.*}} { // BEFORE-NEXT: cir.func private @_ZN4InitC1Eb(!cir.ptr, !cir.bool) -// BEFORE-NEXT: cir.func private @_ZN4InitD1Ev(!cir.ptr) cxx_dtor +// BEFORE-NEXT: cir.func private @_ZN4InitD1Ev(!cir.ptr) special_member<#cir.cxx_dtor> // BEFORE-NEXT: cir.global "private" internal dso_local @_ZL8__ioinit = ctor : !rec_Init { // BEFORE-NEXT: %0 = cir.get_global @_ZL8__ioinit : !cir.ptr // BEFORE-NEXT: %1 = cir.const #true @@ -42,7 +42,7 @@ static Init __ioinit2(false); // AFTER-NEXT: cir.global "private" external @__dso_handle : i8 // AFTER-NEXT: cir.func private @__cxa_atexit(!cir.ptr)>>, !cir.ptr, !cir.ptr) // AFTER-NEXT: cir.func private @_ZN4InitC1Eb(!cir.ptr, !cir.bool) -// AFTER-NEXT: cir.func private @_ZN4InitD1Ev(!cir.ptr) cxx_dtor +// AFTER-NEXT: cir.func private @_ZN4InitD1Ev(!cir.ptr) special_member<#cir.cxx_dtor> // AFTER-NEXT: cir.global "private" internal dso_local @_ZL8__ioinit = #cir.zero : !rec_Init {alignment = 1 : i64, ast = #cir.var.decl.ast} // AFTER-NEXT: cir.func internal private @__cxx_global_var_init() // AFTER-NEXT: %0 = cir.get_global @_ZL8__ioinit : !cir.ptr diff --git a/clang/test/CIR/CodeGen/temporaries.cpp b/clang/test/CIR/CodeGen/temporaries.cpp index 2b8304c69b0f..d104df4f7a24 100644 --- a/clang/test/CIR/CodeGen/temporaries.cpp +++ b/clang/test/CIR/CodeGen/temporaries.cpp @@ -14,9 +14,9 @@ void f() { !E(); } -// CIR: cir.func private @_ZN1EC1Ev(!cir.ptr) cxx_ctor extra(#fn_attr) +// CIR: cir.func private @_ZN1EC1Ev(!cir.ptr) special_member<#cir.cxx_ctor> extra(#fn_attr) // CIR-NEXT: cir.func private @_ZN1EntEv(!cir.ptr) -> !rec_E -// CIR-NEXT: cir.func private @_ZN1ED1Ev(!cir.ptr) cxx_dtor extra(#fn_attr) +// CIR-NEXT: cir.func private @_ZN1ED1Ev(!cir.ptr) special_member<#cir.cxx_dtor> extra(#fn_attr) // CIR-NEXT: cir.func dso_local @_Z1fv() extra(#fn_attr1) { // CIR-NEXT: cir.scope { // CIR-NEXT: %[[ONE:[0-9]+]] = cir.alloca !rec_E, !cir.ptr, ["agg.tmp.ensured"] {alignment = 1 : i64} diff --git a/clang/test/CIR/CodeGen/tempref.cpp b/clang/test/CIR/CodeGen/tempref.cpp index ddf7cee81bc4..a30ebe715c6c 100644 --- a/clang/test/CIR/CodeGen/tempref.cpp +++ b/clang/test/CIR/CodeGen/tempref.cpp @@ -6,7 +6,7 @@ struct A { ~A(); }; A &&a = dynamic_cast(A{}); -// CHECK: cir.func private @_ZN1AD1Ev(!cir.ptr) cxx_dtor extra(#fn_attr) +// CHECK: cir.func private @_ZN1AD1Ev(!cir.ptr) special_member<#cir.cxx_dtor> extra(#fn_attr) // CHECK-NEXT: cir.global external @a = #cir.ptr : !cir.ptr {alignment = 8 : i64, ast = #cir.var.decl.ast} // CHECK-NEXT: cir.func internal private @__cxx_global_var_init() { // CHECK-NEXT: cir.scope { diff --git a/clang/test/CIR/CodeGen/virtual-destructor-calls.cpp b/clang/test/CIR/CodeGen/virtual-destructor-calls.cpp index e54e335ed7d3..4f0a2c8a2201 100644 --- a/clang/test/CIR/CodeGen/virtual-destructor-calls.cpp +++ b/clang/test/CIR/CodeGen/virtual-destructor-calls.cpp @@ -32,7 +32,7 @@ struct B : A { // LLVM: call void @_ZN1AD2Ev // Complete dtor: just an alias because there are no virtual bases. -// CIR: cir.func private dso_local @_ZN1BD1Ev(!cir.ptr) cxx_dtor alias(@_ZN1BD2Ev) +// CIR: cir.func private dso_local @_ZN1BD1Ev(!cir.ptr) special_member<#cir.cxx_dtor> alias(@_ZN1BD2Ev) // FIXME: LLVM output should be: @_ZN1BD1Ev ={{.*}} unnamed_addr alias {{.*}} @_ZN1BD2Ev // LLVM: declare dso_local void @_ZN1BD1Ev(ptr) @@ -43,11 +43,11 @@ struct B : A { // (aliases from C) // CIR: cir.func dso_local @_ZN1CD2Ev(%arg0: !cir.ptr{{.*}})) {{.*}} { -// CIR: cir.func private dso_local @_ZN1CD1Ev(!cir.ptr) cxx_dtor alias(@_ZN1CD2Ev) +// CIR: cir.func private dso_local @_ZN1CD1Ev(!cir.ptr) special_member<#cir.cxx_dtor> alias(@_ZN1CD2Ev) // CIR_O1-NOT: cir.func dso_local @_ZN1CD2Ev(%arg0: !cir.ptr{{.*}})) {{.*}} { -// CIR_O1: cir.func private dso_local @_ZN1CD2Ev(!cir.ptr) cxx_dtor alias(@_ZN1BD2Ev) -// CIR_O1: cir.func private dso_local @_ZN1CD1Ev(!cir.ptr) cxx_dtor alias(@_ZN1CD2Ev) +// CIR_O1: cir.func private dso_local @_ZN1CD2Ev(!cir.ptr) special_member<#cir.cxx_dtor> alias(@_ZN1BD2Ev) +// CIR_O1: cir.func private dso_local @_ZN1CD1Ev(!cir.ptr) special_member<#cir.cxx_dtor> alias(@_ZN1CD2Ev) // FIXME: LLVM output should be: @_ZN1CD2Ev ={{.*}} unnamed_addr alias {{.*}} @_ZN1BD2Ev // LLVM: define dso_local void @_ZN1CD2Ev(ptr diff --git a/clang/test/CIR/IR/cxx-special-member.cir b/clang/test/CIR/IR/cxx-special-member.cir index b65162147d07..b28051826fcd 100644 --- a/clang/test/CIR/IR/cxx-special-member.cir +++ b/clang/test/CIR/IR/cxx-special-member.cir @@ -4,17 +4,17 @@ !s32i = !cir.int !rec_S = !cir.record module { - cir.func private @_ZN1SC1ERKS_(!cir.ptr, !cir.ptr) cxx_ctor + cir.func private @_ZN1SC1ERKS_(!cir.ptr, !cir.ptr) special_member<#cir.cxx_ctor> cir.func private @_ZN1SC2Ei(!cir.ptr, !cir.ptr) - cir.func private @_ZN1SC2Ev(!cir.ptr) cxx_ctor - cir.func private @_ZN1SD2Ev(!cir.ptr) cxx_dtor + cir.func private @_ZN1SC2Ev(!cir.ptr) special_member<#cir.cxx_ctor> + cir.func private @_ZN1SD2Ev(!cir.ptr) special_member<#cir.cxx_dtor> } // CHECK: !s32i = !cir.int // CHECK: !rec_S = !cir.record // CHECK: module { -// CHECK: cir.func private @_ZN1SC1ERKS_(!cir.ptr, !cir.ptr) cxx_ctor +// CHECK: cir.func private @_ZN1SC1ERKS_(!cir.ptr, !cir.ptr) special_member<#cir.cxx_ctor> // CHECK: cir.func private @_ZN1SC2Ei(!cir.ptr, !cir.ptr) -// CHECK: cir.func private @_ZN1SC2Ev(!cir.ptr) cxx_ctor -// CHECK: cir.func private @_ZN1SD2Ev(!cir.ptr) cxx_dtor +// CHECK: cir.func private @_ZN1SC2Ev(!cir.ptr) special_member<#cir.cxx_ctor> +// CHECK: cir.func private @_ZN1SD2Ev(!cir.ptr) special_member<#cir.cxx_dtor> // CHECK: } From 5e8de9be908748e233817ffbc0b3780ed965b20a Mon Sep 17 00:00:00 2001 From: bruteforceboy Date: Wed, 16 Jul 2025 17:05:09 +0300 Subject: [PATCH 11/13] refactor --- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 1 - clang/test/CIR/CodeGen/virtual-destructor-calls.cpp | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 0b0286860d6b..37925e9720da 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -172,7 +172,6 @@ REGISTER_ENUM_TYPE(GlobalLinkageKind); REGISTER_ENUM_TYPE(VisibilityKind); REGISTER_ENUM_TYPE(CallingConv); REGISTER_ENUM_TYPE(SideEffect); -REGISTER_ENUM_TYPE(CtorKind); } // namespace /// Parse an enum from the keyword, or default to the provided default value. diff --git a/clang/test/CIR/CodeGen/virtual-destructor-calls.cpp b/clang/test/CIR/CodeGen/virtual-destructor-calls.cpp index e1f946a756d3..8fb3dfdae335 100644 --- a/clang/test/CIR/CodeGen/virtual-destructor-calls.cpp +++ b/clang/test/CIR/CodeGen/virtual-destructor-calls.cpp @@ -37,7 +37,7 @@ struct B : A { // LLVM: call void @_ZN1AD2Ev // Complete dtor: just an alias because there are no virtual bases. -// CIR: cir.func private dso_local @_ZN1BD1Ev(!cir.ptr) alias(@_ZN1BD2Ev) +// CIR: cir.func private dso_local @_ZN1BD1Ev(!cir.ptr) special_member<#cir.cxx_dtor> alias(@_ZN1BD2Ev) // Deleting dtor: defers to the complete dtor. // LLVM: define{{.*}} void @_ZN1BD0Ev(ptr From 1861174c992665db96db1a40442a59f4157badc9 Mon Sep 17 00:00:00 2001 From: bruteforceboy Date: Thu, 17 Jul 2025 17:10:09 +0300 Subject: [PATCH 12/13] more changes --- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 37925e9720da..4b70b61d55cc 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -2804,19 +2804,11 @@ void cir::FuncOp::print(OpAsmPrinter &p) { p.printAttribute(annotations); } - if (getCxxSpecialMember()) { - if (auto cxxCtor = dyn_cast(*getCxxSpecialMember())) { - p << " special_member<"; - p.printAttribute(cxxCtor); - p << '>'; - } else if (auto cxxDtor = - dyn_cast(*getCxxSpecialMember())) { - p << " special_member<"; - p.printAttribute(cxxDtor); - p << '>'; - } else { - assert(false && "expected a CXX special member"); - } + if (auto specialMemberAttr = getCxxSpecialMember()) { + assert((mlir::isa(*specialMemberAttr))); + p << " special_member<"; + p.printAttribute(*specialMemberAttr); + p << '>'; } function_interface_impl::printFunctionAttributes( From 0cb89ab3f94d1d9e33704d0aa89b3711d07befcf Mon Sep 17 00:00:00 2001 From: bruteforceboy Date: Fri, 18 Jul 2025 17:21:37 +0300 Subject: [PATCH 13/13] update dialect --- clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 4b70b61d55cc..3606baa7c75b 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -2616,9 +2616,9 @@ ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) { cir::CXXDtorAttr dtorAttr; if (parser.parseLess().failed()) return failure(); - if (auto oa = parser.parseOptionalAttribute(ctorAttr); oa.has_value()) + if (parser.parseOptionalAttribute(ctorAttr).has_value()) state.addAttribute(cxxSpecialMemberAttr, ctorAttr); - if (auto oa = parser.parseOptionalAttribute(dtorAttr); oa.has_value()) + if (parser.parseOptionalAttribute(dtorAttr).has_value()) state.addAttribute(cxxSpecialMemberAttr, dtorAttr); if (parser.parseGreater().failed()) return failure();