From 857f0baa8538ba6c3c0af2c13954d6a6bd8cc4e0 Mon Sep 17 00:00:00 2001 From: Nathan Lanza Date: Sun, 23 Nov 2025 17:00:55 -0800 Subject: [PATCH] Update [ghstack-poisoned] --- clang/include/clang/CIR/Dialect/IR/CIROps.td | 1887 ++++++++--------- clang/lib/CIR/CodeGen/CIRGenCXX.cpp | 24 + clang/lib/CIR/CodeGen/CIRGenCXXABI.h | 13 + clang/lib/CIR/CodeGen/CIRGenDecl.cpp | 8 +- clang/lib/CIR/CodeGen/CIRGenDeclCXX.cpp | 13 + clang/lib/CIR/CodeGen/CIRGenFunction.h | 8 + clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp | 141 ++ clang/lib/CIR/CodeGen/CIRGenModule.h | 9 + clang/lib/CIR/Dialect/IR/CIRDialect.cpp | 33 +- .../Dialect/Transforms/LoweringPrepare.cpp | 92 +- clang/test/CIR/CodeGen/static-var-init.cpp | 136 ++ .../test/CIR/crashes/static-var-dyn-cast.cpp | 22 +- .../CIR/crashes/static-var-guarded-init.cpp | 21 +- 13 files changed, 1340 insertions(+), 1067 deletions(-) create mode 100644 clang/test/CIR/CodeGen/static-var-init.cpp diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 5a512b7645aa..328781881d76 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -20,7 +20,6 @@ include "clang/CIR/Dialect/IR/CIRTypeConstraints.td" include "clang/CIR/Dialect/IR/CIRAttrs.td" include "clang/CIR/Dialect/IR/CIRAttrConstraints.td" - include "clang/CIR/Interfaces/ASTAttrInterfaces.td" include "clang/CIR/Interfaces/CIROpInterfaces.td" include "clang/CIR/Interfaces/CIRLoopOpInterface.td" @@ -77,115 +76,107 @@ include "mlir/IR/CommonAttrConstraints.td" // // If you want fully customized LLVM IR lowering logic, simply exclude the // `llvmOp` field from your CIR operation definition. -class LLVMLoweringInfo { - string llvmOp = ""; -} +class LLVMLoweringInfo { string llvmOp = ""; } -class CIR_Op traits = []> : - Op, LLVMLoweringInfo; +class CIR_Op traits = []> + : Op, LLVMLoweringInfo; -def CIRReturnLike : TraitList<[ - DeclareOpInterfaceMethods, - NativeOpTrait<"ReturnLike"> -]>; +def CIRReturnLike + : TraitList<[DeclareOpInterfaceMethods, + NativeOpTrait<"ReturnLike">]>; //===----------------------------------------------------------------------===// // CIR Operation Traits //===----------------------------------------------------------------------===// -class HasAtMostOneOfAttrsPred names> : - CPred; - -class HasAtMostOneOfAttrs names> : PredOpTrait< - "has only one of the optional attributes: " # !interleave(names, ", "), - HasAtMostOneOfAttrsPred ->; +class HasAtMostOneOfAttrsPred names> + : CPred; +class HasAtMostOneOfAttrs names> + : PredOpTrait<"has only one of the optional attributes: "#!interleave(names, + ", "), + HasAtMostOneOfAttrsPred>; //===----------------------------------------------------------------------===// // CastOp //===----------------------------------------------------------------------===// -def CIR_CastKind : CIR_I32EnumAttr<"CastKind", "cast kind", [ - 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 CIR_CastKind + : CIR_I32EnumAttr< + "CastKind", "cast kind", + [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 CIR_CastOp : CIR_Op<"cast",[ - Pure, - DeclareOpInterfaceMethods -]> { +def CIR_CastOp + : CIR_Op<"cast", [Pure, DeclareOpInterfaceMethods]> { // FIXME: not all conversions are free of side effects. let summary = "Conversion between values of different types"; let description = [{ @@ -252,11 +243,10 @@ def CIR_CastOp : CIR_Op<"cast",[ // DynamicCastOp //===----------------------------------------------------------------------===// -def CIR_DynamicCastKind : CIR_I32EnumAttr< - "DynamicCastKind", "dynamic cast kind", [ - I32EnumAttrCase<"Ptr", 0, "ptr">, - I32EnumAttrCase<"Ref", 1, "ref"> -]>; +def CIR_DynamicCastKind + : CIR_I32EnumAttr<"DynamicCastKind", "dynamic cast kind", + [I32EnumAttrCase<"Ptr", 0, "ptr">, + I32EnumAttrCase<"Ref", 1, "ref">]>; def CIR_DynamicCastOp : CIR_Op<"dyn_cast"> { let summary = "Perform dynamic cast on record pointers"; @@ -301,16 +291,10 @@ def CIR_DynamicCastOp : CIR_Op<"dyn_cast"> { ``` }]; - let arguments = (ins - CIR_DynamicCastKind:$kind, - CIR_PtrToRecordType:$src, - OptionalAttr:$info, - UnitAttr:$relative_layout - ); + let arguments = (ins CIR_DynamicCastKind:$kind, CIR_PtrToRecordType:$src, + OptionalAttr:$info, UnitAttr:$relative_layout); - let results = (outs - CIR_PtrToAnyOf<[CIR_VoidType, CIR_RecordType]>:$result - ); + let results = (outs CIR_PtrToAnyOf<[CIR_VoidType, CIR_RecordType]>:$result); let assemblyFormat = [{ $kind (`relative_layout` $relative_layout^)? $src @@ -357,11 +341,7 @@ def CIR_ObjSizeOp : CIR_Op<"objsize", [Pure]> { ``` }]; - let arguments = (ins - CIR_PointerType:$ptr, - UnitAttr:$min, - UnitAttr:$dynamic - ); + let arguments = (ins CIR_PointerType:$ptr, UnitAttr:$min, UnitAttr:$dynamic); let results = (outs CIR_AnyFundamentalIntType:$result); @@ -412,26 +392,22 @@ def CIR_GEPNone : I32BitEnumCaseNone<"none">; def CIR_GEPInboundsFlag : I32BitEnumCaseBit<"inboundsFlag", 0, "inbounds_flag">; def CIR_GEPNusw : I32BitEnumCaseBit<"nusw", 1>; def CIR_GEPNuw : I32BitEnumCaseBit<"nuw", 2>; -def CIR_GEPInbounds : BitEnumCaseGroup<"inbounds", [ - CIR_GEPInboundsFlag, CIR_GEPNusw]>; - -def CIR_GEPNoWrapFlags : CIR_I32BitEnum<"GEPNoWrapFlags", "no-wrap flags", [ - CIR_GEPNone, - CIR_GEPInboundsFlag, - CIR_GEPNusw, - CIR_GEPNuw, - CIR_GEPInbounds -]> { +def CIR_GEPInbounds + : BitEnumCaseGroup<"inbounds", [CIR_GEPInboundsFlag, CIR_GEPNusw]>; + +def CIR_GEPNoWrapFlags + : CIR_I32BitEnum<"GEPNoWrapFlags", "no-wrap flags", + [CIR_GEPNone, CIR_GEPInboundsFlag, CIR_GEPNusw, CIR_GEPNuw, + CIR_GEPInbounds]> { let printBitEnumPrimaryGroups = 1; } def CIR_GEPNoWrapFlagsProp : EnumProp { - let defaultValue = enum.cppType # "::" # "none"; + let defaultValue = enum.cppType#"::"#"none"; } -def CIR_PtrStrideOp : CIR_Op<"ptr_stride",[ - Pure, AllTypesMatch<["base", "result"]> -]> { +def CIR_PtrStrideOp + : CIR_Op<"ptr_stride", [Pure, AllTypesMatch<["base", "result"]>]> { let summary = "Pointer access with stride"; let description = [{ The `cir.ptr_stride` operation computes a new pointer from a base pointer @@ -450,11 +426,8 @@ def CIR_PtrStrideOp : CIR_Op<"ptr_stride",[ ``` }]; - let arguments = (ins - CIR_PointerType:$base, - CIR_AnyFundamentalIntType:$stride, - CIR_GEPNoWrapFlagsProp:$noWrapFlags - ); + let arguments = (ins CIR_PointerType:$base, CIR_AnyFundamentalIntType:$stride, + CIR_GEPNoWrapFlagsProp:$noWrapFlags); let results = (outs CIR_PointerType:$result); @@ -475,9 +448,8 @@ def CIR_PtrStrideOp : CIR_Op<"ptr_stride",[ // ConstantOp //===----------------------------------------------------------------------===// -def CIR_ConstantOp : CIR_Op<"const",[ - ConstantLike, Pure, AllTypesMatch<["value", "res"]> -]> { +def CIR_ConstantOp + : CIR_Op<"const", [ConstantLike, Pure, AllTypesMatch<["value", "res"]>]> { let summary = "Create a CIR constant from a literal attribute"; let description = [{ The `cir.const` operation turns a literal into an SSA value. The data is @@ -528,46 +500,47 @@ def CIR_ConstantOp : CIR_Op<"const",[ // C/C++ memory order definitions //===----------------------------------------------------------------------===// -def CIR_MemOrder : CIR_I32EnumAttr< - "MemOrder", "Memory order according to C++11 memory model", [ - I32EnumAttrCase<"Relaxed", 0, "relaxed">, - I32EnumAttrCase<"Consume", 1, "consume">, - I32EnumAttrCase<"Acquire", 2, "acquire">, - I32EnumAttrCase<"Release", 3, "release">, - I32EnumAttrCase<"AcquireRelease", 4, "acq_rel">, - I32EnumAttrCase<"SequentiallyConsistent", 5, "seq_cst"> -]>; +def CIR_MemOrder + : CIR_I32EnumAttr< + "MemOrder", "Memory order according to C++11 memory model", + [I32EnumAttrCase<"Relaxed", 0, "relaxed">, + I32EnumAttrCase<"Consume", 1, "consume">, + I32EnumAttrCase<"Acquire", 2, "acquire">, + I32EnumAttrCase<"Release", 3, "release">, + I32EnumAttrCase<"AcquireRelease", 4, "acq_rel">, + I32EnumAttrCase<"SequentiallyConsistent", 5, "seq_cst">]>; //===----------------------------------------------------------------------===// // C/C++ sync scope definitions //===----------------------------------------------------------------------===// -def CIR_SyncScopeKind : CIR_I32EnumAttr<"SyncScopeKind", "sync scope kind", [ - I32EnumAttrCase<"SingleThread", 0, "single_thread">, - I32EnumAttrCase<"System", 1, "system"> -]>; +def CIR_SyncScopeKind + : CIR_I32EnumAttr<"SyncScopeKind", "sync scope kind", + [I32EnumAttrCase<"SingleThread", 0, "single_thread">, + I32EnumAttrCase<"System", 1, "system">]>; //===----------------------------------------------------------------------===// // AllocaOp //===----------------------------------------------------------------------===// -class CIR_AllocaTypesMatchWith< - string summary, string lhsArg, string rhsArg, string transform, - string comparator = "std::equal_to<>()" -> : PredOpTrait -> { +class CIR_AllocaTypesMatchWith + : PredOpTrait> { string lhs = lhsArg; string rhs = rhsArg; string transformer = transform; } -def CIR_AllocaOp : CIR_Op<"alloca", [ - CIR_AllocaTypesMatchWith<"'allocaType' matches pointee type of 'addr'", - "addr", "allocaType", "mlir::cast($_self).getPointee()">, - DeclareOpInterfaceMethods -]> { +def CIR_AllocaOp + : CIR_Op<"alloca", + [CIR_AllocaTypesMatchWith< + "'allocaType' matches pointee type of 'addr'", "addr", + "allocaType", + "mlir::cast($_self).getPointee()">, + DeclareOpInterfaceMethods]> { let summary = "Defines a scope-local variable"; let description = [{ The `cir.alloca` operation defines a scope-local variable. @@ -598,37 +571,29 @@ def CIR_AllocaOp : CIR_Op<"alloca", [ ``` }]; - let arguments = (ins - Optional:$dynAllocSize, - TypeAttr:$allocaType, - StrAttr:$name, - UnitAttr:$init, - UnitAttr:$constant, - ConfinedAttr, [IntMinValue<0>]>:$alignment, - OptionalAttr:$annotations, - OptionalAttr:$ast - ); + let arguments = (ins Optional:$dynAllocSize, + TypeAttr:$allocaType, StrAttr:$name, UnitAttr:$init, UnitAttr:$constant, + ConfinedAttr, [IntMinValue<0>]>:$alignment, + OptionalAttr:$annotations, + OptionalAttr:$ast); - let results = (outs Res]>:$addr); + let results = + (outs Res]>:$addr); let skipDefaultBuilders = 1; - let builders = [ - OpBuilder<(ins "mlir::Type":$addr, "mlir::Type":$allocaType, - "llvm::StringRef":$name, - "mlir::IntegerAttr":$alignment)>, - - OpBuilder<(ins "mlir::Type":$addr, - "mlir::Type":$allocaType, - "llvm::StringRef":$name, - "mlir::IntegerAttr":$alignment, - "mlir::Value":$dynAllocSize), - [{ + let builders = [OpBuilder<(ins "mlir::Type":$addr, "mlir::Type":$allocaType, + "llvm::StringRef":$name, "mlir::IntegerAttr":$alignment)>, + + OpBuilder<(ins "mlir::Type":$addr, "mlir::Type":$allocaType, + "llvm::StringRef":$name, + "mlir::IntegerAttr":$alignment, + "mlir::Value":$dynAllocSize), + [{ if (dynAllocSize) $_state.addOperands(dynAllocSize); build($_builder, $_state, addr, allocaType, name, alignment); - }]> - ]; + }]>]; let extraClassDeclaration = [{ // Whether the alloca input type is a pointer. @@ -653,11 +618,12 @@ def CIR_AllocaOp : CIR_Op<"alloca", [ // LoadOp //===----------------------------------------------------------------------===// -def CIR_LoadOp : CIR_Op<"load", [ - TypesMatchWith<"type of 'result' matches pointee type of 'addr'", - "addr", "result", "mlir::cast($_self).getPointee()">, - DeclareOpInterfaceMethods -]> { +def CIR_LoadOp + : CIR_Op<"load", [TypesMatchWith< + "type of 'result' matches pointee type of 'addr'", + "addr", "result", + "mlir::cast($_self).getPointee()">, + DeclareOpInterfaceMethods]> { let summary = "Load value from memory adddress"; let description = [{ `cir.load` reads a value (lvalue to rvalue conversion) given an address @@ -689,15 +655,13 @@ def CIR_LoadOp : CIR_Op<"load", [ ``` }]; - let arguments = (ins Arg:$addr, UnitAttr:$isDeref, - UnitAttr:$is_volatile, - UnitAttr:$is_nontemporal, - OptionalAttr:$alignment, - OptionalAttr:$sync_scope, - OptionalAttr:$mem_order, - OptionalAttr:$tbaa - ); + let arguments = + (ins Arg:$addr, + UnitAttr:$isDeref, UnitAttr:$is_volatile, UnitAttr:$is_nontemporal, + OptionalAttr:$alignment, + OptionalAttr:$sync_scope, + OptionalAttr:$mem_order, + OptionalAttr:$tbaa); let results = (outs CIR_AnyType:$result); let assemblyFormat = [{ @@ -726,11 +690,12 @@ def CIR_LoadOp : CIR_Op<"load", [ // StoreOp //===----------------------------------------------------------------------===// -def CIR_StoreOp : CIR_Op<"store", [ - TypesMatchWith<"type of 'value' matches pointee type of 'addr'", - "addr", "value", "mlir::cast($_self).getPointee()">, - DeclareOpInterfaceMethods -]> { +def CIR_StoreOp + : CIR_Op<"store", [TypesMatchWith< + "type of 'value' matches pointee type of 'addr'", + "addr", "value", + "mlir::cast($_self).getPointee()">, + DeclareOpInterfaceMethods]> { let summary = "Store value to memory address"; let description = [{ `cir.store` stores a value (first operand) to the memory address specified @@ -755,20 +720,15 @@ def CIR_StoreOp : CIR_Op<"store", [ ``` }]; - let builders = [ - OpBuilder<(ins "mlir::Value":$value, "mlir::Value":$addr), [{ + let builders = [OpBuilder<(ins "mlir::Value":$value, "mlir::Value":$addr), [{ $_state.addOperands({value, addr}); - }]> - ]; + }]>]; let arguments = (ins CIR_AnyType:$value, - Arg:$addr, - UnitAttr:$is_volatile, - UnitAttr:$is_nontemporal, - OptionalAttr:$alignment, - OptionalAttr:$mem_order, - OptionalAttr:$tbaa); + Arg:$addr, + UnitAttr:$is_volatile, UnitAttr:$is_nontemporal, + OptionalAttr:$alignment, OptionalAttr:$mem_order, + OptionalAttr:$tbaa); let assemblyFormat = [{ (`volatile` $is_volatile^)? @@ -793,14 +753,12 @@ def CIR_StoreOp : CIR_Op<"store", [ // ReturnOp //===----------------------------------------------------------------------===// -defvar CIR_ReturnableScopes = [ - "FuncOp", "ScopeOp", "IfOp", "SwitchOp", "DoWhileOp", "WhileOp", "ForOp", - "CaseOp", "TryOp" -]; +defvar CIR_ReturnableScopes = ["FuncOp", "ScopeOp", "IfOp", "SwitchOp", + "DoWhileOp", "WhileOp", "ForOp", "CaseOp", + "TryOp"]; -def CIR_ReturnOp : CIR_Op<"return", [ - ParentOneOf, Terminator -]> { +def CIR_ReturnOp + : CIR_Op<"return", [ParentOneOf, Terminator]> { let summary = "Return from function"; let description = [{ The "return" operation represents a return operation within a function. @@ -824,9 +782,7 @@ def CIR_ReturnOp : CIR_Op<"return", [ let assemblyFormat = "($input^ `:` type($input))? attr-dict "; // Allow building a ReturnOp with no return operand. - let builders = [ - OpBuilder<(ins), [{ build($_builder, $_state, {}); }]> - ]; + let builders = [OpBuilder<(ins), [{ build($_builder, $_state, {}); }]>]; // Provide extra utility definitions on the c++ operation class definition. let extraClassDeclaration = [{ @@ -840,9 +796,9 @@ def CIR_ReturnOp : CIR_Op<"return", [ // IfOp //===----------------------------------------------------------------------===// -def CIR_IfOp : CIR_Op<"if", - [DeclareOpInterfaceMethods, - RecursivelySpeculatable, AutomaticAllocationScope, NoRegionArguments]> { +def CIR_IfOp : CIR_Op<"if", [DeclareOpInterfaceMethods, + RecursivelySpeculatable, AutomaticAllocationScope, + NoRegionArguments]> { let summary = "The if-then-else operation"; let description = [{ The `cir.if` operation represents an if-then-else construct for @@ -882,23 +838,21 @@ def CIR_IfOp : CIR_Op<"if", let hasVerifier = 1; let skipDefaultBuilders = 1; - let builders = [ - OpBuilder<(ins "mlir::Value":$cond, "bool":$withElseRegion, + let builders = [OpBuilder<(ins "mlir::Value":$cond, "bool":$withElseRegion, CArg<"llvm::function_ref", "buildTerminatedBody">:$thenBuilder, CArg<"llvm::function_ref", - "nullptr">:$elseBuilder)> - ]; + "nullptr">:$elseBuilder)>]; } //===----------------------------------------------------------------------===// // TernaryOp //===----------------------------------------------------------------------===// -def CIR_TernaryOp : CIR_Op<"ternary", [ - DeclareOpInterfaceMethods, - RecursivelySpeculatable, AutomaticAllocationScope, NoRegionArguments -]> { +def CIR_TernaryOp + : CIR_Op<"ternary", [DeclareOpInterfaceMethods, + RecursivelySpeculatable, AutomaticAllocationScope, + NoRegionArguments]> { let summary = "The `cond ? a : b` C/C++ ternary operation"; let description = [{ The `cir.ternary` operation represents C/C++ ternary, much like a `select` @@ -922,17 +876,15 @@ def CIR_TernaryOp : CIR_Op<"ternary", [ ``` }]; let arguments = (ins CIR_BoolType:$cond); - let regions = (region AnyRegion:$trueRegion, - AnyRegion:$falseRegion); + let regions = (region AnyRegion:$trueRegion, AnyRegion:$falseRegion); let results = (outs Optional:$result); let skipDefaultBuilders = 1; - let builders = [ - OpBuilder<(ins "mlir::Value":$cond, - "llvm::function_ref":$trueBuilder, - "llvm::function_ref":$falseBuilder) - > - ]; + let builders = [OpBuilder<(ins "mlir::Value":$cond, + "llvm::function_ref":$trueBuilder, + "llvm::function_ref":$falseBuilder)>]; let assemblyFormat = [{ `(` $cond `,` @@ -946,10 +898,9 @@ def CIR_TernaryOp : CIR_Op<"ternary", [ // SelectOp //===----------------------------------------------------------------------===// -def CIR_SelectOp : CIR_Op<"select", [ - Pure, - AllTypesMatch<["true_value", "false_value", "result"]> -]> { +def CIR_SelectOp + : CIR_Op<"select", [Pure, AllTypesMatch<["true_value", "false_value", + "result"]>]> { let summary = "Yield one of two values based on a boolean value"; let description = [{ The `cir.select` operation takes three operands. The first operand @@ -969,7 +920,7 @@ def CIR_SelectOp : CIR_Op<"select", [ }]; let arguments = (ins CIR_BoolType:$condition, CIR_AnyType:$true_value, - CIR_AnyType:$false_value); + CIR_AnyType:$false_value); let results = (outs CIR_AnyType:$result); let assemblyFormat = [{ @@ -988,12 +939,11 @@ def CIR_SelectOp : CIR_Op<"select", [ // ConditionOp //===----------------------------------------------------------------------===// -def CIR_ConditionOp : CIR_Op<"condition", [ - Terminator, CIR_ConditionOpInterface, - DeclareOpInterfaceMethods -]> { +def CIR_ConditionOp + : CIR_Op<"condition", [Terminator, CIR_ConditionOpInterface, + DeclareOpInterfaceMethods< + RegionBranchTerminatorOpInterface, + ["getSuccessorRegions"]>]> { let summary = "Loop continuation condition."; let description = [{ The `cir.condition` terminates conditional regions. It takes a single @@ -1034,14 +984,13 @@ def CIR_ConditionOp : CIR_Op<"condition", [ // YieldOp //===----------------------------------------------------------------------===// -defvar CIR_YieldableScopes = [ - "ArrayCtor", "ArrayDtor", "AwaitOp", "CallOp", "CaseOp", "DoWhileOp", "ForOp", - "GlobalOp", "IfOp", "ScopeOp", "SwitchOp", "TernaryOp", "TryOp", "WhileOp" -]; +defvar CIR_YieldableScopes = ["ArrayCtor", "ArrayDtor", "AwaitOp", "CallOp", + "CaseOp", "DoWhileOp", "ForOp", "GlobalOp", + "GuardedInitOp", "IfOp", "ScopeOp", "SwitchOp", + "TernaryOp", "TryOp", "WhileOp"]; -def CIR_YieldOp : CIR_Op<"yield", [ - CIRReturnLike, Terminator, ParentOneOf -]> { +def CIR_YieldOp : CIR_Op<"yield", [CIRReturnLike, Terminator, + ParentOneOf]> { let summary = "Represents the default branching behaviour of a region"; let description = [{ The `cir.yield` operation terminates regions on different CIR operations, @@ -1092,9 +1041,7 @@ def CIR_YieldOp : CIR_Op<"yield", [ let arguments = (ins Variadic:$args); let assemblyFormat = "($args^ `:` type($args))? attr-dict"; - let builders = [ - OpBuilder<(ins), [{ /* nothing to do */ }]>, - ]; + let builders = [OpBuilder<(ins), [{ /* nothing to do */ }]>, ]; } //===----------------------------------------------------------------------===// @@ -1136,9 +1083,8 @@ def CIR_ContinueOp : CIR_Op<"continue", [Terminator]> { // Resume //===----------------------------------------------------------------------===// -def CIR_ResumeOp : CIR_Op<"resume", [ - ReturnLike, Terminator, AttrSizedOperandSegments -]> { +def CIR_ResumeOp + : CIR_Op<"resume", [ReturnLike, Terminator, AttrSizedOperandSegments]> { let summary = "Resumes execution after not catching exceptions"; let description = [{ The `cir.resume` operation handles an uncaught exception scenario and @@ -1155,8 +1101,7 @@ def CIR_ResumeOp : CIR_Op<"resume", [ }]; let arguments = (ins Optional:$exception_ptr, - Optional:$type_id, - UnitAttr:$rethrow); + Optional:$type_id, UnitAttr:$rethrow); let assemblyFormat = [{ (`rethrow` $rethrow^)? ($exception_ptr^ (`,` $type_id^)?)? @@ -1168,10 +1113,10 @@ def CIR_ResumeOp : CIR_Op<"resume", [ // ScopeOp //===----------------------------------------------------------------------===// -def CIR_ScopeOp : CIR_Op<"scope", [ - DeclareOpInterfaceMethods, - RecursivelySpeculatable, AutomaticAllocationScope, NoRegionArguments -]> { +def CIR_ScopeOp + : CIR_Op<"scope", [DeclareOpInterfaceMethods, + RecursivelySpeculatable, AutomaticAllocationScope, + NoRegionArguments]> { let summary = "Represents a C/C++ scope"; let description = [{ `cir.scope` contains one region and defines a strict "scope" for all new @@ -1220,25 +1165,24 @@ def CIR_ScopeOp : CIR_Op<"scope", [ }]; let builders = [ - // Scopes for yielding values. - OpBuilder<(ins - "llvm::function_ref":$scopeBuilder)>, - // Scopes without yielding values. - OpBuilder<(ins "llvm::function_ref":$scopeBuilder)> - ]; + // Scopes for yielding values. + OpBuilder<(ins "llvm::function_ref":$scopeBuilder)>, + // Scopes without yielding values. + OpBuilder<(ins "llvm::function_ref":$scopeBuilder)>]; } //===----------------------------------------------------------------------===// // UnaryOp //===----------------------------------------------------------------------===// -def CIR_UnaryOpKind : CIR_I32EnumAttr<"UnaryOpKind", "unary operation kind", [ - I32EnumAttrCase<"Inc", 0, "inc">, - I32EnumAttrCase<"Dec", 1, "dec">, - I32EnumAttrCase<"Plus", 2, "plus">, - I32EnumAttrCase<"Minus", 3, "minus">, - I32EnumAttrCase<"Not", 4, "not"> -]>; +def CIR_UnaryOpKind : CIR_I32EnumAttr<"UnaryOpKind", "unary operation kind", + [I32EnumAttrCase<"Inc", 0, "inc">, + I32EnumAttrCase<"Dec", 1, "dec">, + I32EnumAttrCase<"Plus", 2, "plus">, + I32EnumAttrCase<"Minus", 3, "minus">, + I32EnumAttrCase<"Not", 4, "not">]>; // FIXME: Pure won't work when we add overloading. def CIR_UnaryOp : CIR_Op<"unary", [Pure, SameOperandsAndResultType]> { @@ -1256,11 +1200,8 @@ def CIR_UnaryOp : CIR_Op<"unary", [Pure, SameOperandsAndResultType]> { ``` }]; - let arguments = (ins - Arg:$kind, - Arg:$input, - UnitAttr:$no_signed_wrap - ); + let arguments = (ins Arg:$kind, + Arg:$input, UnitAttr:$no_signed_wrap); let results = (outs CIR_AnyType:$result); @@ -1279,23 +1220,18 @@ def CIR_UnaryOp : CIR_Op<"unary", [Pure, SameOperandsAndResultType]> { //===----------------------------------------------------------------------===// // FIXME: represent Commutative, Idempotent traits for appropriate binops -def CIR_BinOpKind : CIR_I32EnumAttr< - "BinOpKind", "binary operation (arith and logic) kind", [ - I32EnumAttrCase<"Mul", 0, "mul">, - I32EnumAttrCase<"Div", 1, "div">, - I32EnumAttrCase<"Rem", 2, "rem">, - I32EnumAttrCase<"Add", 3, "add">, - I32EnumAttrCase<"Sub", 4, "sub">, - I32EnumAttrCase<"And", 5, "and">, - I32EnumAttrCase<"Xor", 6, "xor">, - I32EnumAttrCase<"Or", 7, "or">, - I32EnumAttrCase<"Max", 8, "max"> -]>; +def CIR_BinOpKind + : CIR_I32EnumAttr< + "BinOpKind", "binary operation (arith and logic) kind", + [I32EnumAttrCase<"Mul", 0, "mul">, I32EnumAttrCase<"Div", 1, "div">, + I32EnumAttrCase<"Rem", 2, "rem">, I32EnumAttrCase<"Add", 3, "add">, + I32EnumAttrCase<"Sub", 4, "sub">, I32EnumAttrCase<"And", 5, "and">, + I32EnumAttrCase<"Xor", 6, "xor">, I32EnumAttrCase<"Or", 7, "or">, + I32EnumAttrCase<"Max", 8, "max">]>; // FIXME: Pure won't work when we add overloading. -def CIR_BinOp : CIR_Op<"binop", [ - Pure, SameTypeOperands, SameOperandsAndResultType -]> { +def CIR_BinOp + : CIR_Op<"binop", [Pure, SameTypeOperands, SameOperandsAndResultType]> { let summary = "Binary operations (arith and logic)"; let description = [{ cir.binop performs the binary operation according to @@ -1311,13 +1247,9 @@ def CIR_BinOp : CIR_Op<"binop", [ ``` }]; - let arguments = (ins - CIR_BinOpKind:$kind, - CIR_AnyType:$lhs, CIR_AnyType:$rhs, - UnitAttr:$no_unsigned_wrap, - UnitAttr:$no_signed_wrap, - UnitAttr:$saturated - ); + let arguments = (ins CIR_BinOpKind:$kind, CIR_AnyType:$lhs, CIR_AnyType:$rhs, + UnitAttr:$no_unsigned_wrap, UnitAttr:$no_signed_wrap, + UnitAttr:$saturated); // TODO: get more accurate than CIR_AnyType let results = (outs CIR_AnyType:$result); @@ -1353,11 +1285,8 @@ def CIR_ShiftOp : CIR_Op<"shift", [Pure]> { ``` }]; - let arguments = (ins - CIR_AnyIntOrVecOfIntType:$value, - CIR_AnyIntOrVecOfIntType:$amount, - UnitAttr:$isShiftleft - ); + let arguments = (ins CIR_AnyIntOrVecOfIntType:$value, + CIR_AnyIntOrVecOfIntType:$amount, UnitAttr:$isShiftleft); let results = (outs CIR_AnyIntOrVecOfIntType:$result); @@ -1376,14 +1305,11 @@ def CIR_ShiftOp : CIR_Op<"shift", [Pure]> { // CmpOp //===----------------------------------------------------------------------===// -def CIR_CmpOpKind : CIR_I32EnumAttr<"CmpOpKind", "compare operation kind", [ - I32EnumAttrCase<"lt", 0>, - I32EnumAttrCase<"le", 1>, - I32EnumAttrCase<"gt", 2>, - I32EnumAttrCase<"ge", 3>, - I32EnumAttrCase<"eq", 4>, - I32EnumAttrCase<"ne", 5> -]>; +def CIR_CmpOpKind + : CIR_I32EnumAttr<"CmpOpKind", "compare operation kind", + [I32EnumAttrCase<"lt", 0>, I32EnumAttrCase<"le", 1>, + I32EnumAttrCase<"gt", 2>, I32EnumAttrCase<"ge", 3>, + I32EnumAttrCase<"eq", 4>, I32EnumAttrCase<"ne", 5>]>; // FIXME: Pure might not work when we add overloading. def CIR_CmpOp : CIR_Op<"cmp", [Pure, SameTypeOperands]> { @@ -1398,11 +1324,7 @@ def CIR_CmpOp : CIR_Op<"cmp", [Pure, SameTypeOperands]> { ``` }]; - let arguments = (ins - CIR_CmpOpKind:$kind, - CIR_AnyType:$lhs, - CIR_AnyType:$rhs - ); + let arguments = (ins CIR_CmpOpKind:$kind, CIR_AnyType:$lhs, CIR_AnyType:$rhs); let results = (outs CIR_BoolType:$result); @@ -1415,12 +1337,11 @@ def CIR_CmpOp : CIR_Op<"cmp", [Pure, SameTypeOperands]> { // BinOpOverflowOp //===----------------------------------------------------------------------===// -def CIR_BinOpOverflowKind : CIR_I32EnumAttr< - "BinOpOverflowKind", "checked binary arithmetic operation kind", [ - I32EnumAttrCase<"Add", 0, "add">, - I32EnumAttrCase<"Sub", 1, "sub">, - I32EnumAttrCase<"Mul", 2, "mul"> -]>; +def CIR_BinOpOverflowKind + : CIR_I32EnumAttr< + "BinOpOverflowKind", "checked binary arithmetic operation kind", + [I32EnumAttrCase<"Add", 0, "add">, I32EnumAttrCase<"Sub", 1, "sub">, + I32EnumAttrCase<"Mul", 2, "mul">]>; def CIR_BinOpOverflowOp : CIR_Op<"binop.overflow", [Pure, SameTypeOperands]> { let summary = "Perform binary integral arithmetic with overflow checking"; @@ -1448,11 +1369,8 @@ def CIR_BinOpOverflowOp : CIR_Op<"binop.overflow", [Pure, SameTypeOperands]> { is assigned to false. Otherwise, `overflow` is assigned to true. }]; - let arguments = (ins - CIR_BinOpOverflowKind:$kind, - CIR_IntType:$lhs, - CIR_IntType:$rhs - ); + let arguments = (ins CIR_BinOpOverflowKind:$kind, CIR_IntType:$lhs, + CIR_IntType:$rhs); let results = (outs CIR_IntType:$result, CIR_BoolType:$overflow); @@ -1462,15 +1380,13 @@ def CIR_BinOpOverflowOp : CIR_Op<"binop.overflow", [Pure, SameTypeOperands]> { attr-dict }]; - let builders = [ - OpBuilder<(ins "cir::IntType":$resultTy, - "cir::BinOpOverflowKind":$kind, - "mlir::Value":$lhs, - "mlir::Value":$rhs), [{ + let builders = [OpBuilder<(ins "cir::IntType":$resultTy, + "cir::BinOpOverflowKind":$kind, + "mlir::Value":$lhs, "mlir::Value":$rhs), + [{ auto overflowTy = cir::BoolType::get($_builder.getContext()); build($_builder, $_state, resultTy, overflowTy, kind, lhs, rhs); - }]> - ]; + }]>]; } //===----------------------------------------------------------------------===// @@ -1493,10 +1409,8 @@ def CIR_ComplexCreateOp : CIR_Op<"complex.create", [Pure, SameTypeOperands]> { }]; let results = (outs CIR_ComplexType:$result); - let arguments = (ins - CIR_AnyIntOrFloatType:$real, - CIR_AnyIntOrFloatType:$imag - ); + let arguments = (ins CIR_AnyIntOrFloatType:$real, + CIR_AnyIntOrFloatType:$imag); let assemblyFormat = [{ $real `,` $imag @@ -1619,23 +1533,22 @@ def CIR_ComplexImagPtrOp : CIR_Op<"complex.imag_ptr", [Pure]> { // ComplexBinOp //===----------------------------------------------------------------------===// -def CIR_ComplexBinOpKind : CIR_I32EnumAttr< - "ComplexBinOpKind", "complex number binary operation kind", [ - I32EnumAttrCase<"Mul", 0, "mul">, - I32EnumAttrCase<"Div", 1, "div"> -]>; +def CIR_ComplexBinOpKind + : CIR_I32EnumAttr< + "ComplexBinOpKind", "complex number binary operation kind", + [I32EnumAttrCase<"Mul", 0, "mul">, I32EnumAttrCase<"Div", 1, "div">]>; -def CIR_ComplexRangeKind : CIR_I32EnumAttr< - "ComplexRangeKind", "complex multiplication and division implementation", [ - I32EnumAttrCase<"Full", 0, "full">, - I32EnumAttrCase<"Improved", 1, "improved">, - I32EnumAttrCase<"Promoted", 2, "promoted">, - I32EnumAttrCase<"Basic", 3, "basic">, +def CIR_ComplexRangeKind + : CIR_I32EnumAttr<"ComplexRangeKind", + "complex multiplication and division implementation", + [I32EnumAttrCase<"Full", 0, "full">, + I32EnumAttrCase<"Improved", 1, "improved">, + I32EnumAttrCase<"Promoted", 2, "promoted">, + I32EnumAttrCase<"Basic", 3, "basic">, ]>; -def CIR_ComplexBinOp : CIR_Op<"complex.binop",[ - Pure, SameTypeOperands, SameOperandsAndResultType -]> { +def CIR_ComplexBinOp : CIR_Op<"complex.binop", [Pure, SameTypeOperands, + SameOperandsAndResultType]> { let summary = "Binary operations on operands of complex type"; let description = [{ The `cir.complex.binop` operation represents a binary operation on operands @@ -1658,13 +1571,8 @@ def CIR_ComplexBinOp : CIR_Op<"complex.binop",[ ``` }]; - let arguments = (ins - CIR_ComplexBinOpKind:$kind, - CIR_ComplexType:$lhs, - CIR_ComplexType:$rhs, - CIR_ComplexRangeKind:$range, - UnitAttr:$promoted - ); + let arguments = (ins CIR_ComplexBinOpKind:$kind, CIR_ComplexType:$lhs, + CIR_ComplexType:$rhs, CIR_ComplexRangeKind:$range, UnitAttr:$promoted); let results = (outs CIR_ComplexType:$result); @@ -1678,9 +1586,8 @@ def CIR_ComplexBinOp : CIR_Op<"complex.binop",[ // BitsOp //===----------------------------------------------------------------------===// -class CIR_BitOp : CIR_Op { +class CIR_BitOp + : CIR_Op { let arguments = (ins inputTy:$input); let results = (outs inputTy:$result); @@ -1903,8 +1810,7 @@ def CIR_RotateOp : CIR_Op<"rotate", [Pure, SameOperandsAndResultType]> { }]; let results = (outs CIR_IntType:$result); - let arguments = (ins CIR_IntType:$src, CIR_IntType:$amt, - UnitAttr:$left); + let arguments = (ins CIR_IntType:$src, CIR_IntType:$amt, UnitAttr:$left); let assemblyFormat = [{ (`left` $left^) : (`right`)? @@ -1916,9 +1822,8 @@ def CIR_RotateOp : CIR_Op<"rotate", [Pure, SameOperandsAndResultType]> { // BitReverseOp //===----------------------------------------------------------------------===// -def CIR_BitReverseOp : CIR_Op<"bit_reverse", [ - Pure, SameOperandsAndResultType -]> { +def CIR_BitReverseOp + : CIR_Op<"bit_reverse", [Pure, SameOperandsAndResultType]> { let summary = "Reverse the bit pattern of the operand integer"; let description = [{ The `cir.bit_reverse` operation reverses the bit pattern of the operand @@ -1981,11 +1886,8 @@ def CIR_CmpThreeWayOp : CIR_Op<"cmp3way", [Pure, SameTypeOperands]> { ``` }]; - let arguments = (ins - CIR_AnyType:$lhs, - CIR_AnyType:$rhs, - CIR_CmpThreeWayInfoAttr:$info - ); + let arguments = (ins CIR_AnyType:$lhs, CIR_AnyType:$rhs, + CIR_CmpThreeWayInfoAttr:$info); let results = (outs CIR_AnySIntType:$result); @@ -2011,17 +1913,15 @@ def CIR_CmpThreeWayOp : CIR_Op<"cmp3way", [Pure, SameTypeOperands]> { // SwitchOp //===----------------------------------------------------------------------===// -def CIR_CaseOpKind : CIR_I32EnumAttr<"CaseOpKind", "case kind", [ - I32EnumAttrCase<"Default", 0, "default">, - I32EnumAttrCase<"Equal", 1, "equal">, - I32EnumAttrCase<"Anyof", 2, "anyof">, - I32EnumAttrCase<"Range", 3, "range"> -]>; +def CIR_CaseOpKind : CIR_I32EnumAttr<"CaseOpKind", "case kind", + [I32EnumAttrCase<"Default", 0, "default">, + I32EnumAttrCase<"Equal", 1, "equal">, + I32EnumAttrCase<"Anyof", 2, "anyof">, + I32EnumAttrCase<"Range", 3, "range">]>; -def CIR_CaseOp : CIR_Op<"case", [ - DeclareOpInterfaceMethods, - RecursivelySpeculatable, AutomaticAllocationScope -]> { +def CIR_CaseOp + : CIR_Op<"case", [DeclareOpInterfaceMethods, + RecursivelySpeculatable, AutomaticAllocationScope]> { let summary = "Case operation"; let description = [{ The `cir.case` operation represents a case within a C/C++ switch. @@ -2046,19 +1946,15 @@ def CIR_CaseOp : CIR_Op<"case", [ let hasVerifier = 1; let skipDefaultBuilders = 1; - let builders = [ - OpBuilder<(ins "mlir::ArrayAttr":$value, - "CaseOpKind":$kind, - "mlir::OpBuilder::InsertPoint &":$insertPoint)> - ]; + let builders = [OpBuilder<(ins "mlir::ArrayAttr":$value, "CaseOpKind":$kind, + "mlir::OpBuilder::InsertPoint &":$insertPoint)>]; } -def CIR_SwitchOp : CIR_Op<"switch", [ - SameVariadicOperandSize, - DeclareOpInterfaceMethods, - RecursivelySpeculatable, AutomaticAllocationScope, NoRegionArguments, - CIR_Breakable -]> { +def CIR_SwitchOp + : CIR_Op<"switch", [SameVariadicOperandSize, + DeclareOpInterfaceMethods, + RecursivelySpeculatable, AutomaticAllocationScope, + NoRegionArguments, CIR_Breakable]> { let summary = "Switch operation"; let description = [{ The `cir.switch` operation represents C/C++ switch functionality for @@ -2199,10 +2095,9 @@ def CIR_SwitchOp : CIR_Op<"switch", [ let hasVerifier = 1; let skipDefaultBuilders = 1; - let builders = [ - OpBuilder<(ins "mlir::Value":$condition, - "llvm::function_ref":$switchBuilder)> - ]; + let builders = [OpBuilder<(ins "mlir::Value":$condition, + "llvm::function_ref":$switchBuilder)>]; let assemblyFormat = [{ custom( @@ -2225,10 +2120,10 @@ def CIR_SwitchOp : CIR_Op<"switch", [ // BrOp //===----------------------------------------------------------------------===// -def CIR_BrOp : CIR_Op<"br",[ - DeclareOpInterfaceMethods, - Pure, Terminator -]> { +def CIR_BrOp + : CIR_Op<"br", [DeclareOpInterfaceMethods< + BranchOpInterface, ["getSuccessorForOperands"]>, + Pure, Terminator]> { let summary = "Unconditional branch"; let description = [{ The `cir.br` branches unconditionally to a block. Used to represent C/C++ @@ -2247,13 +2142,12 @@ def CIR_BrOp : CIR_Op<"br",[ ``` }]; - let builders = [ - OpBuilder<(ins "mlir::Block *":$dest, - CArg<"mlir::ValueRange", "{}">:$destOperands), [{ + let builders = [OpBuilder<(ins "mlir::Block *":$dest, + CArg<"mlir::ValueRange", "{}">:$destOperands), + [{ $_state.addSuccessors(dest); $_state.addOperands(destOperands); - }]> - ]; + }]>]; let arguments = (ins Variadic:$destOperands); let successors = (successor AnySuccessor:$dest); @@ -2266,10 +2160,10 @@ def CIR_BrOp : CIR_Op<"br",[ // BrCondOp //===----------------------------------------------------------------------===// -def CIR_BrCondOp : CIR_Op<"brcond", [ - DeclareOpInterfaceMethods, - Pure, Terminator, AttrSizedOperandSegments -]> { +def CIR_BrCondOp + : CIR_Op<"brcond", [DeclareOpInterfaceMethods< + BranchOpInterface, ["getSuccessorForOperands"]>, + Pure, Terminator, AttrSizedOperandSegments]> { let summary = "Conditional branch"; let description = [{ The `cir.brcond %cond, ^bb0, ^bb1` branches to 'bb0' block in case @@ -2288,18 +2182,19 @@ def CIR_BrCondOp : CIR_Op<"brcond", [ ``` }]; - let builders = [ - OpBuilder<(ins "mlir::Value":$cond, "mlir::Block *":$destTrue, "mlir::Block *":$destFalse, - CArg<"mlir::ValueRange", "{}">:$destOperandsTrue, - CArg<"mlir::ValueRange", "{}">:$destOperandsFalse), [{ + let builders = [OpBuilder< + (ins "mlir::Value":$cond, "mlir::Block *":$destTrue, + "mlir::Block *":$destFalse, + CArg<"mlir::ValueRange", "{}">:$destOperandsTrue, + CArg<"mlir::ValueRange", "{}">:$destOperandsFalse), + [{ build($_builder, $_state, cond, destOperandsTrue, destOperandsFalse, destTrue, destFalse); - }]> - ]; + }]>]; let arguments = (ins CIR_BoolType:$cond, - Variadic:$destOperandsTrue, - Variadic:$destOperandsFalse); + Variadic:$destOperandsTrue, + Variadic:$destOperandsFalse); let successors = (successor AnySuccessor:$destTrue, AnySuccessor:$destFalse); let assemblyFormat = [{ $cond @@ -2314,9 +2209,9 @@ def CIR_BrCondOp : CIR_Op<"brcond", [ // IndirectBrOp //===----------------------------------------------------------------------===// -def CIR_IndirectBrOp : CIR_Op<"indirectbr", [ - DeclareOpInterfaceMethods - , SameVariadicOperandSize, Terminator, Pure]> { +def CIR_IndirectBrOp + : CIR_Op<"indirectbr", [DeclareOpInterfaceMethods, + SameVariadicOperandSize, Terminator, Pure]> { let summary = "Indirect branch"; let description = [{ The `cir.indirectbr` operation represents an indirect branch to one of @@ -2353,12 +2248,9 @@ def CIR_IndirectBrOp : CIR_Op<"indirectbr", [ ``` }]; - let arguments = (ins - CIR_VoidPtrType:$addr, - UnitAttr:$poison, - VariadicOfVariadic:$succOperands, - DenseI32ArrayAttr:$indbr_operand_segments - ); + let arguments = (ins CIR_VoidPtrType:$addr, UnitAttr:$poison, + VariadicOfVariadic:$succOperands, + DenseI32ArrayAttr:$indbr_operand_segments); let successors = (successor VariadicSuccessor:$successors); let assemblyFormat = [{ @@ -2375,26 +2267,28 @@ def CIR_IndirectBrOp : CIR_Op<"indirectbr", [ // While & DoWhileOp //===----------------------------------------------------------------------===// -class CIR_WhileOpBase : CIR_Op { +class CIR_WhileOpBase + : CIR_Op { defvar isWhile = !eq(mnemonic, "while"); - let summary = "C/C++ " # !if(isWhile, "while", "do-while") # " loop"; - let builders = [ - OpBuilder<(ins "llvm::function_ref":$condBuilder, - "llvm::function_ref":$bodyBuilder), [{ + let summary = "C/C++ "#!if(isWhile, "while", "do-while")#" loop"; + let builders = [OpBuilder<(ins "llvm::function_ref":$condBuilder, + "llvm::function_ref":$bodyBuilder), + [{ mlir::OpBuilder::InsertionGuard guard($_builder); $_builder.createBlock($_state.addRegion()); - }] # !if(isWhile, [{ + }]#!if(isWhile, [{ condBuilder($_builder, $_state.location); $_builder.createBlock($_state.addRegion()); bodyBuilder($_builder, $_state.location); - }], [{ + }], + [{ bodyBuilder($_builder, $_state.location); $_builder.createBlock($_state.addRegion()); condBuilder($_builder, $_state.location); - }])> - ]; + }])>]; } def CIR_WhileOp : CIR_WhileOpBase<"while"> { @@ -2452,7 +2346,8 @@ def CIR_DoWhileOp : CIR_WhileOpBase<"do"> { // ForOp //===----------------------------------------------------------------------===// -def CIR_ForOp : CIR_Op<"for", [CIR_LoopOpInterface, CIR_Breakable, NoRegionArguments]> { +def CIR_ForOp + : CIR_Op<"for", [CIR_LoopOpInterface, CIR_Breakable, NoRegionArguments]> { let summary = "C/C++ for loop counterpart"; let description = [{ Represents a C/C++ for loop. It consists of three regions: @@ -2477,9 +2372,8 @@ def CIR_ForOp : CIR_Op<"for", [CIR_LoopOpInterface, CIR_Breakable, NoRegionArgum ``` }]; - let regions = (region SizedRegion<1>:$cond, - MinSizedRegion<1>:$body, - SizedRegion<1>:$step); + let regions = (region SizedRegion<1>:$cond, MinSizedRegion<1>:$body, + SizedRegion<1>:$step); let assemblyFormat = [{ `:` `cond` $cond `body` $body @@ -2487,10 +2381,13 @@ def CIR_ForOp : CIR_Op<"for", [CIR_LoopOpInterface, CIR_Breakable, NoRegionArgum attr-dict }]; - let builders = [ - OpBuilder<(ins "llvm::function_ref":$condBuilder, - "llvm::function_ref":$bodyBuilder, - "llvm::function_ref":$stepBuilder), [{ + let builders = [OpBuilder<(ins "llvm::function_ref":$condBuilder, + "llvm::function_ref":$bodyBuilder, + "llvm::function_ref":$stepBuilder), + [{ mlir::OpBuilder::InsertionGuard guard($_builder); // Build condition region. @@ -2504,8 +2401,7 @@ def CIR_ForOp : CIR_Op<"for", [CIR_LoopOpInterface, CIR_Breakable, NoRegionArgum // Build step region. $_builder.createBlock($_state.addRegion()); stepBuilder($_builder, $_state.location); - }]> - ]; + }]>]; let extraClassDeclaration = [{ mlir::Region *maybeGetStep() { return &getStep(); } @@ -2524,58 +2420,58 @@ def CIR_ForOp : CIR_Op<"for", [CIR_LoopOpInterface, CIR_Breakable, NoRegionArgum // lowering, specially useful for C++ support. /// An enumeration for the kinds of linkage for global values. -def CIR_GlobalLinkageKind : CIR_I32EnumAttr< - "GlobalLinkageKind", "linkage kind", [ - // Externally visible function - I32EnumAttrCase<"ExternalLinkage", 0, "external">, - // Available for inspection, not emission. - I32EnumAttrCase<"AvailableExternallyLinkage", 1, "available_externally">, - // Keep one copy of function when linking (inline) - I32EnumAttrCase<"LinkOnceAnyLinkage", 2, "linkonce">, - // Same, but only replaced by something equivalent. - I32EnumAttrCase<"LinkOnceODRLinkage", 3, "linkonce_odr">, - // Keep one copy of named function when linking (weak) - I32EnumAttrCase<"WeakAnyLinkage", 4, "weak">, - // Same, but only replaced by something equivalent. - I32EnumAttrCase<"WeakODRLinkage", 5, "weak_odr">, - // TODO: should we add something like appending linkage too? - // Special purpose, only applies to global arrays - // I32EnumAttrCase<"AppendingLinkage", 6, "appending">, - // Rename collisions when linking (static functions). - I32EnumAttrCase<"InternalLinkage", 7, "internal">, - // Like Internal, but omit from symbol table, prefix it with - // "cir_" to prevent clash with MLIR's symbol "private". - I32EnumAttrCase<"PrivateLinkage", 8, "cir_private">, - // ExternalWeak linkage description. - I32EnumAttrCase<"ExternalWeakLinkage", 9, "extern_weak">, - // Tentative definitions. - I32EnumAttrCase<"CommonLinkage", 10, "common"> -]>; - -def CIR_SignedOverflowBehavior : CIR_I32EnumAttr< - "SignedOverflowBehavior", "behavior for signed overflow", [ - I32EnumAttrCase<"Undefined", 0, "undefined">, - I32EnumAttrCase<"Defined", 1, "defined">, - I32EnumAttrCase<"Trapping", 2, "trapping"> -]> { +def CIR_GlobalLinkageKind + : CIR_I32EnumAttr< + "GlobalLinkageKind", "linkage kind", + [ + // Externally visible function + I32EnumAttrCase<"ExternalLinkage", 0, "external">, + // Available for inspection, not emission. + I32EnumAttrCase<"AvailableExternallyLinkage", 1, + "available_externally">, + // Keep one copy of function when linking (inline) + I32EnumAttrCase<"LinkOnceAnyLinkage", 2, "linkonce">, + // Same, but only replaced by something equivalent. + I32EnumAttrCase<"LinkOnceODRLinkage", 3, "linkonce_odr">, + // Keep one copy of named function when linking (weak) + I32EnumAttrCase<"WeakAnyLinkage", 4, "weak">, + // Same, but only replaced by something equivalent. + I32EnumAttrCase<"WeakODRLinkage", 5, "weak_odr">, + // TODO: should we add something like appending linkage too? + // Special purpose, only applies to global arrays + // I32EnumAttrCase<"AppendingLinkage", 6, "appending">, + // Rename collisions when linking (static functions). + I32EnumAttrCase<"InternalLinkage", 7, "internal">, + // Like Internal, but omit from symbol table, prefix it with + // "cir_" to prevent clash with MLIR's symbol "private". + I32EnumAttrCase<"PrivateLinkage", 8, "cir_private">, + // ExternalWeak linkage description. + I32EnumAttrCase<"ExternalWeakLinkage", 9, "extern_weak">, + // Tentative definitions. + I32EnumAttrCase<"CommonLinkage", 10, "common">]>; + +def CIR_SignedOverflowBehavior + : CIR_I32EnumAttr<"SignedOverflowBehavior", "behavior for signed overflow", + [I32EnumAttrCase<"Undefined", 0, "undefined">, + I32EnumAttrCase<"Defined", 1, "defined">, + I32EnumAttrCase<"Trapping", 2, "trapping">]> { let genSpecializedAttr = 0; } -def CIR_SignedOverflowBehaviorAttr : CIR_EnumAttr< - CIR_SignedOverflowBehavior, "signed_overflow_behavior">; +def CIR_SignedOverflowBehaviorAttr + : CIR_EnumAttr; -def CIR_TLSModel : CIR_I32EnumAttr<"TLS_Model", "TLS model", [ - I32EnumAttrCase<"GeneralDynamic", 0, "tls_dyn">, - I32EnumAttrCase<"LocalDynamic", 1, "tls_local_dyn">, - I32EnumAttrCase<"InitialExec", 2, "tls_init_exec">, - I32EnumAttrCase<"LocalExec", 3, "tls_local_exec"> -]>; +def CIR_TLSModel + : CIR_I32EnumAttr<"TLS_Model", "TLS model", + [I32EnumAttrCase<"GeneralDynamic", 0, "tls_dyn">, + I32EnumAttrCase<"LocalDynamic", 1, "tls_local_dyn">, + I32EnumAttrCase<"InitialExec", 2, "tls_init_exec">, + I32EnumAttrCase<"LocalExec", 3, "tls_local_exec">]>; -def CIR_GlobalOp : CIR_Op<"global", [ - DeclareOpInterfaceMethods, - DeclareOpInterfaceMethods, - NoRegionArguments -]> { +def CIR_GlobalOp + : CIR_Op<"global", [DeclareOpInterfaceMethods, + DeclareOpInterfaceMethods, + NoRegionArguments]> { let summary = "Declares or defines a global variable"; let description = [{ The `cir.global` operation declares or defines a named global variable. @@ -2607,30 +2503,19 @@ def CIR_GlobalOp : CIR_Op<"global", [ // Note that both sym_name and sym_visibility are tied to Symbol trait. // TODO: sym_visibility can possibly be represented by implementing the // necessary Symbol's interface in terms of linkage instead. - let arguments = (ins - SymbolNameAttr:$sym_name, - DefaultValuedAttr< - CIR_VisibilityAttr, - "VisibilityKind::Default" - >:$global_visibility, - OptionalAttr:$sym_visibility, - TypeAttr:$sym_type, - CIR_GlobalLinkageKind:$linkage, - DefaultValuedAttr< - CIR_AddressSpaceAttr, - "AddressSpace::Default" - >:$addr_space, - OptionalAttr:$tls_model, - // Note this can also be a FlatSymbolRefAttr - OptionalAttr:$initial_value, - UnitAttr:$comdat, - UnitAttr:$constant, - UnitAttr:$dso_local, - OptionalAttr:$alignment, - OptionalAttr:$ast, - OptionalAttr:$section, - OptionalAttr:$annotations - ); + let arguments = (ins SymbolNameAttr:$sym_name, + DefaultValuedAttr:$global_visibility, + OptionalAttr:$sym_visibility, TypeAttr:$sym_type, + CIR_GlobalLinkageKind:$linkage, + DefaultValuedAttr:$addr_space, + OptionalAttr:$tls_model, + // Note this can also be a FlatSymbolRefAttr + OptionalAttr:$initial_value, UnitAttr:$comdat, + UnitAttr:$constant, UnitAttr:$dso_local, OptionalAttr:$alignment, + OptionalAttr:$ast, OptionalAttr:$section, + OptionalAttr:$annotations); let regions = (region AnyRegion:$ctorRegion, AnyRegion:$dtorRegion); @@ -2657,22 +2542,18 @@ def CIR_GlobalOp : CIR_Op<"global", [ }]; let skipDefaultBuilders = 1; - let builders = [ - OpBuilder<(ins + let builders = [OpBuilder<(ins // MLIR's default visibility is public. "llvm::StringRef":$sym_name, - "mlir::Type":$sym_type, - CArg<"bool", "false">:$isConstant, + "mlir::Type":$sym_type, CArg<"bool", "false">:$isConstant, // CIR defaults to external linkage. CArg<"cir::GlobalLinkageKind", - "cir::GlobalLinkageKind::ExternalLinkage">:$linkage, + "cir::GlobalLinkageKind::ExternalLinkage">:$linkage, CArg<"cir::AddressSpace", "cir::AddressSpace::Default">:$addrSpace, CArg<"llvm::function_ref", "nullptr">:$ctorBuilder, CArg<"llvm::function_ref", - "nullptr">:$dtorBuilder) - > - ]; + "nullptr">:$dtorBuilder)>]; let hasVerifier = 1; } @@ -2681,9 +2562,9 @@ def CIR_GlobalOp : CIR_Op<"global", [ // GetGlobalOp //===----------------------------------------------------------------------===// -def CIR_GetGlobalOp : CIR_Op<"get_global", [ - Pure, DeclareOpInterfaceMethods -]> { +def CIR_GetGlobalOp + : CIR_Op<"get_global", [Pure, + DeclareOpInterfaceMethods]> { let summary = "Get the address of a global variable"; let description = [{ The `cir.get_global` operation retrieves the address pointing to a @@ -2715,13 +2596,80 @@ def CIR_GetGlobalOp : CIR_Op<"get_global", [ }]; } +//===----------------------------------------------------------------------===// +// GuardedInitOp +//===----------------------------------------------------------------------===// + +def CIR_GuardedInitOp : CIR_Op<"guarded.init"> { + let summary = "Guarded initialization for static variables with non-trivial " + "initialization/destruction"; + let description = [{ + The `cir.guarded.init` operation represents the guarded initialization pattern + for C++ static local variables that have non-trivial initialization or + destruction. This implements the thread-safe one-time initialization semantics + required by the C++ standard (since C++11). + + The operation takes a guard variable (pointer to a guard global) and a static + variable (the variable being initialized), along with flags indicating whether + the initialization should be thread-safe and whether the initializer should + be executed. + + The `init_region` contains the code that performs the initialization. This + region is executed only once, on the first time the static variable is + encountered. The guard variable is used to track whether initialization has + occurred. + + The `thread_safe` attribute indicates whether thread-safe initialization is + required (i.e., using __cxa_guard_acquire/release). When false, a simple + check-and-set pattern is used. + + The `perform_init` attribute indicates whether the initialization code should + be executed. When true, the init_region contains the constructor call. When + false, only the destructor registration is performed (for variables with + constant initializers but non-trivial destructors). + + Example with non-constant initializer: + ```mlir + cir.guarded.init(%guard, %var) thread_safe perform_init { + // Call constructor + cir.call @_ZN1aC1Ev(%var) : (!cir.ptr) -> () + cir.yield + } + ``` + + Example with constant initializer but non-trivial destructor: + ```mlir + cir.guarded.init(%guard, %var) thread_safe { + // Destructor registration happens implicitly via GlobalOp's dtorRegion + cir.yield + } + ``` + }]; + + let arguments = (ins CIR_PointerType:$guard_var, + FlatSymbolRefAttr:$static_var, UnitAttr:$thread_safe, + UnitAttr:$perform_init, UnitAttr:$is_local_var); + + let regions = (region SizedRegion<1>:$init_region); + + let assemblyFormat = [{ + `(` $guard_var `,` $static_var `)` + (`thread_safe` $thread_safe^)? + (`perform_init` $perform_init^)? + (`local` $is_local_var^)? + $init_region attr-dict `:` qualified(type($guard_var)) + }]; + + let hasVerifier = 1; +} + //===----------------------------------------------------------------------===// // VTableAddrPointOp //===----------------------------------------------------------------------===// -def CIR_VTableAddrPointOp : CIR_Op<"vtable.address_point", [ - Pure, DeclareOpInterfaceMethods -]> { +def CIR_VTableAddrPointOp + : CIR_Op<"vtable.address_point", [Pure, DeclareOpInterfaceMethods< + SymbolUserOpInterface>]> { let summary = "Get the vtable (global variable) address point"; let description = [{ The `vtable.address_point` operation retrieves the "effective" address @@ -2785,10 +2733,8 @@ def CIR_VTableAddrPointOp : CIR_Op<"vtable.address_point", [ ``` }]; - let arguments = (ins - FlatSymbolRefAttr:$name, - CIR_AddressPointAttr:$address_point - ); + let arguments = (ins FlatSymbolRefAttr:$name, + CIR_AddressPointAttr:$address_point); let results = (outs Res:$addr); @@ -2854,25 +2800,22 @@ def CIR_VTableGetVPtrOp : CIR_Op<"vtable.get_vptr", [Pure]> { ``` }]; - let arguments = (ins - Arg:$src - ); + let arguments = + (ins Arg:$src); let results = (outs CIR_PtrToVPtr:$result); let assemblyFormat = [{ $src `:` qualified(type($src)) `->` qualified(type($result)) attr-dict }]; - } //===----------------------------------------------------------------------===// // VTableGetVirtualFnAddrOp //===----------------------------------------------------------------------===// -def CIR_VTableGetVirtualFnAddrOp : CIR_Op<"vtable.get_virtual_fn_addr", [ - Pure -]> { +def CIR_VTableGetVirtualFnAddrOp + : CIR_Op<"vtable.get_virtual_fn_addr", [Pure]> { let summary = "Get a the address of a virtual function pointer"; let description = [{ The `vtable.get_virtual_fn_addr` operation retrieves the address of a @@ -2981,9 +2924,8 @@ def CIR_VTableGetVirtualFnAddrOp : CIR_Op<"vtable.get_virtual_fn_addr", [ ``` }]; - let arguments = (ins - Arg:$vptr, - I64Attr:$index); + let arguments = (ins Arg:$vptr, + I64Attr:$index); let results = (outs CIR_PointerType:$result); @@ -2997,9 +2939,9 @@ def CIR_VTableGetVirtualFnAddrOp : CIR_Op<"vtable.get_virtual_fn_addr", [ // VTTAddrPointOp //===----------------------------------------------------------------------===// -def CIR_VTTAddrPointOp : CIR_Op<"vtt.address_point", [ - Pure, DeclareOpInterfaceMethods -]> { +def CIR_VTTAddrPointOp + : CIR_Op<"vtt.address_point", [Pure, DeclareOpInterfaceMethods< + SymbolUserOpInterface>]> { let summary = "Get the VTT address point"; let description = [{ The `vtt.address_point` operation retrieves an element from the VTT, @@ -3038,8 +2980,7 @@ def CIR_VTTAddrPointOp : CIR_Op<"vtt.address_point", [ }]; let arguments = (ins OptionalAttr:$name, - Optional:$sym_addr, - I32Attr:$offset); + Optional:$sym_addr, I32Attr:$offset); let results = (outs CIR_PointerType:$addr); let assemblyFormat = [{ @@ -3101,13 +3042,11 @@ def CIR_SetBitfieldOp : CIR_Op<"set_bitfield"> { ``` }]; - let arguments = (ins - Arg:$addr, - CIR_AnyType:$src, - CIR_BitfieldInfoAttr:$bitfield_info, - DefaultValuedOptionalAttr:$alignment, - UnitAttr:$is_volatile - ); + let arguments = (ins Arg:$addr, + CIR_AnyType:$src, CIR_BitfieldInfoAttr:$bitfield_info, + DefaultValuedOptionalAttr:$alignment, + UnitAttr:$is_volatile); let results = (outs CIR_IntType:$result); @@ -3116,26 +3055,18 @@ def CIR_SetBitfieldOp : CIR_Op<"set_bitfield"> { `(`$bitfield_info`,` $addr`:`qualified(type($addr))`,` $src`:`type($src) `)` attr-dict `->` type($result) }]; - let builders = [ - OpBuilder<(ins "mlir::Type":$type, - "mlir::Value":$addr, - "mlir::Type":$storage_type, - "mlir::Value":$src, - "llvm::StringRef":$name, - "unsigned":$size, - "unsigned":$offset, - "bool":$is_signed, - "bool":$is_volatile, - CArg<"unsigned", "0">:$alignment - ), - [{ + let builders = [OpBuilder< + (ins "mlir::Type":$type, "mlir::Value":$addr, "mlir::Type":$storage_type, + "mlir::Value":$src, "llvm::StringRef":$name, "unsigned":$size, + "unsigned":$offset, "bool":$is_signed, "bool":$is_volatile, + CArg<"unsigned", "0">:$alignment), + [{ BitfieldInfoAttr info = BitfieldInfoAttr::get($_builder.getContext(), name, storage_type, size, offset, is_signed); build($_builder, $_state, type, addr, src, info, alignment, is_volatile); - }]> - ]; + }]>]; } //===----------------------------------------------------------------------===// @@ -3184,12 +3115,11 @@ def CIR_GetBitfieldOp : CIR_Op<"get_bitfield"> { ``` }]; - let arguments = (ins - Arg:$addr, - CIR_BitfieldInfoAttr:$bitfield_info, - DefaultValuedOptionalAttr:$alignment, - UnitAttr:$is_volatile - ); + let arguments = + (ins Arg:$addr, + CIR_BitfieldInfoAttr:$bitfield_info, + DefaultValuedOptionalAttr:$alignment, + UnitAttr:$is_volatile); let results = (outs CIR_IntType:$result); @@ -3198,25 +3128,18 @@ def CIR_GetBitfieldOp : CIR_Op<"get_bitfield"> { `(`$bitfield_info `,` $addr attr-dict `:` qualified(type($addr)) `)` `->` type($result) }]; - let builders = [ - OpBuilder<(ins "mlir::Type":$type, - "mlir::Value":$addr, - "mlir::Type":$storage_type, - "llvm::StringRef":$name, - "unsigned":$size, - "unsigned":$offset, - "bool":$is_signed, - "bool":$is_volatile, - CArg<"unsigned", "0">:$alignment - ), - [{ + let builders = [OpBuilder< + (ins "mlir::Type":$type, "mlir::Value":$addr, "mlir::Type":$storage_type, + "llvm::StringRef":$name, "unsigned":$size, "unsigned":$offset, + "bool":$is_signed, "bool":$is_volatile, + CArg<"unsigned", "0">:$alignment), + [{ BitfieldInfoAttr info = BitfieldInfoAttr::get($_builder.getContext(), name, storage_type, size, offset, is_signed); build($_builder, $_state, type, addr, info, alignment, is_volatile); - }]> - ]; + }]>]; } //===----------------------------------------------------------------------===// @@ -3244,10 +3167,9 @@ def CIR_GetMemberOp : CIR_Op<"get_member"> { ``` }]; - let arguments = (ins - Arg:$addr, - StrAttr:$name, - I64Attr:$index); + let arguments = + (ins Arg:$addr, + StrAttr:$name, I64Attr:$index); let results = (outs Res:$result); @@ -3303,13 +3225,11 @@ def CIR_ExtractMemberOp : CIR_Op<"extract_member", [Pure]> { `:` qualified(type($record)) `->` qualified(type($result)) }]; - let builders = [ - OpBuilder<(ins "mlir::Value":$record, "uint64_t":$index), [{ + let builders = [OpBuilder<(ins "mlir::Value":$record, "uint64_t":$index), [{ auto recordTy = mlir::cast(record.getType()); mlir::Type memberTy = recordTy.getMembers()[index]; build($_builder, $_state, memberTy, record, index); - }]> - ]; + }]>]; let hasVerifier = 1; } @@ -3318,9 +3238,8 @@ def CIR_ExtractMemberOp : CIR_Op<"extract_member", [Pure]> { // InsertMemberOp //===----------------------------------------------------------------------===// -def CIR_InsertMemberOp : CIR_Op<"insert_member", [ - Pure, AllTypesMatch<["record", "result"]> -]> { +def CIR_InsertMemberOp + : CIR_Op<"insert_member", [Pure, AllTypesMatch<["record", "result"]>]> { let summary = "Overwrite the value of a member of a record value"; let description = [{ The `cir.insert_member` operation overwrites the value of a particular @@ -3352,7 +3271,7 @@ def CIR_InsertMemberOp : CIR_Op<"insert_member", [ }]; let arguments = (ins CIRRecordType:$record, I64Attr:$index, - CIR_AnyType:$value); + CIR_AnyType:$value); let results = (outs CIRRecordType:$result); let assemblyFormat = [{ @@ -3406,9 +3325,9 @@ def CIR_GetRuntimeMemberOp : CIR_Op<"get_runtime_member"> { to the target member. }]; - let arguments = (ins - Arg:$addr, - Arg:$member); + let arguments = (ins Arg:$addr, + Arg:$member); let results = (outs Res:$result); @@ -3501,10 +3420,9 @@ def CIR_GetElementOp : CIR_Op<"get_element"> { ``` }]; - let arguments = (ins - Arg:$base, - Arg:$index - ); + let arguments = + (ins Arg:$base, + Arg:$index); let results = (outs CIR_PointerType:$result); @@ -3530,12 +3448,13 @@ def CIR_GetElementOp : CIR_Op<"get_element"> { // VecInsertOp //===----------------------------------------------------------------------===// -def CIR_VecInsertOp : CIR_Op<"vec.insert", [ - Pure, - TypesMatchWith<"argument type matches vector element type", - "vec", "value", "mlir::cast($_self).getElementType()">, - AllTypesMatch<["result", "vec"]> -]> { +def CIR_VecInsertOp + : CIR_Op<"vec.insert", + [Pure, + TypesMatchWith< + "argument type matches vector element type", "vec", "value", + "mlir::cast($_self).getElementType()">, + AllTypesMatch<["result", "vec"]>]> { let summary = "Insert one element into a vector object"; let description = [{ The `cir.vec.insert` operation replaces the element of the given vector at @@ -3543,11 +3462,8 @@ def CIR_VecInsertOp : CIR_Op<"vec.insert", [ element is returned. }]; - let arguments = (ins - CIR_VectorType:$vec, - CIR_VectorElementType:$value, - CIR_AnyFundamentalIntType:$index - ); + let arguments = (ins CIR_VectorType:$vec, CIR_VectorElementType:$value, + CIR_AnyFundamentalIntType:$index); let results = (outs CIR_VectorType:$result); @@ -3563,21 +3479,20 @@ def CIR_VecInsertOp : CIR_Op<"vec.insert", [ // VecExtractOp //===----------------------------------------------------------------------===// -def CIR_VecExtractOp : CIR_Op<"vec.extract", [ - Pure, - TypesMatchWith<"type of 'result' matches element type of 'vec'", - "vec", "result", "mlir::cast($_self).getElementType()"> -]> { +def CIR_VecExtractOp + : CIR_Op<"vec.extract", + [Pure, + TypesMatchWith< + "type of 'result' matches element type of 'vec'", "vec", + "result", + "mlir::cast($_self).getElementType()">]> { let summary = "Extract one element from a vector object"; let description = [{ The `cir.vec.extract` operation extracts the element at the given index from a vector object. }]; - let arguments = (ins - CIR_VectorType:$vec, - CIR_AnyFundamentalIntType:$index - ); + let arguments = (ins CIR_VectorType:$vec, CIR_AnyFundamentalIntType:$index); let results = (outs CIR_VectorElementType:$result); @@ -3622,11 +3537,13 @@ def CIR_VecCreateOp : CIR_Op<"vec.create", [Pure]> { // analysis passes can benefit from knowing that all elements of the vector // have the same value. -def CIR_VecSplatOp : CIR_Op<"vec.splat", [ - Pure, - TypesMatchWith<"type of 'value' matches element type of 'result'", - "result", "value", "mlir::cast($_self).getElementType()"> -]> { +def CIR_VecSplatOp + : CIR_Op<"vec.splat", + [Pure, + TypesMatchWith< + "type of 'value' matches element type of 'result'", "result", + "value", + "mlir::cast($_self).getElementType()">]> { let summary = "Convert a scalar into a vector"; let description = [{ The `cir.vec.splat` operation creates a vector value from a scalar value. @@ -3654,11 +3571,8 @@ def CIR_VecCmpOp : CIR_Op<"vec.cmp", [Pure, SameTypeOperands]> { element type of the operands. The values in the result are 0 or -1. }]; - let arguments = (ins - CIR_CmpOpKind:$kind, - CIR_VectorType:$lhs, - CIR_VectorType:$rhs - ); + let arguments = (ins CIR_CmpOpKind:$kind, CIR_VectorType:$lhs, + CIR_VectorType:$rhs); let results = (outs CIR_VectorType:$result); @@ -3674,9 +3588,8 @@ def CIR_VecCmpOp : CIR_Op<"vec.cmp", [Pure, SameTypeOperands]> { // VecTernary //===----------------------------------------------------------------------===// -def CIR_VecTernaryOp : CIR_Op<"vec.ternary", [ - Pure, AllTypesMatch<["result", "lhs", "rhs"]> -]> { +def CIR_VecTernaryOp + : CIR_Op<"vec.ternary", [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, @@ -3693,11 +3606,8 @@ def CIR_VecTernaryOp : CIR_Op<"vec.ternary", [ Each element of the result is `(bool)a[n] ? b[n] : c[n]`. }]; - let arguments = (ins - CIR_VectorOfIntType:$cond, - CIR_VectorType:$lhs, - CIR_VectorType:$rhs - ); + let arguments = (ins CIR_VectorOfIntType:$cond, CIR_VectorType:$lhs, + CIR_VectorType:$rhs); let results = (outs CIR_VectorType:$result); let assemblyFormat = [{ @@ -3717,9 +3627,8 @@ def CIR_VecTernaryOp : CIR_Op<"vec.ternary", [ // implement. This could be useful for passes that don't care how the vector // shuffle was specified. -def CIR_VecShuffleOp : CIR_Op<"vec.shuffle", [ - Pure, AllTypesMatch<["vec1", "vec2"]> -]> { +def CIR_VecShuffleOp + : CIR_Op<"vec.shuffle", [Pure, AllTypesMatch<["vec1", "vec2"]>]> { let summary = "Combine two vectors using indices passed as constant integers"; let description = [{ The `cir.vec.shuffle` operation implements the documented form of Clang's @@ -3737,7 +3646,7 @@ def CIR_VecShuffleOp : CIR_Op<"vec.shuffle", [ concatenated vector. }]; let arguments = (ins CIR_VectorType:$vec1, CIR_VectorType:$vec2, - ArrayAttr:$indices); + ArrayAttr:$indices); let results = (outs CIR_VectorType:$result); let assemblyFormat = [{ `(` $vec1 `,` $vec2 `:` qualified(type($vec1)) `)` $indices `:` @@ -3752,9 +3661,8 @@ def CIR_VecShuffleOp : CIR_Op<"vec.shuffle", [ // VecShuffleDynamic //===----------------------------------------------------------------------===// -def CIR_VecShuffleDynamicOp : CIR_Op<"vec.shuffle.dynamic", [ - Pure, AllTypesMatch<["vec", "result"]> -]> { +def CIR_VecShuffleDynamicOp + : CIR_Op<"vec.shuffle.dynamic", [Pure, AllTypesMatch<["vec", "result"]>]> { let summary = "Shuffle a vector using indices in another vector"; let description = [{ The `cir.vec.shuffle.dynamic` operation implements the undocumented form of @@ -3808,9 +3716,9 @@ def CIR_BaseClassAddrOp : CIR_Op<"base_class_addr"> { // The validity of the relationship of derived and base cannot yet be // verified, currently not worth adding a verifier. - let arguments = (ins - Arg:$derived_addr, - IndexAttr:$offset, UnitAttr:$assume_not_null); + let arguments = (ins Arg:$derived_addr, + IndexAttr:$offset, UnitAttr:$assume_not_null); let results = (outs Res:$base_addr); @@ -3858,9 +3766,9 @@ def CIR_DerivedClassAddrOp : CIR_Op<"derived_class_addr"> { // The validity of the relationship of derived and base cannot yet be // verified, currently not worth adding a verifier. - let arguments = (ins - Arg:$base_addr, - IndexAttr:$offset, UnitAttr:$assume_not_null); + let arguments = + (ins Arg:$base_addr, + IndexAttr:$offset, UnitAttr:$assume_not_null); let results = (outs Res:$derived_addr); @@ -3877,8 +3785,8 @@ def CIR_DerivedClassAddrOp : CIR_Op<"derived_class_addr"> { def CIR_BaseDataMemberOp : CIR_Op<"base_data_member", [Pure]> { let summary = - "Cast a derived class data member pointer to a base class data member " - "pointer"; + "Cast a derived class data member pointer to a base class data member " + "pointer"; let description = [{ The `cir.base_data_member` operation casts a data member pointer of type `T Derived::*` to a data member pointer of type `T Base::*`, where `Base` @@ -3901,8 +3809,8 @@ def CIR_BaseDataMemberOp : CIR_Op<"base_data_member", [Pure]> { def CIR_DerivedDataMemberOp : CIR_Op<"derived_data_member", [Pure]> { let summary = - "Cast a base class data member pointer to a derived class data member " - "pointer"; + "Cast a base class data member pointer to a derived class data member " + "pointer"; let description = [{ The `cir.derived_data_member` operation casts a data member pointer of type `T Base::*` to a data member pointer of type `T Derived::*`, where `Base` @@ -3997,27 +3905,25 @@ def CIR_DerivedMethodOp : CIR_Op<"derived_method", [Pure]> { // The enumeration values are not necessarily in sync with `clang::CallingConv` // or `llvm::CallingConv`. -def CIR_CallingConv : CIR_I32EnumAttr<"CallingConv", "calling convention", [ - I32EnumAttrCase<"C", 1, "c">, - I32EnumAttrCase<"SpirKernel", 2, "spir_kernel">, - I32EnumAttrCase<"SpirFunction", 3, "spir_function">, - I32EnumAttrCase<"OpenCLKernel", 4, "opencl_kernel">, - I32EnumAttrCase<"PTXKernel", 5, "ptx_kernel"> -]>; - -def CIR_OptionalPriorityAttr : OptionalAttr< - DefaultValuedAttr< - ConfinedAttr, IntMaxValue<65535>]>, - "cir::DefaultGlobalCtorDtorPriority" - > ->; - -def FuncOp : CIR_Op<"func", [ - AutomaticAllocationScope, CallableOpInterface, FunctionOpInterface, - DeclareOpInterfaceMethods, - HasAtMostOneOfAttrs<["global_ctor_priority", "global_dtor_priority"]>, - IsolatedFromAbove -]> { +def CIR_CallingConv + : CIR_I32EnumAttr<"CallingConv", "calling convention", + [I32EnumAttrCase<"C", 1, "c">, + I32EnumAttrCase<"SpirKernel", 2, "spir_kernel">, + I32EnumAttrCase<"SpirFunction", 3, "spir_function">, + I32EnumAttrCase<"OpenCLKernel", 4, "opencl_kernel">, + I32EnumAttrCase<"PTXKernel", 5, "ptx_kernel">]>; + +def CIR_OptionalPriorityAttr + : OptionalAttr, IntMaxValue<65535>]>, + "cir::DefaultGlobalCtorDtorPriority">>; + +def FuncOp : CIR_Op<"func", [AutomaticAllocationScope, CallableOpInterface, + FunctionOpInterface, + DeclareOpInterfaceMethods, + HasAtMostOneOfAttrs<["global_ctor_priority", + "global_dtor_priority"]>, + IsolatedFromAbove]> { let summary = "Declare or define a function"; let description = [{ @@ -4094,44 +4000,32 @@ def FuncOp : CIR_Op<"func", [ ``` }]; - let arguments = (ins - SymbolNameAttr:$sym_name, - CIR_VisibilityAttr:$global_visibility, - TypeAttrOf:$function_type, - UnitAttr:$builtin, - UnitAttr:$coroutine, - UnitAttr:$lambda, - UnitAttr:$no_proto, - UnitAttr:$dso_local, - DefaultValuedAttr< - CIR_GlobalLinkageKind, "GlobalLinkageKind::ExternalLinkage" - >:$linkage, - DefaultValuedAttr< - CIR_CallingConv, "CallingConv::C" - >:$calling_conv, - CIR_ExtraFuncAttr:$extra_attrs, - OptionalAttr:$sym_visibility, - UnitAttr:$comdat, - OptionalAttr:$arg_attrs, - OptionalAttr:$res_attrs, - OptionalAttr:$aliasee, - CIR_OptionalPriorityAttr:$global_ctor_priority, - CIR_OptionalPriorityAttr:$global_dtor_priority, - OptionalAttr:$annotations, - OptionalAttr:$cxx_special_member, - OptionalAttr:$ast - ); + let arguments = (ins SymbolNameAttr:$sym_name, + CIR_VisibilityAttr:$global_visibility, + TypeAttrOf:$function_type, UnitAttr:$builtin, + UnitAttr:$coroutine, UnitAttr:$lambda, UnitAttr:$no_proto, + UnitAttr:$dso_local, + DefaultValuedAttr:$linkage, + DefaultValuedAttr:$calling_conv, + CIR_ExtraFuncAttr:$extra_attrs, OptionalAttr:$sym_visibility, + UnitAttr:$comdat, OptionalAttr:$arg_attrs, + OptionalAttr:$res_attrs, + OptionalAttr:$aliasee, + CIR_OptionalPriorityAttr:$global_ctor_priority, + CIR_OptionalPriorityAttr:$global_dtor_priority, + OptionalAttr:$annotations, + OptionalAttr:$cxx_special_member, + OptionalAttr:$ast); let regions = (region AnyRegion:$body); let skipDefaultBuilders = 1; - let builders = [OpBuilder<(ins - "llvm::StringRef":$name, "FuncType":$type, - CArg<"GlobalLinkageKind", "GlobalLinkageKind::ExternalLinkage">:$linkage, - CArg<"CallingConv", "CallingConv::C">:$callingConv, - CArg<"llvm::ArrayRef", "{}">:$attrs, - CArg<"llvm::ArrayRef", "{}">:$argAttrs) - >]; + let builders = [OpBuilder<(ins "llvm::StringRef":$name, "FuncType":$type, + CArg<"GlobalLinkageKind", "GlobalLinkageKind::ExternalLinkage">:$linkage, + CArg<"CallingConv", "CallingConv::C">:$callingConv, + CArg<"llvm::ArrayRef", "{}">:$attrs, + CArg<"llvm::ArrayRef", "{}">:$argAttrs)>]; let extraClassDeclaration = [{ /// Returns the region on the current operation that is callable. This may @@ -4192,8 +4086,7 @@ def CIR_LLVMIntrinsicCallOp : CIR_Op<"llvm.intrinsic"> { }]; let results = (outs Optional:$result); - let arguments = (ins - StrAttr:$intrinsic_name, Variadic:$arg_ops); + let arguments = (ins StrAttr:$intrinsic_name, Variadic:$arg_ops); let skipDefaultBuilders = 1; @@ -4201,25 +4094,24 @@ def CIR_LLVMIntrinsicCallOp : CIR_Op<"llvm.intrinsic"> { $intrinsic_name $arg_ops `:` functional-type($arg_ops, $result) attr-dict }]; - let builders = [ - OpBuilder<(ins "mlir::StringAttr":$intrinsic_name, "mlir::Type":$resType, - CArg<"mlir::ValueRange", "{}">:$operands), [{ + let builders = [OpBuilder<(ins "mlir::StringAttr":$intrinsic_name, + "mlir::Type":$resType, + CArg<"mlir::ValueRange", "{}">:$operands), + [{ $_state.addAttribute("intrinsic_name", intrinsic_name); $_state.addOperands(operands); if (resType) $_state.addTypes(resType); }]>, ]; - } //===----------------------------------------------------------------------===// // InvariantGroupOp //===----------------------------------------------------------------------===// -def CIR_InvariantGroupOp : CIR_Op<"invariant_group", [ - Pure, SameOperandsAndResultType -]> { +def CIR_InvariantGroupOp + : CIR_Op<"invariant_group", [Pure, SameOperandsAndResultType]> { let summary = "Start an invariant group"; let description = [{ The `cir.invariant_group` operation takes a single pointer value as argument @@ -4293,12 +4185,11 @@ def CIR_DeleteArrayOp : CIR_Op<"delete.array"> { // CallOp and TryCallOp //===----------------------------------------------------------------------===// -def CIR_SideEffect : CIR_I32EnumAttr< - "SideEffect", "allowed side effects of a function", [ - I32EnumAttrCase<"All", 0, "all">, - I32EnumAttrCase<"Pure", 1, "pure">, - I32EnumAttrCase<"Const", 2, "const"> -]> { +def CIR_SideEffect + : CIR_I32EnumAttr<"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 @@ -4325,11 +4216,10 @@ def CIR_SideEffect : CIR_I32EnumAttr< } class CIR_CallOp extra_traits = []> - : CIR_Op, - DeclareOpInterfaceMethods - ])> -{ + : CIR_Op, + DeclareOpInterfaceMethods])> { let extraClassDeclaration = [{ /// Get the argument operands to the called function. mlir::OperandRange getArgOperands() { @@ -4372,14 +4262,11 @@ class CIR_CallOp extra_traits = []> let hasCustomAssemblyFormat = 1; let skipDefaultBuilders = 1; - dag commonArgs = (ins - OptionalAttr:$callee, - Variadic:$arg_ops, - DefaultValuedAttr:$calling_conv, - DefaultValuedAttr:$side_effect, - CIR_ExtraFuncAttr:$extra_attrs, - OptionalAttr:$ast - ); + dag commonArgs = (ins OptionalAttr:$callee, + Variadic:$arg_ops, + DefaultValuedAttr:$calling_conv, + DefaultValuedAttr:$side_effect, + CIR_ExtraFuncAttr:$extra_attrs, OptionalAttr:$ast); } def CIR_CallOp : CIR_CallOp<"call", [NoRegionArguments]> { @@ -4418,19 +4305,18 @@ def CIR_CallOp : CIR_CallOp<"call", [NoRegionArguments]> { }]; let results = (outs Optional:$result); - let arguments = !con((ins - UnitAttr:$exception - ), commonArgs); + let arguments = !con((ins UnitAttr:$exception), commonArgs); let regions = (region AnyRegion:$cleanup); let skipDefaultBuilders = 1; - let builders = [ - OpBuilder<(ins "mlir::SymbolRefAttr":$callee, "mlir::Type":$resType, - CArg<"mlir::ValueRange", "{}">:$operands, - CArg<"CallingConv", "CallingConv::C">:$callingConv, - CArg<"SideEffect", "SideEffect::All">:$sideEffect, - CArg<"mlir::UnitAttr", "{}">:$exception), [{ + let builders = + [OpBuilder<(ins "mlir::SymbolRefAttr":$callee, "mlir::Type":$resType, + CArg<"mlir::ValueRange", "{}">:$operands, + CArg<"CallingConv", "CallingConv::C">:$callingConv, + CArg<"SideEffect", "SideEffect::All">:$sideEffect, + CArg<"mlir::UnitAttr", "{}">:$exception), + [{ $_state.addOperands(operands); if (callee) $_state.addAttribute("callee", callee); @@ -4445,12 +4331,12 @@ def CIR_CallOp : CIR_CallOp<"call", [NoRegionArguments]> { // Create region placeholder for potential cleanups. $_state.addRegion(); }]>, - OpBuilder<(ins "mlir::Value":$ind_target, - "FuncType":$fn_type, - CArg<"mlir::ValueRange", "{}">:$operands, - CArg<"CallingConv", "CallingConv::C">:$callingConv, - CArg<"SideEffect", "SideEffect::All">:$sideEffect, - CArg<"mlir::UnitAttr", "{}">:$exception), [{ + OpBuilder<(ins "mlir::Value":$ind_target, "FuncType":$fn_type, + CArg<"mlir::ValueRange", "{}">:$operands, + CArg<"CallingConv", "CallingConv::C">:$callingConv, + CArg<"SideEffect", "SideEffect::All">:$sideEffect, + CArg<"mlir::UnitAttr", "{}">:$exception), + [{ $_state.addOperands(ValueRange{ind_target}); $_state.addOperands(operands); if (!fn_type.hasVoidReturn()) @@ -4463,14 +4349,12 @@ def CIR_CallOp : CIR_CallOp<"call", [NoRegionArguments]> { $_state.addAttribute("exception", exception); // Create region placeholder for potential cleanups. $_state.addRegion(); - }]> - ]; + }]>]; } -def CIR_TryCallOp : CIR_CallOp<"try_call",[ - DeclareOpInterfaceMethods, - Terminator, AttrSizedOperandSegments -]> { +def CIR_TryCallOp + : CIR_CallOp<"try_call", [DeclareOpInterfaceMethods, + Terminator, AttrSizedOperandSegments]> { let summary = "try_call operation"; let description = [{ Mostly similar to cir.call but requires two destination @@ -4485,25 +4369,24 @@ def CIR_TryCallOp : CIR_CallOp<"try_call",[ ``` }]; - let arguments = !con((ins - Variadic:$contOperands, - Variadic:$landingPadOperands - ), commonArgs); + let arguments = !con((ins Variadic:$contOperands, + Variadic:$landingPadOperands), + commonArgs); let results = (outs Optional:$result); - let successors = (successor AnySuccessor:$cont, - AnySuccessor:$landing_pad); + let successors = (successor AnySuccessor:$cont, AnySuccessor:$landing_pad); let skipDefaultBuilders = 1; - let builders = [ - OpBuilder<(ins "mlir::SymbolRefAttr":$callee, "mlir::Type":$resType, - "mlir::Block *":$cont, "mlir::Block *":$landing_pad, - CArg<"mlir::ValueRange", "{}">:$operands, - CArg<"mlir::ValueRange", "{}">:$contOperands, - CArg<"mlir::ValueRange", "{}">:$landingPadOperands, - CArg<"CallingConv", "CallingConv::C">:$callingConv, - CArg<"SideEffect", "SideEffect::All">:$sideEffect), [{ + let builders = + [OpBuilder<(ins "mlir::SymbolRefAttr":$callee, "mlir::Type":$resType, + "mlir::Block *":$cont, "mlir::Block *":$landing_pad, + CArg<"mlir::ValueRange", "{}">:$operands, + CArg<"mlir::ValueRange", "{}">:$contOperands, + CArg<"mlir::ValueRange", "{}">:$landingPadOperands, + CArg<"CallingConv", "CallingConv::C">:$callingConv, + CArg<"SideEffect", "SideEffect::All">:$sideEffect), + [{ $_state.addOperands(operands); if (callee) $_state.addAttribute("callee", callee); @@ -4528,14 +4411,14 @@ def CIR_TryCallOp : CIR_CallOp<"try_call",[ $_state.addSuccessors(cont); $_state.addSuccessors(landing_pad); }]>, - OpBuilder<(ins "mlir::Value":$ind_target, - "FuncType":$fn_type, - "mlir::Block *":$cont, "mlir::Block *":$landing_pad, - CArg<"mlir::ValueRange", "{}">:$operands, - CArg<"mlir::ValueRange", "{}">:$contOperands, - CArg<"mlir::ValueRange", "{}">:$landingPadOperands, - CArg<"CallingConv", "CallingConv::C">:$callingConv, - CArg<"SideEffect", "SideEffect::All">:$sideEffect), [{ + OpBuilder<(ins "mlir::Value":$ind_target, "FuncType":$fn_type, + "mlir::Block *":$cont, "mlir::Block *":$landing_pad, + CArg<"mlir::ValueRange", "{}">:$operands, + CArg<"mlir::ValueRange", "{}">:$contOperands, + CArg<"mlir::ValueRange", "{}">:$landingPadOperands, + CArg<"CallingConv", "CallingConv::C">:$callingConv, + CArg<"SideEffect", "SideEffect::All">:$sideEffect), + [{ ::llvm::SmallVector finalCallOperands({ind_target}); finalCallOperands.append(operands.begin(), operands.end()); $_state.addOperands(finalCallOperands); @@ -4560,25 +4443,22 @@ def CIR_TryCallOp : CIR_CallOp<"try_call",[ odsState.getOrAddProperties().operandSegmentSizes.begin()); $_state.addSuccessors(cont); $_state.addSuccessors(landing_pad); - }]> - ]; + }]>]; } //===----------------------------------------------------------------------===// // AwaitOp //===----------------------------------------------------------------------===// -def CIR_AwaitKind : CIR_I32EnumAttr<"AwaitKind", "await kind", [ - I32EnumAttrCase<"Init", 0, "init">, - I32EnumAttrCase<"User", 1, "user">, - I32EnumAttrCase<"Yield", 2, "yield">, - I32EnumAttrCase<"Final", 3, "final"> -]>; +def CIR_AwaitKind : CIR_I32EnumAttr<"AwaitKind", "await kind", + [I32EnumAttrCase<"Init", 0, "init">, + I32EnumAttrCase<"User", 1, "user">, + I32EnumAttrCase<"Yield", 2, "yield">, + I32EnumAttrCase<"Final", 3, "final">]>; -def CIR_AwaitOp : CIR_Op<"await",[ - DeclareOpInterfaceMethods, - RecursivelySpeculatable, NoRegionArguments -]> { +def CIR_AwaitOp + : CIR_Op<"await", [DeclareOpInterfaceMethods, + RecursivelySpeculatable, NoRegionArguments]> { let summary = "Wraps C++ co_await implicit logic"; let description = [{ The under the hood effect of using C++ `co_await expr` roughly @@ -4632,9 +4512,8 @@ def CIR_AwaitOp : CIR_Op<"await",[ }]; let arguments = (ins CIR_AwaitKind:$kind); - let regions = (region SizedRegion<1>:$ready, - SizedRegion<1>:$suspend, - SizedRegion<1>:$resume); + let regions = (region SizedRegion<1>:$ready, SizedRegion<1>:$suspend, + SizedRegion<1>:$resume); let assemblyFormat = [{ `(` $kind `,` `ready` `:` $ready `,` @@ -4645,17 +4524,13 @@ def CIR_AwaitOp : CIR_Op<"await",[ }]; let skipDefaultBuilders = 1; - let builders = [ - OpBuilder<(ins - "cir::AwaitKind":$kind, + let builders = [OpBuilder<(ins "cir::AwaitKind":$kind, CArg<"llvm::function_ref", "nullptr">:$readyBuilder, CArg<"llvm::function_ref", "nullptr">:$suspendBuilder, CArg<"llvm::function_ref", - "nullptr">:$resumeBuilder - )> - ]; + "nullptr">:$resumeBuilder)>]; let hasVerifier = 1; } @@ -4675,10 +4550,10 @@ def CIR_CatchAll : CIR_UnitAttr<"CatchAll", "all"> { let storageType = [{ CatchAllAttr }]; } -def CIR_TryOp : CIR_Op<"try",[ - DeclareOpInterfaceMethods, - RecursivelySpeculatable, AutomaticAllocationScope, NoRegionArguments -]> { +def CIR_TryOp + : CIR_Op<"try", [DeclareOpInterfaceMethods, + RecursivelySpeculatable, AutomaticAllocationScope, + NoRegionArguments]> { let summary = "C++ try block"; let description = [{ ```mlir @@ -4697,9 +4572,9 @@ def CIR_TryOp : CIR_Op<"try",[ }]; let arguments = (ins UnitAttr:$synthetic, UnitAttr:$cleanup, - OptionalAttr:$catch_types); + OptionalAttr:$catch_types); let regions = (region AnyRegion:$try_region, - VariadicRegion:$catch_regions); + VariadicRegion:$catch_regions); let assemblyFormat = [{ (`synthetic` $synthetic^)? @@ -4719,11 +4594,11 @@ def CIR_TryOp : CIR_Op<"try",[ }]; // Everything already covered elsewhere. - let builders = [ - OpBuilder<(ins - "llvm::function_ref":$tryBuilder, - "llvm::function_ref" - :$catchBuilder)>, + let builders = + [OpBuilder<(ins "llvm::function_ref":$tryBuilder, + "llvm::function_ref":$catchBuilder)>, ]; } @@ -4731,11 +4606,11 @@ def CIR_TryOp : CIR_Op<"try",[ // CatchParamOp //===----------------------------------------------------------------------===// -def CIR_CatchParamKind : CIR_I32EnumAttr< - "CatchParamKind", "Designate limits for begin/end of catch param handling", [ - I32EnumAttrCase<"Begin", 0, "begin">, - I32EnumAttrCase<"End", 1, "end"> -]>; +def CIR_CatchParamKind + : CIR_I32EnumAttr<"CatchParamKind", + "Designate limits for begin/end of catch param handling", + [I32EnumAttrCase<"Begin", 0, "begin">, + I32EnumAttrCase<"End", 1, "end">]>; def CIR_CatchParamOp : CIR_Op<"catch_param"> { let summary = "Represents catch clause formal parameter"; @@ -4750,10 +4625,8 @@ def CIR_CatchParamOp : CIR_Op<"catch_param"> { ``` }]; - let arguments = (ins - Optional:$exception_ptr, - OptionalAttr:$kind - ); + let arguments = (ins Optional:$exception_ptr, + OptionalAttr:$kind); let results = (outs Optional:$param); let assemblyFormat = [{ @@ -4791,7 +4664,7 @@ def CIR_EhInflightOp : CIR_Op<"eh.inflight_exception"> { }]; let arguments = (ins UnitAttr:$cleanup, - OptionalAttr:$sym_type_list); + OptionalAttr:$sym_type_list); let results = (outs CIR_VoidPtrType:$exception_ptr, CIR_UInt32:$type_id); let assemblyFormat = [{ (`cleanup` $cleanup^)? @@ -4800,8 +4673,9 @@ def CIR_EhInflightOp : CIR_Op<"eh.inflight_exception"> { }]; } -def CIR_EhTypeIdOp : CIR_Op<"eh.typeid", - [Pure, DeclareOpInterfaceMethods]> { +def CIR_EhTypeIdOp + : CIR_Op<"eh.typeid", [Pure, + DeclareOpInterfaceMethods]> { let summary = "Compute exception type id from it's global type symbol"; let description = [{ Returns the exception type id for a given global symbol representing @@ -4869,14 +4743,12 @@ def CIR_EhLongjmpOp : CIR_Op<"eh.longjmp"> { // CopyOp //===----------------------------------------------------------------------===// -def CIR_CopyOp : CIR_Op<"copy",[ - SameTypeOperands, - DeclareOpInterfaceMethods -]> { +def CIR_CopyOp + : CIR_Op<"copy", [SameTypeOperands, + DeclareOpInterfaceMethods]> { let arguments = (ins Arg:$dst, - Arg:$src, - UnitAttr:$is_volatile, - OptionalAttr:$tbaa); + Arg:$src, UnitAttr:$is_volatile, + OptionalAttr:$tbaa); let summary = "Copies contents from a CIR pointer to another"; let description = [{ Given two CIR pointers, `src` and `dst`, `cir.copy` will copy the memory @@ -4915,13 +4787,10 @@ def CIR_CopyOp : CIR_Op<"copy",[ // MemCpyOp && MemMoveOp //===----------------------------------------------------------------------===// -class CIR_MemOp : CIR_Op -]> { - dag commonArgs = (ins - Arg:$dst, - Arg:$src - ); +class CIR_MemOp + : CIR_Op]> { + dag commonArgs = (ins Arg:$dst, + Arg:$src); } def CIR_MemCpyOp : CIR_MemOp<"libc.memcpy"> { @@ -5037,11 +4906,8 @@ def CIR_MemSetOp : CIR_Op<"libc.memset"> { ``` }]; - let arguments = (ins - Arg:$dst, - CIR_SInt32:$val, - CIR_AnyFundamentalUIntType:$len - ); + let arguments = (ins Arg:$dst, + CIR_SInt32:$val, CIR_AnyFundamentalUIntType:$len); let assemblyFormat = [{ $len `bytes` `from` $dst `set` `to` $val attr-dict @@ -5071,11 +4937,8 @@ def CIR_MemSetInlineOp : CIR_Op<"memset_inline"> { ``` }]; - let arguments = (ins - Arg:$dst, - CIR_SInt32:$val, - I64Attr:$len - ); + let arguments = (ins Arg:$dst, + CIR_SInt32:$val, I64Attr:$len); let assemblyFormat = [{ $len `bytes` `from` $dst `set` `to` $val attr-dict @@ -5103,11 +4966,8 @@ def CIR_MemChrOp : CIR_Op<"libc.memchr"> { // TODO: instead of using UInt64 for len, we could make it constrained on // size_t (64 or 32) and have a builder that does the right job. - let arguments = (ins - Arg:$src, - CIR_SInt32:$pattern, - CIR_UInt64:$len - ); + let arguments = (ins Arg:$src, + CIR_SInt32:$pattern, CIR_UInt64:$len); let results = (outs CIR_VoidPtrType:$result); @@ -5183,8 +5043,7 @@ def CIR_FrameAddrOp : CIR_FuncAddrBuiltinOp<"frame_address"> { //===----------------------------------------------------------------------===// class CIR_UnaryFPToIntBuiltinOp - : CIR_Op -{ + : CIR_Op { let arguments = (ins CIR_AnyFloatType:$src); let results = (outs CIR_IntType:$result); @@ -5206,8 +5065,7 @@ def CIR_LrintOp : CIR_UnaryFPToIntBuiltinOp<"lrint", "LrintOp">; def CIR_LLrintOp : CIR_UnaryFPToIntBuiltinOp<"llrint", "LlrintOp">; class CIR_UnaryFPToFPBuiltinOp - : CIR_Op -{ + : CIR_Op { let arguments = (ins CIR_AnyFloatOrVecOfFloatType:$src); let results = (outs CIR_AnyFloatOrVecOfFloatType:$result); let summary = "libc builtin equivalent ignoring " @@ -5255,10 +5113,7 @@ def CIR_AbsOp : CIR_Op<"abs", [Pure, SameOperandsAndResultType]> { ``` }]; - let arguments = (ins - CIR_AnySIntOrVecOfSIntType:$src, - UnitAttr:$poison - ); + let arguments = (ins CIR_AnySIntOrVecOfSIntType:$src, UnitAttr:$poison); let results = (outs CIR_AnySIntOrVecOfSIntType:$result); @@ -5271,12 +5126,10 @@ class CIR_BinaryFPToFPBuiltinOp libc builtin equivalent ignoring floating-point exceptions and errno. }]; - let arguments = (ins - CIR_AnyFloatOrVecOfFloatType:$lhs, - CIR_AnyFloatOrVecOfFloatType:$rhs - ); + let arguments = (ins CIR_AnyFloatOrVecOfFloatType:$lhs, + CIR_AnyFloatOrVecOfFloatType:$rhs); - let results = (outs CIR_AnyFloatOrVecOfFloatType:$result); + let results = (outs CIR_AnyFloatOrVecOfFloatType:$result); let assemblyFormat = [{ $lhs `,` $rhs `:` qualified(type($lhs)) attr-dict @@ -5295,7 +5148,8 @@ def CIR_PowOp : CIR_BinaryFPToFPBuiltinOp<"pow", "PowOp">; def CIR_ATan2Op : CIR_BinaryFPToFPBuiltinOp<"atan2", "ATan2Op">; def CIR_IsFPClassOp : CIR_Op<"is_fp_class"> { - let summary = "Corresponding to the `__builtin_fpclassify` builtin function in clang"; + let summary = + "Corresponding to the `__builtin_fpclassify` builtin function in clang"; let description = [{ The `cir.is_fp_class` operation takes a floating-point value as its first @@ -5319,8 +5173,7 @@ def CIR_IsFPClassOp : CIR_Op<"is_fp_class"> { | 9 | Positive infinity | }]; - let arguments = (ins CIR_AnyFloatType:$src, - I32Attr:$flags); + let arguments = (ins CIR_AnyFloatType:$src, I32Attr:$flags); let results = (outs CIR_BoolType:$result); let assemblyFormat = [{ $src `,` $flags `:` functional-type($src, $result) attr-dict @@ -5375,9 +5228,8 @@ def CIR_AssumeAlignedOp function. }]; - let arguments = (ins CIR_PointerType:$pointer, - I64Attr:$alignment, - Optional:$offset); + let arguments = (ins CIR_PointerType:$pointer, I64Attr:$alignment, + Optional:$offset); let results = (outs CIR_PointerType:$result); let assemblyFormat = [{ @@ -5387,9 +5239,8 @@ def CIR_AssumeAlignedOp }]; } -def CIR_AssumeSepStorageOp : CIR_Op<"assume.separate_storage", [ - SameTypeOperands -]> { +def CIR_AssumeSepStorageOp + : CIR_Op<"assume.separate_storage", [SameTypeOperands]> { let summary = "Tell the optimizer that two pointers point to different allocations"; let description = [{ @@ -5419,8 +5270,7 @@ def CIR_PtrMaskOp : CIR_Op<"ptr_mask", [AllTypesMatch<["ptr", "result"]>]> { argument and return the masked pointer type according to the `mask`. }]; - let arguments = (ins CIR_PointerType:$ptr, - CIR_IntType:$mask); + let arguments = (ins CIR_PointerType:$ptr, CIR_IntType:$mask); let results = (outs CIR_PointerType:$result); let assemblyFormat = [{ @@ -5434,11 +5284,10 @@ def CIR_PtrMaskOp : CIR_Op<"ptr_mask", [AllTypesMatch<["ptr", "result"]>]> { // Branch Probability Operations //===----------------------------------------------------------------------===// -def CIR_ExpectOp : CIR_Op<"expect",[ - Pure, AllTypesMatch<["result", "val", "expected"]> -]> { +def CIR_ExpectOp + : CIR_Op<"expect", [Pure, AllTypesMatch<["result", "val", "expected"]>]> { let summary = - "Compute whether expression is likely to evaluate to a specified value"; + "Compute whether expression is likely to evaluate to a specified value"; let description = [{ Provides __builtin_expect functionality in Clang IR. @@ -5447,11 +5296,8 @@ def CIR_ExpectOp : CIR_Op<"expect",[ where probability = $prob. }]; - let arguments = (ins - CIR_AnyFundamentalIntType:$val, - CIR_AnyFundamentalIntType:$expected, - OptionalAttr:$prob - ); + let arguments = (ins CIR_AnyFundamentalIntType:$val, + CIR_AnyFundamentalIntType:$expected, OptionalAttr:$prob); let results = (outs CIR_AnyFundamentalIntType:$result); @@ -5487,10 +5333,7 @@ def CIR_VAEndOp : CIR_Op<"va.end"> { def CIR_VACopyOp : CIR_Op<"va.copy"> { let summary = "Copies a variable argument list"; - let arguments = (ins - CIR_PointerType:$dst_list, - CIR_PointerType:$src_list - ); + let arguments = (ins CIR_PointerType:$dst_list, CIR_PointerType:$src_list); let assemblyFormat = [{ $src_list `to` $dst_list attr-dict `:` type(operands) @@ -5535,8 +5378,8 @@ def CIR_AllocExceptionOp : CIR_Op<"alloc.exception"> { }]; let arguments = (ins I64Attr:$size); - let results = (outs Res]>:$addr); + let results = + (outs Res]>:$addr); let assemblyFormat = [{ $size `->` qualified(type($addr)) attr-dict @@ -5605,8 +5448,8 @@ def CIR_ThrowOp : CIR_Op<"throw"> { }]; let arguments = (ins Optional:$exception_ptr, - OptionalAttr:$type_info, - OptionalAttr:$dtor); + OptionalAttr:$type_info, + OptionalAttr:$dtor); let assemblyFormat = [{ ($exception_ptr^ `:` type($exception_ptr))? @@ -5661,10 +5504,9 @@ def CIR_StackRestoreOp : CIR_Op<"stack_restore"> { let llvmOp = "StackRestoreOp"; } -def CIR_AsmFlavor : CIR_I32EnumAttr<"AsmFlavor", "ATT or Intel", [ - I32EnumAttrCase<"x86_att", 0>, - I32EnumAttrCase<"x86_intel", 1> -]>; +def CIR_AsmFlavor : CIR_I32EnumAttr<"AsmFlavor", "ATT or Intel", + [I32EnumAttrCase<"x86_att", 0>, + I32EnumAttrCase<"x86_intel", 1>]>; def CIR_InlineAsmOp : CIR_Op<"asm", [RecursiveMemoryEffects]> { let description = [{ @@ -5725,25 +5567,17 @@ def CIR_InlineAsmOp : CIR_Op<"asm", [RecursiveMemoryEffects]> { let results = (outs Optional:$res); - let arguments = ( - ins VariadicOfVariadic:$asm_operands, - StrAttr:$asm_string, - StrAttr:$constraints, - UnitAttr:$side_effects, - CIR_AsmFlavor:$asm_flavor, - ArrayAttr:$operand_attrs, - DenseI32ArrayAttr:$operands_segments - ); + let arguments = + (ins VariadicOfVariadic:$asm_operands, + StrAttr:$asm_string, StrAttr:$constraints, UnitAttr:$side_effects, + CIR_AsmFlavor:$asm_flavor, ArrayAttr:$operand_attrs, + DenseI32ArrayAttr:$operands_segments); let builders = [OpBuilder<(ins - "llvm::ArrayRef":$asm_operands, - "llvm::StringRef":$asm_string, - "llvm::StringRef":$constraints, - "bool":$side_effects, - "AsmFlavor":$asm_flavor, - "llvm::ArrayRef":$operand_attrs - )> - ]; + "llvm::ArrayRef":$asm_operands, + "llvm::StringRef":$asm_string, "llvm::StringRef":$constraints, + "bool":$side_effects, "AsmFlavor":$asm_flavor, + "llvm::ArrayRef":$operand_attrs)>]; let hasCustomAssemblyFormat = 1; } @@ -5802,11 +5636,9 @@ def CIR_PrefetchOp : CIR_Op<"prefetch"> { If $isWrite doesn't specified it means that prefetch is prepared for 'read'. }]; - let arguments = (ins - CIR_VoidPtrType:$addr, - ConfinedAttr, IntMaxValue<3>]>:$locality, - UnitAttr:$isWrite - ); + let arguments = (ins CIR_VoidPtrType:$addr, + ConfinedAttr, IntMaxValue<3>]>:$locality, + UnitAttr:$isWrite); let assemblyFormat = [{ `(` $addr `:` qualified(type($addr)) `)` @@ -5820,9 +5652,8 @@ def CIR_PrefetchOp : CIR_Op<"prefetch"> { // ClearCacheOp //===----------------------------------------------------------------------===// -def CIR_ClearCacheOp : CIR_Op<"clear_cache", [ - AllTypesMatch<["begin", "end"]> -]> { +def CIR_ClearCacheOp + : CIR_Op<"clear_cache", [AllTypesMatch<["begin", "end"]>]> { let summary = "clear cache operation"; let description = [{ CIR representation for `__builtin___clear_cache`. @@ -5841,26 +5672,25 @@ def CIR_ClearCacheOp : CIR_Op<"clear_cache", [ //===----------------------------------------------------------------------===// class CIR_ArrayInitDestroy : CIR_Op { - let arguments = (ins - Arg:$addr - ); + let arguments = + (ins Arg:$addr); let regions = (region SizedRegion<1>:$body); let assemblyFormat = [{ `(` $addr `:` qualified(type($addr)) `)` $body attr-dict }]; - let builders = [ - OpBuilder<(ins "mlir::Value":$addr, - "llvm::function_ref":$regionBuilder), [{ + let builders = [OpBuilder<(ins "mlir::Value":$addr, + "llvm::function_ref":$regionBuilder), + [{ assert(regionBuilder && "builder callback expected"); mlir::OpBuilder::InsertionGuard guard($_builder); mlir::Region *r = $_state.addRegion(); $_state.addOperands(ValueRange{addr}); $_builder.createBlock(r); regionBuilder($_builder, $_state.location); - }]> - ]; + }]>]; } def CIR_ArrayCtor : CIR_ArrayInitDestroy<"array.ctor"> { @@ -5902,27 +5732,21 @@ def CIR_IsConstantOp : CIR_Op<"is_constant", [Pure]> { // SwitchFlatOp //===----------------------------------------------------------------------===// -def CIR_SwitchFlatOp : CIR_Op<"switch.flat", [ - AttrSizedOperandSegments, Terminator -]> { +def CIR_SwitchFlatOp + : CIR_Op<"switch.flat", [AttrSizedOperandSegments, Terminator]> { let summary = "A flattened version of cir.switch"; let description = [{ The `cir.switch.flat` operation is a region-less and simplified version of the `cir.switch`. It's representation is closer to LLVM IR dialect than the C/C++ language feature. }]; - let arguments = (ins - CIR_IntType:$condition, - Variadic:$defaultOperands, - VariadicOfVariadic:$caseOperands, - ArrayAttr:$case_values, - DenseI32ArrayAttr:$case_operand_segments - ); + let arguments = (ins CIR_IntType:$condition, + Variadic:$defaultOperands, + VariadicOfVariadic:$caseOperands, + ArrayAttr:$case_values, DenseI32ArrayAttr:$case_operand_segments); - let successors = (successor - AnySuccessor:$defaultDestination, - VariadicSuccessor:$caseDestinations - ); + let successors = (successor AnySuccessor:$defaultDestination, + VariadicSuccessor:$caseDestinations); let assemblyFormat = [{ $condition `:` type($condition) `,` @@ -5932,14 +5756,11 @@ def CIR_SwitchFlatOp : CIR_Op<"switch.flat", [ attr-dict }]; - let builders = [ - OpBuilder<(ins "mlir::Value":$condition, - "mlir::Block *":$defaultDestination, - "mlir::ValueRange":$defaultOperands, + let builders = [OpBuilder<(ins "mlir::Value":$condition, + "mlir::Block *":$defaultDestination, "mlir::ValueRange":$defaultOperands, CArg<"llvm::ArrayRef", "{}">:$caseValues, CArg<"mlir::BlockRange", "{}">:$caseDestinations, - CArg<"llvm::ArrayRef", "{}">:$caseOperands)> - ]; + CArg<"llvm::ArrayRef", "{}">:$caseOperands)>]; } //===----------------------------------------------------------------------===// @@ -6002,7 +5823,8 @@ def CIR_GotoOp : CIR_Op<"goto", [Terminator]> { // LabelOp //===----------------------------------------------------------------------===// -// The LabelOp has AlwaysSpeculatable trait in order to not to be swept by canonicalizer +// The LabelOp has AlwaysSpeculatable trait in order to not to be swept by +// canonicalizer def CIR_LabelOp : CIR_Op<"label", [AlwaysSpeculatable]> { let description = [{ An identifier which may be referred by cir.goto operation @@ -6016,22 +5838,17 @@ def CIR_LabelOp : CIR_Op<"label", [AlwaysSpeculatable]> { // Atomic operations //===----------------------------------------------------------------------===// -def CIR_AtomicFetchKind : CIR_I32EnumAttr< - "AtomicFetchKind", "Binary opcode for atomic fetch operations", [ - I32EnumAttrCase<"Add", 0, "add">, - I32EnumAttrCase<"Sub", 1, "sub">, - I32EnumAttrCase<"And", 2, "and">, - I32EnumAttrCase<"Xor", 3, "xor">, - I32EnumAttrCase<"Or", 4, "or">, - I32EnumAttrCase<"Nand", 5, "nand">, - I32EnumAttrCase<"Max", 6, "max">, - I32EnumAttrCase<"Min", 7, "min">, - I32EnumAttrCase<"Xchg", 8, "xchg"> -]>; +def CIR_AtomicFetchKind + : CIR_I32EnumAttr< + "AtomicFetchKind", "Binary opcode for atomic fetch operations", + [I32EnumAttrCase<"Add", 0, "add">, I32EnumAttrCase<"Sub", 1, "sub">, + I32EnumAttrCase<"And", 2, "and">, I32EnumAttrCase<"Xor", 3, "xor">, + I32EnumAttrCase<"Or", 4, "or">, I32EnumAttrCase<"Nand", 5, "nand">, + I32EnumAttrCase<"Max", 6, "max">, I32EnumAttrCase<"Min", 7, "min">, + I32EnumAttrCase<"Xchg", 8, "xchg">]>; -def CIR_AtomicFetch : CIR_Op<"atomic.fetch", [ - AllTypesMatch<["result", "val"]> -]> { +def CIR_AtomicFetch + : CIR_Op<"atomic.fetch", [AllTypesMatch<["result", "val"]>]> { let summary = "Atomic fetch with unary and binary operations"; let description = [{ Represents `__atomic__fetch` and `__atomic_fetch_` builtins, @@ -6052,14 +5869,11 @@ def CIR_AtomicFetch : CIR_Op<"atomic.fetch", [ %val : !s32i, seq_cst) : !s32i }]; let results = (outs CIR_AnyIntOrFloatType:$result); - let arguments = (ins - Arg:$ptr, - CIR_AnyIntOrFloatType:$val, - CIR_AtomicFetchKind:$binop, - Arg:$mem_order, - UnitAttr:$is_volatile, - UnitAttr:$fetch_first - ); + let arguments = + (ins Arg:$ptr, + CIR_AnyIntOrFloatType:$val, CIR_AtomicFetchKind:$binop, + Arg:$mem_order, UnitAttr:$is_volatile, + UnitAttr:$fetch_first); let assemblyFormat = [{ `(`$binop `,` @@ -6074,9 +5888,7 @@ def CIR_AtomicFetch : CIR_Op<"atomic.fetch", [ let hasVerifier = 1; } -def CIR_AtomicXchg : CIR_Op<"atomic.xchg", [ - AllTypesMatch<["result", "val"]> -]> { +def CIR_AtomicXchg : CIR_Op<"atomic.xchg", [AllTypesMatch<["result", "val"]>]> { let summary = "Atomic exchange"; let description = [{ Atomic exchange operations. Implements C/C++ builtins such as @@ -6088,9 +5900,8 @@ def CIR_AtomicXchg : CIR_Op<"atomic.xchg", [ }]; let results = (outs CIR_AnyType:$result); let arguments = (ins Arg:$ptr, - CIR_AnyType:$val, - Arg:$mem_order, - UnitAttr:$is_volatile); + CIR_AnyType:$val, Arg:$mem_order, + UnitAttr:$is_volatile); let assemblyFormat = [{ `(` @@ -6104,9 +5915,9 @@ def CIR_AtomicXchg : CIR_Op<"atomic.xchg", [ let hasVerifier = 1; } -def CIR_AtomicCmpXchg : CIR_Op<"atomic.cmp_xchg", [ - AllTypesMatch<["old", "expected", "desired"]> -]> { +def CIR_AtomicCmpXchg + : CIR_Op< + "atomic.cmp_xchg", [AllTypesMatch<["old", "expected", "desired"]>]> { let summary = "Atomic compare exchange"; let description = [{ C/C++ Atomic compare and exchange operation. Implements builtins like @@ -6123,14 +5934,11 @@ def CIR_AtomicCmpXchg : CIR_Op<"atomic.cmp_xchg", [ }]; let results = (outs CIR_AnyType:$old, CIR_BoolType:$cmp); let arguments = (ins Arg:$ptr, - CIR_AnyType:$expected, - CIR_AnyType:$desired, - Arg:$succ_order, - Arg:$fail_order, - OptionalAttr:$sync_scope, - OptionalAttr:$alignment, - UnitAttr:$weak, - UnitAttr:$is_volatile); + CIR_AnyType:$expected, CIR_AnyType:$desired, + Arg:$succ_order, + Arg:$fail_order, + OptionalAttr:$sync_scope, + OptionalAttr:$alignment, UnitAttr:$weak, UnitAttr:$is_volatile); let assemblyFormat = [{ `(` @@ -6167,12 +5975,11 @@ def CIR_AtomicTestAndSetOp : CIR_Op<"atomic.test_and_set"> { ``` }]; - let arguments = (ins - Arg, "", [MemRead, MemWrite]>:$ptr, - Arg:$mem_order, - OptionalAttr:$sync_scope, - OptionalAttr:$alignment, - UnitAttr:$is_volatile); + let arguments = + (ins Arg, "", [MemRead, MemWrite]>:$ptr, + Arg:$mem_order, + OptionalAttr:$sync_scope, + OptionalAttr:$alignment, UnitAttr:$is_volatile); let results = (outs CIR_BoolType:$result); @@ -6198,12 +6005,11 @@ def CIR_AtomicClearOp : CIR_Op<"atomic.clear"> { ``` }]; - let arguments = (ins - Arg, "", [MemRead, MemWrite]>:$ptr, - Arg:$mem_order, - OptionalAttr:$sync_scope, - OptionalAttr:$alignment, - UnitAttr:$is_volatile); + let arguments = + (ins Arg, "", [MemRead, MemWrite]>:$ptr, + Arg:$mem_order, + OptionalAttr:$sync_scope, + OptionalAttr:$alignment, UnitAttr:$is_volatile); let assemblyFormat = [{ $mem_order $ptr @@ -6233,10 +6039,8 @@ def CIR_AtomicFence : CIR_Op<"atomic.fence"> { }]; - let arguments = (ins - Arg:$ordering, - OptionalAttr:$sync_scope - ); + let arguments = (ins Arg:$ordering, + OptionalAttr:$sync_scope); let assemblyFormat = [{ (`syncscope` `(` $sync_scope^ `)`)? $ordering attr-dict @@ -6260,9 +6064,8 @@ def CIR_SignBitOp : CIR_Op<"signbit", [Pure]> { // LinkerOptionsOp //===----------------------------------------------------------------------===// -def CIR_LinkerOptionsOp : CIR_Op<"linker_options", [ - HasParent<"mlir::ModuleOp"> -]> { +def CIR_LinkerOptionsOp + : CIR_Op<"linker_options", [HasParent<"mlir::ModuleOp">]> { let summary = "Options to pass to the linker when the object file is linked"; let description = [{ Pass the given options to the linker when the resulting object file diff --git a/clang/lib/CIR/CodeGen/CIRGenCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenCXX.cpp index 4b886ae15b87..b934cb7c4f4d 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCXX.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCXX.cpp @@ -282,6 +282,30 @@ static void emitDeclDestroy(CIRGenFunction &CGF, const VarDecl *D) { CGM.getCXXABI().registerGlobalDtor(CGF, D, fnOp, nullptr); } +/// Emit the code to initialize a static local variable from within a function +/// context. This is called from guarded init for static locals. +void CIRGenFunction::emitCXXGlobalVarDeclInit(const VarDecl &D, + Address DeclAddr, + bool PerformInit) { + const Expr *Init = D.getInit(); + QualType T = D.getType(); + + if (!T->isReferenceType()) { + bool NeedsDtor = + D.needsDestruction(getContext()) == QualType::DK_cxx_destructor; + if (PerformInit) + emitDeclInit(*this, &D, DeclAddr); + if (NeedsDtor) + emitDeclDestroy(*this, &D); + return; + } + + assert(PerformInit && "cannot have constant initializer which needs " + "destruction for reference"); + RValue RV = emitReferenceBindingToExpr(Init); + emitStoreThroughLValue(RV, makeAddrLValue(DeclAddr, T)); +} + cir::FuncOp CIRGenModule::codegenCXXStructor(GlobalDecl GD) { const auto &FnInfo = getTypes().arrangeCXXStructorDeclaration(GD); auto Fn = getAddrOfCXXStructor(GD, &FnInfo, /*FnType=*/nullptr, diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h index c001c9cf055f..cc08eca83354 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h +++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h @@ -182,6 +182,19 @@ class CIRGenCXXABI { virtual void registerGlobalDtor(CIRGenFunction &CGF, const VarDecl *D, cir::FuncOp dtor, mlir::Value Addr) = 0; + /// Emit the guarded initialization code for static local variables with + /// non-trivial initialization or destruction. This implements the C++ + /// standard's requirements for thread-safe static initialization. + /// + /// \param CGF - The code generation function context + /// \param D - The variable being initialized + /// \param DeclPtr - The global variable representing the static local + /// \param PerformInit - Whether to perform initialization (true) or just + /// register the destructor (false, for constant-init + /// variables with non-trivial destructors) + virtual void emitGuardedInit(CIRGenFunction &CGF, const VarDecl &D, + cir::GlobalOp DeclPtr, bool PerformInit) = 0; + virtual void emitVirtualObjectDelete(CIRGenFunction &CGF, const CXXDeleteExpr *DE, Address Ptr, QualType ElementType, diff --git a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp index 6d3c035e3901..32bd44cc3d63 100644 --- a/clang/lib/CIR/CodeGen/CIRGenDecl.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenDecl.cpp @@ -556,8 +556,7 @@ cir::GlobalOp CIRGenFunction::addInitializerToStaticVarDecl( const VarDecl &D, cir::GlobalOp GV, cir::GetGlobalOp GVAddr) { ConstantEmitter emitter(*this); mlir::TypedAttr Init = - mlir::dyn_cast(emitter.tryEmitForInitializer(D)); - assert(Init && "Expected typed attribute"); + mlir::dyn_cast_or_null(emitter.tryEmitForInitializer(D)); // If constant emission failed, then this should be a C++ static // initializer. @@ -570,7 +569,8 @@ cir::GlobalOp CIRGenFunction::addInitializerToStaticVarDecl( // Since we have a static initializer, this global variable can't // be constant. GV.setConstant(false); - llvm_unreachable("C++ guarded init it NYI"); + + emitCXXGuardedInit(D, GV, /*PerformInit=*/true); } return GV; } @@ -613,7 +613,7 @@ cir::GlobalOp CIRGenFunction::addInitializerToStaticVarDecl( // We have a constant initializer, but a nontrivial destructor. We still // need to perform a guarded "initialization" in order to register the // destructor. - llvm_unreachable("C++ guarded init is NYI"); + emitCXXGuardedInit(D, GV, /*PerformInit=*/false); } return GV; diff --git a/clang/lib/CIR/CodeGen/CIRGenDeclCXX.cpp b/clang/lib/CIR/CodeGen/CIRGenDeclCXX.cpp index 0b9fa80536de..6fd3649956a0 100644 --- a/clang/lib/CIR/CodeGen/CIRGenDeclCXX.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenDeclCXX.cpp @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "CIRGenCXXABI.h" #include "CIRGenFunction.h" #include "CIRGenModule.h" #include "TargetInfo.h" @@ -51,3 +52,15 @@ void CIRGenModule::emitCXXGlobalVarDeclInitFunc(const VarDecl *D, emitCXXGlobalVarDeclInit(D, Addr, PerformInit); } + +void CIRGenFunction::emitCXXGuardedInit(const VarDecl &D, cir::GlobalOp DeclPtr, + bool PerformInit) { + // Darwin kernel configurations forbid guard variables to reduce overhead. + // See CodeGen: CGDeclCXX.cpp:390-396 + if (CGM.getCodeGenOpts().ForbidGuardVariables) + CGM.Error(D.getLocation(), + "this initialization requires a guard variable, which " + "the kernel does not support"); + + CGM.getCXXABI().emitGuardedInit(*this, D, DeclPtr, PerformInit); +} diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 86f047d43dfe..a1399d722496 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -2420,6 +2420,14 @@ class CIRGenFunction : public CIRGenTypeCache { void emitStaticVarDecl(const VarDecl &D, cir::GlobalLinkageKind Linkage); + void emitCXXGuardedInit(const VarDecl &D, cir::GlobalOp DeclPtr, + bool PerformInit); + + /// Emit code to perform initialization/destruction for a static local + /// variable from within a function. This is used by guarded init. + void emitCXXGlobalVarDeclInit(const VarDecl &D, Address DeclAddr, + bool PerformInit); + // Build CIR for a statement. useCurrentScope should be true if no // new scopes need be created when finding a compound statement. mlir::LogicalResult emitStmt(const clang::Stmt *S, bool useCurrentScope, diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp index 09418ae2447a..ecc6b71a2390 100644 --- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp @@ -194,6 +194,8 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI { QualType ThisTy) override; void registerGlobalDtor(CIRGenFunction &CGF, const VarDecl *D, cir::FuncOp dtor, mlir::Value Addr) override; + void emitGuardedInit(CIRGenFunction &CGF, const VarDecl &D, + cir::GlobalOp DeclPtr, bool PerformInit) override; void emitVirtualObjectDelete(CIRGenFunction &CGF, const CXXDeleteExpr *DE, Address Ptr, QualType ElementType, const CXXDestructorDecl *Dtor) override; @@ -2375,6 +2377,145 @@ void CIRGenItaniumCXXABI::registerGlobalDtor(CIRGenFunction &CGF, // prepare. Nothing to be done for CIR here. } +void CIRGenItaniumCXXABI::emitGuardedInit(CIRGenFunction &CGF, const VarDecl &D, + cir::GlobalOp declPtr, + bool performInit) { + auto &builder = CGF.getBuilder(); + mlir::Location loc = CGF.getLoc(D.getLocation()); + + // Inline variables that weren't instantiated from variable templates have + // partially-ordered initialization within their translation unit. + bool nonTemplateInline = + D.isInline() && + !isTemplateInstantiation(D.getTemplateSpecializationKind()); + + // We only need to use thread-safe statics for local non-TLS variables and + // inline variables; other global initialization is always single-threaded + // or (through lazy dynamic loading in multiple threads) unsequenced. + bool threadSafe = getContext().getLangOpts().ThreadsafeStatics && + (D.isLocalVarDecl() || nonTemplateInline) && + !D.getTLSKind(); + + // If we have a global variable with internal linkage and thread-safe statics + // are disabled, we can just let the guard variable be of type i8. + bool useInt8GuardVariable = + !threadSafe && + declPtr.getLinkage() == cir::GlobalLinkageKind::InternalLinkage; + + // Determine the guard variable type. + mlir::Type guardTy; + if (useInt8GuardVariable) { + guardTy = builder.getUInt8Ty(); + } else { + // Guard variables are 64 bits in the generic ABI and size width on ARM + // (i.e. 32-bit on AArch32, 64-bit on AArch64). + if (UseARMGuardVarABI) { + llvm_unreachable("NYI: ARM guard variable ABI"); + } else { + guardTy = builder.getUInt64Ty(); + } + } + + // Create the guard variable if we don't already have it (as we + // might if we're double-emitting this function body). + // See CodeGen: ItaniumCXXABI.cpp:2735-2772 + cir::GlobalOp guardGlobal = CGM.getStaticLocalDeclGuardAddress(&D); + if (!guardGlobal) { + // Mangle the name for the guard variable. + SmallString<256> guardName; + { + llvm::raw_svector_ostream out(guardName); + getMangleContext().mangleStaticGuardVariable(&D, out); + } + + // Create the guard variable with a zero-initializer. + // Just absorb linkage, visibility and dll storage class from the guarded + // variable. + guardGlobal = CIRGenModule::createGlobalOp( + CGM, loc, guardName.str(), guardTy, /*isConstant=*/false, + cir::AddressSpace::Default, /*insertPoint=*/nullptr, + declPtr.getLinkage()); + guardGlobal.setVisibility(declPtr.getVisibility()); + guardGlobal.setDSOLocal(declPtr.isDSOLocal()); + + // DLL storage class should match the guarded variable. + // See CodeGen: ItaniumCXXABI.cpp:2755 + assert(!cir::MissingFeatures::setDLLStorageClass()); + + // Set alignment for the guard variable based on its type. + // See CodeGen: ItaniumCXXABI.cpp:2716-2728, 2758 + CharUnits guardAlignment; + if (useInt8GuardVariable) { + guardAlignment = CharUnits::One(); + } else { + if (UseARMGuardVarABI) { + llvm_unreachable("NYI: ARM guard variable ABI alignment"); + } else { + guardAlignment = CharUnits::fromQuantity( + CGM.getDataLayout().getABITypeAlign(guardTy)); + } + } + guardGlobal.setAlignment(guardAlignment.getQuantity()); + + // Set the initial value to zero. + guardGlobal.setInitialValueAttr(builder.getZeroInitAttr(guardTy)); + + // The ABI says: "It is suggested that it be emitted in the same COMDAT + // group as the associated data object." In practice, this doesn't work for + // non-ELF and non-Wasm object formats, so only do it for ELF and Wasm. + // See CodeGen: ItaniumCXXABI.cpp:2760-2770 + bool declHasComdat = declPtr.getComdat(); + if (!D.isLocalVarDecl() && declHasComdat && + (CGM.getTarget().getTriple().isOSBinFormatELF() || + CGM.getTarget().getTriple().isOSBinFormatWasm())) { + guardGlobal.setComdat(true); + } else if (CGM.supportsCOMDAT() && guardGlobal.isWeakForLinker()) { + guardGlobal.setComdat(true); + } + + // Register the guard variable so we don't create it again. + CGM.setStaticLocalDeclGuardAddress(&D, guardGlobal); + } + + // If the variable is thread-local, so is its guard variable. + if (D.getTLSKind()) + llvm_unreachable("NYI: thread-local guard variables"); + + // Create a pointer to the guard variable for the GuardedInitOp. + auto guardAddr = builder.createGetGlobal(guardGlobal); + + // Get a symbol reference to the static variable. + auto staticVarSymbol = + mlir::FlatSymbolRefAttr::get(builder.getContext(), declPtr.getSymName()); + + // Create the GuardedInitOp. + bool isLocalVar = D.isLocalVarDecl(); + mlir::UnitAttr threadSafeAttr = threadSafe ? builder.getUnitAttr() : nullptr; + mlir::UnitAttr performInitAttr = + performInit ? builder.getUnitAttr() : nullptr; + mlir::UnitAttr isLocalVarAttr = isLocalVar ? builder.getUnitAttr() : nullptr; + auto guardedInitOp = builder.create( + loc, guardAddr, staticVarSymbol, threadSafeAttr, performInitAttr, + isLocalVarAttr); + + // Build the init region. + mlir::Region &initRegion = guardedInitOp.getInitRegion(); + mlir::OpBuilder::InsertionGuard guard(builder); + mlir::Block *initBlock = builder.createBlock(&initRegion); + builder.setInsertionPointToStart(initBlock); + + // Emit the initialization code if performInit is true. + if (performInit) { + // Get the address of the static variable for initialization. + Address declAddr(CGF.getBuilder().createGetGlobal(declPtr), + declPtr.getSymType(), getContext().getDeclAlign(&D)); + CGF.emitCXXGlobalVarDeclInit(D, declAddr, /*performInit=*/true); + } + + // Terminate the init region with a yield. + builder.create(loc); +} + mlir::Value CIRGenItaniumCXXABI::getCXXDestructorImplicitParam( CIRGenFunction &CGF, const CXXDestructorDecl *DD, CXXDtorType Type, bool ForVirtualBase, bool Delegating) { diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index e6edcd48e657..f05dab8b7658 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -237,6 +237,7 @@ class CIRGenModule : public CIRGenTypeCache { void HandleCXXStaticMemberVarInstantiation(VarDecl *VD); llvm::DenseMap StaticLocalDeclMap; + llvm::DenseMap StaticLocalDeclGuardMap; llvm::DenseMap Globals; mlir::Operation *getGlobalValue(llvm::StringRef Ref); mlir::Value getGlobalValue(const clang::Decl *D); @@ -256,6 +257,14 @@ class CIRGenModule : public CIRGenTypeCache { StaticLocalDeclMap[D] = C; } + cir::GlobalOp getStaticLocalDeclGuardAddress(const VarDecl *D) { + return StaticLocalDeclGuardMap[D]; + } + + void setStaticLocalDeclGuardAddress(const VarDecl *D, cir::GlobalOp C) { + StaticLocalDeclGuardMap[D] = C; + } + cir::GlobalOp getOrCreateStaticVarDecl(const VarDecl &D, cir::GlobalLinkageKind Linkage); diff --git a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp index 4387142ac8c5..37152e0acab7 100644 --- a/clang/lib/CIR/Dialect/IR/CIRDialect.cpp +++ b/clang/lib/CIR/Dialect/IR/CIRDialect.cpp @@ -360,8 +360,8 @@ void cir::ConditionOp::getSuccessorRegions( regions.emplace_back(&await.getSuspend(), await.getSuspend().getArguments()); } -MutableOperandRange cir::ConditionOp::getMutableSuccessorOperands( - RegionSuccessor /*successor*/) { +MutableOperandRange +cir::ConditionOp::getMutableSuccessorOperands(RegionSuccessor /*successor*/) { // No values are yielded to the successor region. return MutableOperandRange(getOperation(), 0, 0); } @@ -1525,8 +1525,7 @@ void cir::ScopeOp::getSuccessorRegions( mlir::RegionBranchPoint point, SmallVectorImpl ®ions) { // The only region always branch back to the parent operation. if (!point.isParent()) { - regions.push_back( - RegionSuccessor(getOperation(), this->getODSResults(0))); + regions.push_back(RegionSuccessor(getOperation(), this->getODSResults(0))); return; } @@ -1787,8 +1786,8 @@ void cir::TernaryOp::build( // YieldOp //===----------------------------------------------------------------------===// -MutableOperandRange cir::YieldOp::getMutableSuccessorOperands( - RegionSuccessor successor) { +MutableOperandRange +cir::YieldOp::getMutableSuccessorOperands(RegionSuccessor successor) { Operation *op = getOperation(); if (auto loop = dyn_cast(op->getParentOp())) { if (op->getParentRegion() == &loop.getCond()) @@ -2506,6 +2505,28 @@ cir::GetGlobalOp::verifySymbolUses(SymbolTableCollection &symbolTable) { return success(); } +//===----------------------------------------------------------------------===// +// GuardedInitOp +//===----------------------------------------------------------------------===// + +LogicalResult cir::GuardedInitOp::verify() { + // Verify that the guard variable is a pointer type. + auto guardPtrTy = mlir::dyn_cast(getGuardVar().getType()); + if (!guardPtrTy) + return emitOpError("guard_var must be a pointer type"); + + // Verify that the init region has exactly one block. + if (getInitRegion().getBlocks().size() != 1) + return emitOpError("init_region must have exactly one block"); + + // Verify that the init region terminates with a yield. + auto &block = getInitRegion().front(); + if (block.empty() || !isa(block.back())) + return emitOpError("init_region must terminate with cir.yield"); + + return success(); +} + //===----------------------------------------------------------------------===// // VTableAddrPointOp //===----------------------------------------------------------------------===// diff --git a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp index 4c5befec0147..7980c6182d61 100644 --- a/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp +++ b/clang/lib/CIR/Dialect/Transforms/LoweringPrepare.cpp @@ -82,6 +82,7 @@ struct LoweringPreparePass : public LoweringPrepareBase { void lowerVAArgOp(VAArgOp op); void lowerDeleteArrayOp(DeleteArrayOp op); void lowerGlobalOp(GlobalOp op); + void lowerGuardedInitOp(GuardedInitOp op); void lowerDynamicCastOp(DynamicCastOp op); void lowerStdFindOp(StdFindOp op); void lowerIterBeginOp(IterBeginOp op); @@ -920,6 +921,92 @@ void LoweringPreparePass::lowerGlobalOp(GlobalOp op) { } } +void LoweringPreparePass::lowerGuardedInitOp(GuardedInitOp op) { + CIRBaseBuilderTy builder(getContext()); + mlir::Location loc = op.getLoc(); + builder.setInsertionPoint(op); + + auto guardVar = op.getGuardVar(); + bool threadSafe = op.getThreadSafe(); + bool performInit = op.getPerformInit(); + bool isLocalVar = op.getIsLocalVar(); + + // For now, assert on thread-safe guards as they require runtime calls + // that we'll implement in a follow-up. + if (threadSafe) { + llvm_unreachable( + "NYI: thread-safe guards with __cxa_guard_acquire/release"); + } + + // Create labels for the control flow. + // We'll emit: if (!guard) { init_code; guard = 1; } + // For non-local variables, guard is set to 1 BEFORE initialization. + // For local variables, guard is set to 1 AFTER initialization. + + // Get the guard variable's element type (should be i8 or i64). + auto guardPtrTy = mlir::cast(guardVar.getType()); + auto guardTy = guardPtrTy.getPointee(); + + // Load the first byte of the guard to check initialization status. + auto guardAddr = builder.createBitcast( + guardVar, builder.getPointerTo(builder.getUIntNTy(8))); + auto guardValue = builder.createLoad(loc, guardAddr); + + // Check if the guard is zero (uninitialized). + auto zero = builder.getUnsignedInt(loc, 0, 8); + auto needsInit = + builder.createCompare(loc, cir::CmpOpKind::eq, guardValue, zero); + + // Create an if operation to conditionally execute the initialization. + cir::IfOp::create(builder, loc, needsInit, /*withElse=*/false, + [&](mlir::OpBuilder &b, mlir::Location l) { + CIRBaseBuilderTy ifBuilder(b); + ifBuilder.setInsertionPointToStart( + ifBuilder.getInsertionBlock()); + + // Create the constant value '1' to set in the guard after + // initialization. + auto one = ifBuilder.getUnsignedInt(l, 1, 8); + + // For non-local variables, set guard to 1 BEFORE init + // to prevent recursive initialization during + // construction. + if (!isLocalVar) { + ifBuilder.createStore(l, one, guardAddr); + } + + // Move the initialization code from the init_region into + // the if block. + mlir::Region &initRegion = op.getInitRegion(); + if (!initRegion.empty()) { + mlir::Block &initBlock = initRegion.front(); + // Move all operations except the terminator. + auto &ops = initBlock.getOperations(); + while (!ops.empty()) { + mlir::Operation &frontOp = ops.front(); + if (mlir::isa(frontOp)) { + frontOp.erase(); + break; + } + frontOp.moveBefore(ifBuilder.getInsertionBlock(), + ifBuilder.getInsertionPoint()); + } + } + + // For local variables, set guard to 1 AFTER init + // to allow retrying initialization if interrupted by + // exception. + if (isLocalVar) { + ifBuilder.createStore(l, one, guardAddr); + } + + ifBuilder.createYield(l); + }); + + // Remove the GuardedInitOp. + op.erase(); +} + template static llvm::SmallVector prepareCtorDtorAttrList(mlir::MLIRContext *context, @@ -1839,6 +1926,8 @@ void LoweringPreparePass::runOnOp(Operation *op) { lowerThrowOp(throwOp); } else if (auto callOp = dyn_cast(op)) { lowerTrivialConstructorCall(callOp); + } else if (auto guardedInitOp = dyn_cast(op)) { + lowerGuardedInitOp(guardedInitOp); } } @@ -1855,7 +1944,8 @@ void LoweringPreparePass::runOnOperation() { op->walk([&](Operation *op) { if (isa(op)) + ArrayCtor, ArrayDtor, cir::FuncOp, StoreOp, ThrowOp, CallOp, + GuardedInitOp>(op)) opsToTransform.push_back(op); }); diff --git a/clang/test/CIR/CodeGen/static-var-init.cpp b/clang/test/CIR/CodeGen/static-var-init.cpp new file mode 100644 index 000000000000..97e660149017 --- /dev/null +++ b/clang/test/CIR/CodeGen/static-var-init.cpp @@ -0,0 +1,136 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -fno-threadsafe-statics -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -fno-threadsafe-statics -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s + +// Test static local variable with non-trivial destructor + +class A { +public: + ~A(); +}; + +void test_static_with_dtor() { + static A obj; +} + +// CIR: cir.global "private" internal dso_local @_ZZ21test_static_with_dtorvE3obj = #cir.zero : !rec_A +// CIR: cir.global "private" internal dso_local @_ZGVZ21test_static_with_dtorvE3obj = #cir.int<0> : !u8i + +// CIR-LABEL: cir.func dso_local @_Z21test_static_with_dtorv() +// CIR: %[[OBJ:.*]] = cir.get_global @_ZZ21test_static_with_dtorvE3obj : !cir.ptr +// CIR: %[[GUARD:.*]] = cir.get_global @_ZGVZ21test_static_with_dtorvE3obj : !cir.ptr +// CIR: %[[GUARD_VAL:.*]] = cir.load %[[GUARD]] : !cir.ptr, !u8i +// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !u8i +// CIR: %[[NEED_INIT:.*]] = cir.cmp(eq, %[[GUARD_VAL]], %[[ZERO]]) : !u8i, !cir.bool +// CIR: cir.if %[[NEED_INIT]] { +// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !u8i +// CIR: cir.store %[[ONE]], %[[GUARD]] : !u8i, !cir.ptr +// CIR: } +// CIR: cir.return + +// LLVM-LABEL: define dso_local void @_Z21test_static_with_dtorv() +// LLVM: %[[GUARD_VAL:.*]] = load i8, ptr @_ZGVZ21test_static_with_dtorvE3obj +// LLVM: %[[NEED_INIT:.*]] = icmp eq i8 %[[GUARD_VAL]], 0 +// LLVM: br i1 %[[NEED_INIT]], label %[[INIT_BLOCK:.*]], label %[[END_BLOCK:.*]] +// LLVM: [[INIT_BLOCK]]: +// LLVM: store i8 1, ptr @_ZGVZ21test_static_with_dtorvE3obj +// LLVM: br label %[[END_BLOCK]] +// LLVM: [[END_BLOCK]]: + +// Test static local variable with dynamic initialization + +class B { +public: + B(int); + ~B(); +}; + +void test_static_with_init() { + static B obj(42); +} + +// CIR: cir.global "private" internal dso_local @_ZGVZ21test_static_with_initvE3obj = #cir.int<0> : !u8i + +// CIR-LABEL: cir.func dso_local @_Z21test_static_with_initv() +// CIR: %[[OBJ:.*]] = cir.get_global @_ZZ21test_static_with_initvE3obj : !cir.ptr +// CIR: %[[GUARD:.*]] = cir.get_global @_ZGVZ21test_static_with_initvE3obj : !cir.ptr +// CIR: %[[GUARD_VAL:.*]] = cir.load %[[GUARD]] : !cir.ptr, !u8i +// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !u8i +// CIR: %[[NEED_INIT:.*]] = cir.cmp(eq, %[[GUARD_VAL]], %[[ZERO]]) : !u8i, !cir.bool +// CIR: cir.if %[[NEED_INIT]] { +// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !u8i +// CIR: %[[OBJ2:.*]] = cir.get_global @_ZZ21test_static_with_initvE3obj : !cir.ptr +// CIR: %[[INIT_VAL:.*]] = cir.const #cir.int<42> : !s32i +// CIR: cir.call @_ZN1BC1Ei(%[[OBJ2]], %[[INIT_VAL]]) : (!cir.ptr, !s32i) -> () +// CIR: cir.call @_ZN1BD1Ev({{.*}}) : (!cir.ptr) -> () +// CIR: cir.store %[[ONE]], %[[GUARD]] : !u8i, !cir.ptr +// CIR: } +// CIR: cir.return + +// LLVM-LABEL: define dso_local void @_Z21test_static_with_initv() +// LLVM: %[[GUARD_VAL:.*]] = load i8, ptr @_ZGVZ21test_static_with_initvE3obj +// LLVM: %[[NEED_INIT:.*]] = icmp eq i8 %[[GUARD_VAL]], 0 +// LLVM: br i1 %[[NEED_INIT]], label %[[INIT_BLOCK:.*]], label %[[END_BLOCK:.*]] +// LLVM: [[INIT_BLOCK]]: +// LLVM: call {{.*}} @_ZN1BC1Ei +// LLVM: store i8 1, ptr @_ZGVZ21test_static_with_initvE3obj +// LLVM: br label %[[END_BLOCK]] +// LLVM: [[END_BLOCK]]: + +// Test static local variable with constant initializer but non-trivial destructor + +class C { +public: + C() = default; + ~C(); + int x = 0; +}; + +void test_static_const_init_with_dtor() { + static C obj; +} + +// CIR: cir.global "private" internal dso_local @_ZGVZ32test_static_const_init_with_dtorvE3obj = #cir.int<0> : !u8i + +// CIR-LABEL: cir.func dso_local @_Z32test_static_const_init_with_dtorv() +// CIR: %[[OBJ:.*]] = cir.get_global @_ZZ32test_static_const_init_with_dtorvE3obj : !cir.ptr +// CIR: %[[GUARD:.*]] = cir.get_global @_ZGVZ32test_static_const_init_with_dtorvE3obj : !cir.ptr +// CIR: %[[GUARD_VAL:.*]] = cir.load %[[GUARD]] : !cir.ptr, !u8i +// CIR: %[[ZERO:.*]] = cir.const #cir.int<0> : !u8i +// CIR: %[[NEED_INIT:.*]] = cir.cmp(eq, %[[GUARD_VAL]], %[[ZERO]]) : !u8i, !cir.bool +// CIR: cir.if %[[NEED_INIT]] { +// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !u8i +// CIR: cir.store %[[ONE]], %[[GUARD]] : !u8i, !cir.ptr +// CIR: } +// CIR: cir.return +// Test static variable with reference parameter and non-trivial destructor + +class RefHolder { +public: + RefHolder(const int&); + ~RefHolder(); +}; + +int external_value = 42; + +void test_static_with_ref_param() { + static RefHolder rh(external_value); +} + +// CIR-LABEL: cir.func dso_local @_Z26test_static_with_ref_paramv() +// CIR: cir.get_global @_ZGVZ26test_static_with_ref_paramvE2rh : !cir.ptr +// CIR: cir.load +// CIR: cir.cmp(eq, +// CIR: cir.if +// CIR: cir.call @_ZN9RefHolderC1ERKi +// CIR: cir.call @_ZN9RefHolderD1Ev +// CIR: cir.return + +// LLVM-LABEL: define dso_local void @_Z26test_static_with_ref_paramv() +// LLVM: load i8, ptr @_ZGVZ26test_static_with_ref_paramvE2rh +// LLVM: icmp eq i8 +// LLVM: br i1 +// LLVM: call {{.*}} @_ZN9RefHolderC1ERKi +// LLVM: store i8 1, ptr @_ZGVZ26test_static_with_ref_paramvE2rh + diff --git a/clang/test/CIR/crashes/static-var-dyn-cast.cpp b/clang/test/CIR/crashes/static-var-dyn-cast.cpp index 9ca2c610b43f..8ad770333f02 100644 --- a/clang/test/CIR/crashes/static-var-dyn-cast.cpp +++ b/clang/test/CIR/crashes/static-var-dyn-cast.cpp @@ -1,11 +1,8 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir -// XFAIL: * +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -fno-threadsafe-statics -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s // -// dyn_cast on non-existent value - assertion failure -// Location: Casting.h:644 -// -// Original failure: assertion_dyncast from LLVM build -// Reduced from /tmp/FormattedStream-a19c5f.cpp +// Test static local variable with template constructor +// (Previously crashed with assertion failure in dyn_cast) struct a { template a(b, c); @@ -17,3 +14,14 @@ class d { d(int) : e(0, 0) {} }; void f() { static d g(0); } + +// CHECK: cir.global "private" internal dso_local @_ZZ1fvE1g = #cir.zero : !rec_d +// CHECK: cir.global "private" internal dso_local @_ZGVZ1fvE1g = #cir.int<0> : !u8i +// CHECK: cir.func dso_local @_Z1fv() +// CHECK: cir.get_global @_ZZ1fvE1g +// CHECK: cir.get_global @_ZGVZ1fvE1g +// CHECK: cir.load +// CHECK: cir.cmp(eq, +// CHECK: cir.if +// CHECK: cir.call @_ZN1dC1Ei +// CHECK: cir.return diff --git a/clang/test/CIR/crashes/static-var-guarded-init.cpp b/clang/test/CIR/crashes/static-var-guarded-init.cpp index 45f42b127906..884935c71e5d 100644 --- a/clang/test/CIR/crashes/static-var-guarded-init.cpp +++ b/clang/test/CIR/crashes/static-var-guarded-init.cpp @@ -1,14 +1,21 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir -// XFAIL: * +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -fno-threadsafe-statics -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s // -// Declaration handling NYI -// Location: CIRGenDecl.cpp:616 -// -// Original failure: decl_616 from LLVM build -// Reduced from /tmp/MSFError-102e4d.cpp +// Test static local variable with non-trivial destructor +// (Previously crashed with "C++ guarded init is NYI") class a { public: ~a(); }; void b() { static a c; } + +// CHECK: cir.global "private" internal dso_local @_ZZ1bvE1c = #cir.zero : !rec_a +// CHECK: cir.global "private" internal dso_local @_ZGVZ1bvE1c = #cir.int<0> : !u8i +// CHECK: cir.func dso_local @_Z1bv() +// CHECK: cir.get_global @_ZZ1bvE1c +// CHECK: cir.get_global @_ZGVZ1bvE1c +// CHECK: cir.load +// CHECK: cir.cmp(eq, +// CHECK: cir.if +// CHECK: cir.return