| //===--- Builtins.def - Builtins Macro Metaprogramming Database -*- C++ -*-===// |
| // |
| // This source file is part of the Swift.org open source project |
| // |
| // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors |
| // Licensed under Apache License v2.0 with Runtime Library Exception |
| // |
| // See https://swift.org/LICENSE.txt for license information |
| // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines the database of builtin functions. |
| // |
| // BUILTIN(Id, Name, Attrs) |
| // - Id is an identifier suitable for use in C++ |
| // - Name is a string literal for the name to which the builtin should be |
| // bound in Swift |
| // - Attrs specifies information about attributes of the function: |
| // n -> readnone |
| // |
| //===----------------------------------------------------------------------===// |
| |
| /// Cast operations have type T1 -> T2. |
| #ifndef BUILTIN_CAST_OPERATION |
| #define BUILTIN_CAST_OPERATION(Id, Name, Attrs) BUILTIN(Id, Name, Attrs) |
| #endif |
| BUILTIN_CAST_OPERATION(Trunc , "trunc", "n") |
| BUILTIN_CAST_OPERATION(ZExt , "zext", "n") |
| BUILTIN_CAST_OPERATION(SExt , "sext", "n") |
| BUILTIN_CAST_OPERATION(FPToUI , "fptoui", "n") |
| BUILTIN_CAST_OPERATION(FPToSI , "fptosi", "n") |
| BUILTIN_CAST_OPERATION(UIToFP , "uitofp", "n") |
| BUILTIN_CAST_OPERATION(SIToFP , "sitofp", "n") |
| BUILTIN_CAST_OPERATION(FPTrunc , "fptrunc", "n") |
| BUILTIN_CAST_OPERATION(FPExt , "fpext", "n") |
| BUILTIN_CAST_OPERATION(PtrToInt, "ptrtoint", "n") |
| BUILTIN_CAST_OPERATION(IntToPtr, "inttoptr", "n") |
| BUILTIN_CAST_OPERATION(BitCast , "bitcast", "n") |
| |
| #undef BUILTIN_CAST_OPERATION |
| |
| /// Cast-or-bitcast operations have type T1 -> T2. |
| /// T1 and T2 may be the same size, unlike the corresponding true casts. |
| #ifndef BUILTIN_CAST_OR_BITCAST_OPERATION |
| #define BUILTIN_CAST_OR_BITCAST_OPERATION(Id, Name, Attrs) BUILTIN(Id, Name, Attrs) |
| #endif |
| BUILTIN_CAST_OR_BITCAST_OPERATION(TruncOrBitCast, "truncOrBitCast", "n") |
| BUILTIN_CAST_OR_BITCAST_OPERATION(ZExtOrBitCast, "zextOrBitCast", "n") |
| BUILTIN_CAST_OR_BITCAST_OPERATION(SExtOrBitCast, "sextOrBitCast", "n") |
| #undef BUILTIN_CAST_OR_BITCAST_OPERATION |
| |
| /// Binary operations have type (T,T) -> T. |
| /// |
| /// We define two different sorts of operations varying when T is static, |
| /// specifically: |
| /// |
| /// 1. Overloaded statically typed operations. E.x: |
| /// |
| /// builtin "add_Vec4xInt32"(Vec4xInt32, Vec4xInt32) : Vec4xInt32. |
| /// |
| /// 2. Polymorphic typed operations that are valid only in raw SIL. By the time |
| /// diagnostic constant propagation runs, these must have as its operand a |
| /// fully specialized type. If the builtin has a type that is not one of its |
| /// overloaded types, diagnostic constant propagation will emit a diagnostic |
| /// saying the builtin's type has not been fully resolved. Otherwise, |
| /// diagnostic constant propagation will transform the builtin to the |
| /// relevant static overloaded builtin form. E.x.: |
| /// |
| /// builtin "add"(Self, Self) : Self // *error* |
| /// |
| /// OR |
| /// |
| /// builtin "generic_add"(Vec4xInt32, Vec4xInt32) : Vec4xInt32 |
| /// -> |
| /// builtin "add_Vec4xInt32"(Vec4xInt32, Vec4xInt32) : Vec4xInt32 |
| /// |
| /// NOTE: If a polymorphic typed operation is not static by the time guaranteed |
| /// constant propagation runs, we emit a diagnostic to inform the user (who is |
| /// assumed to be an expert user) to tell them the value was unspecialized. The |
| /// typical way this specialization occurs today is via transparent inlining |
| /// since the transparent inliner devirtualizes and specializes as it goes. Of |
| /// course this means mandatory inlining must /always/ occur before diagnostic |
| /// constant propagation. |
| /// |
| /// NOTE: Often times the builtin infrastructure wants to treat all |
| /// binary operation builtins generic or not the same way. To ensure |
| /// we support all use cases in the compiler, we do not declare the |
| /// operations as part of this builtin since often times this macro is |
| /// used to generic code. Instead, we stamp this out using the |
| /// overloaded_static, polymorphic, and all suffixed operations. |
| #ifndef BUILTIN_BINARY_OPERATION |
| #define BUILTIN_BINARY_OPERATION(Id, Name, Attrs) BUILTIN(Id, Name, Attrs) |
| #endif |
| |
| #ifdef BUILTIN_BINARY_OPERATION_GENERIC_HELPER_STR |
| #error "Do not define BUILTIN_BINARY_OPERATION_GENERIC_HELPER_STR before including this .def file" |
| #endif |
| |
| #define BUILTIN_BINARY_OPERATION_GENERIC_HELPER_STR(NAME) #NAME |
| |
| #ifndef BUILTIN_BINARY_OPERATION_OVERLOADED_STATIC |
| #define BUILTIN_BINARY_OPERATION_OVERLOADED_STATIC(Id, Name, Attrs, Overload) \ |
| BUILTIN_BINARY_OPERATION(Id, Name, Attrs) |
| #endif |
| |
| #ifndef BUILTIN_BINARY_OPERATION_POLYMORPHIC |
| #define BUILTIN_BINARY_OPERATION_POLYMORPHIC(Id, Name) \ |
| BUILTIN_BINARY_OPERATION(Id, Name, "") |
| #endif |
| |
| // TODO: This needs a better name. We stringify generic_ in *_{OVERLOADED_STATIC,POLYMORPHIC} |
| #ifndef BUILTIN_BINARY_OPERATION_ALL |
| #define BUILTIN_BINARY_OPERATION_ALL(Id, Name, Attrs, Overload) \ |
| BUILTIN_BINARY_OPERATION_OVERLOADED_STATIC(Id, BUILTIN_BINARY_OPERATION_GENERIC_HELPER_STR(Name), Attrs, Overload) \ |
| BUILTIN_BINARY_OPERATION_POLYMORPHIC(Generic##Id, BUILTIN_BINARY_OPERATION_GENERIC_HELPER_STR(generic_##Name)) |
| #endif |
| |
| // NOTE: Here we need our name field to be bare. We stringify them as |
| // appropriately in BUILTIN_BINARY_OPERATION_{OVERLOADED_STATIC,POLYMORPHIC}. |
| BUILTIN_BINARY_OPERATION_ALL(Add, add, "n", IntegerOrVector) |
| BUILTIN_BINARY_OPERATION_ALL(FAdd, fadd, "n", FloatOrVector) |
| BUILTIN_BINARY_OPERATION_ALL(And, and, "n", IntegerOrVector) |
| BUILTIN_BINARY_OPERATION_ALL(AShr, ashr, "n", IntegerOrVector) |
| BUILTIN_BINARY_OPERATION_ALL(LShr, lshr, "n", IntegerOrVector) |
| BUILTIN_BINARY_OPERATION_ALL(Or, or, "n", IntegerOrVector) |
| BUILTIN_BINARY_OPERATION_ALL(FDiv, fdiv, "n", FloatOrVector) |
| BUILTIN_BINARY_OPERATION_ALL(Mul, mul, "n", IntegerOrVector) |
| BUILTIN_BINARY_OPERATION_ALL(FMul, fmul, "n", FloatOrVector) |
| BUILTIN_BINARY_OPERATION_ALL(SDiv, sdiv, "n", IntegerOrVector) |
| BUILTIN_BINARY_OPERATION_ALL(ExactSDiv, sdiv_exact, "n", IntegerOrVector) |
| BUILTIN_BINARY_OPERATION_ALL(Shl, shl, "n", IntegerOrVector) |
| BUILTIN_BINARY_OPERATION_ALL(SRem, srem, "n", IntegerOrVector) |
| BUILTIN_BINARY_OPERATION_ALL(Sub, sub, "n", IntegerOrVector) |
| BUILTIN_BINARY_OPERATION_ALL(FSub, fsub, "n", FloatOrVector) |
| BUILTIN_BINARY_OPERATION_ALL(UDiv, udiv, "n", IntegerOrVector) |
| BUILTIN_BINARY_OPERATION_ALL(ExactUDiv, udiv_exact, "n", IntegerOrVector) |
| BUILTIN_BINARY_OPERATION_ALL(URem, urem, "n", Integer) |
| BUILTIN_BINARY_OPERATION_ALL(FRem, frem, "n", FloatOrVector) |
| BUILTIN_BINARY_OPERATION_ALL(Xor, xor, "n", IntegerOrVector) |
| BUILTIN_BINARY_OPERATION_OVERLOADED_STATIC(Expect, "int_expect", "n", Integer) |
| #undef BUILTIN_BINARY_OPERATION_ALL |
| #undef BUILTIN_BINARY_OPERATION_POLYMORPHIC |
| #undef BUILTIN_BINARY_OPERATION_OVERLOADED_STATIC |
| #undef BUILTIN_BINARY_OPERATION_GENERIC_HELPER_STR |
| #undef BUILTIN_BINARY_OPERATION |
| |
| /// These builtins are analogous the similarly named llvm intrinsics. The |
| /// difference between the two is that these are not expected to overflow, |
| /// so we should produce a compile time error if we can statically prove |
| /// that they do. |
| #ifndef BUILTIN_BINARY_OPERATION_WITH_OVERFLOW |
| #define BUILTIN_BINARY_OPERATION_WITH_OVERFLOW(Id, Name, UncheckedID, Attrs, Overload) \ |
| BUILTIN(Id, Name, Attrs) |
| #endif |
| BUILTIN_BINARY_OPERATION_WITH_OVERFLOW(SAddOver, |
| "sadd_with_overflow", Add, "n", Integer) |
| BUILTIN_BINARY_OPERATION_WITH_OVERFLOW(UAddOver, |
| "uadd_with_overflow", Add, "n", Integer) |
| BUILTIN_BINARY_OPERATION_WITH_OVERFLOW(SSubOver, |
| "ssub_with_overflow", Sub, "n", Integer) |
| BUILTIN_BINARY_OPERATION_WITH_OVERFLOW(USubOver, |
| "usub_with_overflow", Sub, "n", Integer) |
| BUILTIN_BINARY_OPERATION_WITH_OVERFLOW(SMulOver, |
| "smul_with_overflow", Mul, "n", Integer) |
| BUILTIN_BINARY_OPERATION_WITH_OVERFLOW(UMulOver, |
| "umul_with_overflow", Mul, "n", Integer) |
| #undef BUILTIN_BINARY_OPERATION_WITH_OVERFLOW |
| |
| /// Unary operations have type (T) -> T. |
| #ifndef BUILTIN_UNARY_OPERATION |
| #define BUILTIN_UNARY_OPERATION(Id, Name, Attrs, Overload) \ |
| BUILTIN(Id, Name, Attrs) |
| #endif |
| |
| // "fneg" is a separate builtin because its LLVM representation is |
| // 'fsub -0.0, %x', but defining it in swift as |
| // 'func [prefix] -(x) { -0.0 - x }' would be infinitely recursive. |
| BUILTIN_UNARY_OPERATION(FNeg, "fneg", "n", FloatOrVector) |
| |
| // Returns the argument and specifies that the value is not negative. |
| // It has only an effect if the argument is a load or call. |
| // TODO: consider printing a warning if it is not used on a load or call. |
| BUILTIN_UNARY_OPERATION(AssumeNonNegative, "assumeNonNegative", "n", Integer) |
| // It only works on i1. |
| BUILTIN_UNARY_OPERATION(AssumeTrue, "assume", "", Integer) |
| |
| #undef BUILTIN_UNARY_OPERATION |
| |
| // Binary predicates have type (T,T) -> i1 or (T, T) -> Vector<i1> for scalars |
| // and vectors, respectively. |
| #ifndef BUILTIN_BINARY_PREDICATE |
| #define BUILTIN_BINARY_PREDICATE(Id, Name, Attrs, Overload) \ |
| BUILTIN(Id, Name, Attrs) |
| #endif |
| BUILTIN_BINARY_PREDICATE(ICMP_EQ, "cmp_eq", "n", IntegerOrRawPointerOrVector) |
| BUILTIN_BINARY_PREDICATE(ICMP_NE, "cmp_ne", "n", IntegerOrRawPointerOrVector) |
| BUILTIN_BINARY_PREDICATE(ICMP_SLE, "cmp_sle", "n", IntegerOrVector) |
| BUILTIN_BINARY_PREDICATE(ICMP_SLT, "cmp_slt", "n", IntegerOrVector) |
| BUILTIN_BINARY_PREDICATE(ICMP_SGE, "cmp_sge", "n", IntegerOrVector) |
| BUILTIN_BINARY_PREDICATE(ICMP_SGT, "cmp_sgt", "n", IntegerOrVector) |
| BUILTIN_BINARY_PREDICATE(ICMP_ULE, "cmp_ule", "n", IntegerOrRawPointerOrVector) |
| BUILTIN_BINARY_PREDICATE(ICMP_ULT, "cmp_ult", "n", IntegerOrRawPointerOrVector) |
| BUILTIN_BINARY_PREDICATE(ICMP_UGE, "cmp_uge", "n", IntegerOrRawPointerOrVector) |
| BUILTIN_BINARY_PREDICATE(ICMP_UGT, "cmp_ugt", "n", IntegerOrRawPointerOrVector) |
| BUILTIN_BINARY_PREDICATE(FCMP_OEQ, "fcmp_oeq", "n", FloatOrVector) |
| BUILTIN_BINARY_PREDICATE(FCMP_OGT, "fcmp_ogt", "n", FloatOrVector) |
| BUILTIN_BINARY_PREDICATE(FCMP_OGE, "fcmp_oge", "n", FloatOrVector) |
| BUILTIN_BINARY_PREDICATE(FCMP_OLT, "fcmp_olt", "n", FloatOrVector) |
| BUILTIN_BINARY_PREDICATE(FCMP_OLE, "fcmp_ole", "n", FloatOrVector) |
| BUILTIN_BINARY_PREDICATE(FCMP_ONE, "fcmp_one", "n", FloatOrVector) |
| BUILTIN_BINARY_PREDICATE(FCMP_ORD, "fcmp_ord", "n", FloatOrVector) |
| BUILTIN_BINARY_PREDICATE(FCMP_UEQ, "fcmp_ueq", "n", FloatOrVector) |
| BUILTIN_BINARY_PREDICATE(FCMP_UGT, "fcmp_ugt", "n", FloatOrVector) |
| BUILTIN_BINARY_PREDICATE(FCMP_UGE, "fcmp_uge", "n", FloatOrVector) |
| BUILTIN_BINARY_PREDICATE(FCMP_ULT, "fcmp_ult", "n", FloatOrVector) |
| BUILTIN_BINARY_PREDICATE(FCMP_ULE, "fcmp_ule", "n", FloatOrVector) |
| BUILTIN_BINARY_PREDICATE(FCMP_UNE, "fcmp_une", "n", FloatOrVector) |
| BUILTIN_BINARY_PREDICATE(FCMP_UNO, "fcmp_uno", "n", FloatOrVector) |
| #undef BUILTIN_BINARY_PREDICATE |
| |
| // BUILTIN_SIL_OPERATION - Operations that can be lowered to SIL instructions. |
| // These have various types. |
| // Since these operations will be lowered to SIL Instructions, we do not |
| // assign any attributes on them. |
| #ifndef BUILTIN_SIL_OPERATION |
| #define BUILTIN_SIL_OPERATION(Id, Name, Overload) BUILTIN(Id, Name, "") |
| #endif |
| |
| /// retain: T -> () |
| BUILTIN_SIL_OPERATION(Retain, "retain", Special) |
| |
| /// release: T -> () |
| BUILTIN_SIL_OPERATION(Release, "release", Special) |
| |
| /// autorelease: T -> () |
| BUILTIN_SIL_OPERATION(Autorelease, "autorelease", Special) |
| |
| /// Load has type (Builtin.RawPointer) -> T |
| BUILTIN_SIL_OPERATION(Load, "load", Special) |
| |
| /// LoadRaw has type (Builtin.RawPointer) -> T |
| /// This is a load of T from raw memory. |
| /// Its address does not adhere to strict aliasing. |
| BUILTIN_SIL_OPERATION(LoadRaw, "loadRaw", Special) |
| |
| /// LoadInvariant has type (Builtin.RawPointer) -> T |
| /// This is a load of T from raw memory. |
| /// The load is marked as invariant. |
| BUILTIN_SIL_OPERATION(LoadInvariant, "loadInvariant", Special) |
| |
| /// Take has type (Builtin.RawPointer) -> T |
| BUILTIN_SIL_OPERATION(Take, "take", Special) |
| |
| /// Destroy has type (T.Type, Builtin.RawPointer) -> () |
| BUILTIN_SIL_OPERATION(Destroy, "destroy", Special) |
| |
| /// Assign has type (T, Builtin.RawPointer) -> () |
| BUILTIN_SIL_OPERATION(Assign, "assign", Special) |
| |
| /// Init has type (T, Builtin.RawPointer) -> () |
| BUILTIN_SIL_OPERATION(Init, "initialize", Special) |
| |
| /// CastToNativeObject has type (T) -> Builtin.NativeObject. |
| /// |
| /// This builtin asserts if the underlying type /could/ be objc. |
| BUILTIN_SIL_OPERATION(CastToNativeObject, "castToNativeObject", Special) |
| |
| /// UnsafeCastToNativeObject has type (T) -> Builtin.NativeObject. |
| /// |
| /// This builtin does not check if the underlying type /could/ be objc. |
| BUILTIN_SIL_OPERATION(UnsafeCastToNativeObject, "unsafeCastToNativeObject", Special) |
| |
| /// CastFromNativeObject has type (Builtin.NativeObject) -> T |
| BUILTIN_SIL_OPERATION(CastFromNativeObject, "castFromNativeObject", Special) |
| |
| /// CastToBridgeObject has type (T, Builtin.Word) -> Builtin.BridgeObject. |
| /// It sets the BridgeObject to the bitwise OR of its operands. |
| /// It is assumed that |
| /// |
| /// castReferenceFromBridgeObject(castToBridgeObject(ref, x)) === ref |
| /// |
| /// regardless of what x is. |
| /// x thus must not have any bits set that would change the heap |
| /// object pointer value, nor may it have the native/ObjC discriminator bit set, |
| /// nor may it have any bits set if the first operand is an ObjC tagged pointer, |
| /// or else undefined behavior will ensue. |
| BUILTIN_SIL_OPERATION(CastToBridgeObject, "castToBridgeObject", Special) |
| |
| /// ValueToBridgeObject has type (T) -> Builtin.BridgeObject. |
| /// It sets the BridgeObject to a tagged pointer representation holding its |
| // operands by tagging and shifting the operand if needed. |
| /// |
| /// valueToBridgeObject(x) === (x << _swift_abi_ObjCReservedLowBits) | |
| /// _swift_BridgeObject_TaggedPointerBits |
| /// |
| /// x thus must not be using any high bits shifted away (via _swift_abi_ObjCReservedLowBits) |
| /// or the tag bits post-shift. |
| /// ARC operations on such tagged values are NOPs. |
| BUILTIN_SIL_OPERATION(ValueToBridgeObject, "valueToBridgeObject", Special) |
| |
| /// CastReferenceFromBridgeObject has type (Builtin.BridgeObject) -> T. |
| /// It recovers the heap object reference by masking spare bits from the |
| /// BridgeObject. |
| BUILTIN_SIL_OPERATION(CastReferenceFromBridgeObject, |
| "castReferenceFromBridgeObject", |
| Special) |
| |
| /// CastBitPatternFromBridgeObject has type (Builtin.BridgeObject) -> Builtin.Word. |
| /// It presents the raw bit pattern of the BridgeObject as |
| BUILTIN_SIL_OPERATION(CastBitPatternFromBridgeObject, |
| "castBitPatternFromBridgeObject", |
| Special) |
| |
| /// ClassifyBridgeObject has type: |
| /// (Builtin.BridgeObject) -> (Builtin.Int1, Builtin.Int1). |
| /// It interprets the bits mangled into a bridge object, returning whether it is |
| /// an Objective-C object or tagged pointer representation. |
| BUILTIN_SIL_OPERATION(ClassifyBridgeObject, "classifyBridgeObject", Special) |
| |
| |
| /// BridgeToRawPointer has type (T) -> Builtin.RawPointer |
| BUILTIN_SIL_OPERATION(BridgeToRawPointer, "bridgeToRawPointer", Special) |
| |
| /// BridgeFromRawPointer (Builtin.RawPointer) -> T |
| /// SILGen requires that T is a single retainable pointer. |
| /// Bridging to/from a raw pointer does not imply a retain. |
| BUILTIN_SIL_OPERATION(BridgeFromRawPointer, "bridgeFromRawPointer", Special) |
| |
| /// castReference has type T -> U. |
| /// T and U must be convertible to AnyObject. |
| BUILTIN_SIL_OPERATION(CastReference, "castReference", Special) |
| |
| /// reinterpretCast has type T -> U. |
| BUILTIN_SIL_OPERATION(ReinterpretCast, "reinterpretCast", Special) |
| |
| /// addressof (inout T) -> Builtin.RawPointer |
| /// Returns a RawPointer pointing to a physical lvalue. The returned pointer is |
| /// only valid for the duration of the original binding. |
| BUILTIN_SIL_OPERATION(AddressOf, "addressof", Special) |
| |
| /// addressOfBorrow (__shared T) -> Builtin.RawPointer |
| /// Returns a RawPointer pointing to a borrowed rvalue. The returned pointer is only |
| /// valid within the scope of the borrow. |
| BUILTIN_SIL_OPERATION(AddressOfBorrow, "addressOfBorrow", Special) |
| |
| /// GepRaw(Builtin.RawPointer, Builtin.Word) -> Builtin.RawPointer |
| /// |
| /// Adds index bytes to a base pointer. |
| BUILTIN_SIL_OPERATION(GepRaw, "gepRaw", Integer) |
| |
| /// Gep (Builtin.RawPointer, Builtin.Word, T.Type) -> Builtin.RawPointer |
| /// |
| /// Like the GepRaw-builtin, but multiplies the index by stride-of type 'T'. |
| BUILTIN_SIL_OPERATION(Gep, "gep", Integer) |
| |
| /// getTailAddr(Builtin.RawPointer, |
| /// Builtin.Word, T.Type, E.Type) -> Builtin.RawPointer |
| /// |
| /// Like the Gep-builtin, but rounds up the resulting address to a tail- |
| /// allocated element type 'E'. |
| BUILTIN_SIL_OPERATION(GetTailAddr, "getTailAddr", Integer) |
| |
| /// performInstantaneousReadAccess(Builtin.RawPointer, T.Type) -> () |
| /// Begin and then immediately end a read access to the given raw pointer, |
| /// which will be treated as an address of type 'T'. |
| BUILTIN_SIL_OPERATION(PerformInstantaneousReadAccess, |
| "performInstantaneousReadAccess", Special) |
| |
| /// beginUnpairedModifyAccess(Builtin.RawPointer, Builtin.RawPointer, |
| /// T.Type) -> () |
| /// Begins but does not end a 'modify' access to the first raw pointer argument. |
| /// The second raw pointer must be a pointer to an UnsafeValueBuffer, which |
| /// will be used by the runtime to record the access. The lifetime of the |
| /// value buffer must be longer than that of the access itself. The accessed |
| /// address will be treated as having type 'T'. |
| BUILTIN_SIL_OPERATION(BeginUnpairedModifyAccess, "beginUnpairedModifyAccess", |
| Special) |
| |
| /// endUnpairedAccess(Builtin.RawPointer) -> () |
| /// Ends an in-progress unpaired access. The raw pointer argument must be |
| /// be a pointer to an UnsafeValueBuffer that records an in progress access. |
| BUILTIN_SIL_OPERATION(EndUnpairedAccess, "endUnpairedAccess", Special) |
| |
| /// condfail(Int1) -> () |
| /// Triggers a runtime failure if the condition is true. |
| /// This builtin is deprecated. Use condfail_message instead. |
| BUILTIN_SIL_OPERATION(LegacyCondFail, "condfail", Special) |
| |
| /// fixLifetime(T) -> () |
| /// Fixes the lifetime of any heap references in a value. |
| BUILTIN_SIL_OPERATION(FixLifetime, "fixLifetime", Special) |
| |
| /// isUnique : <T> (inout T[?]) -> Int1 |
| /// |
| /// This builtin takes an inout object reference and returns a boolean. Passing |
| /// the reference inout forces the optimizer to preserve a retain distinct from |
| /// what's required to maintain lifetime for any of the reference's source-level |
| /// copies, because the called function is allowed to replace the reference, |
| /// thereby releasing the referent. |
| /// |
| /// The kind of reference count checking that Builtin.isUnique performs depends |
| /// on the argument type: |
| /// |
| /// - Native object types are directly checked by reading the |
| /// strong reference count: |
| /// (Builtin.NativeObject, known native class reference) |
| /// |
| /// - Objective-C object types require an additional check that the |
| /// dynamic object type uses native swift reference counting: |
| /// (AnyObject, unknown class reference, class existential) |
| /// |
| /// - Bridged object types allow the dynamic object type check to be |
| /// passed based on their pointer encoding: |
| /// (Builtin.BridgeObject) |
| /// |
| /// Any of the above types may also be wrapped in an optional. |
| /// If the static argument type is optional, then a null check is also |
| /// performed. |
| /// |
| /// Thus, isUnique only returns true for non-null, native swift object |
| /// references with a strong reference count of one. |
| BUILTIN_SIL_OPERATION(IsUnique, "isUnique", Special) |
| |
| /// IsUnique_native : <T> (inout T[?]) -> Int1 |
| /// |
| /// These variants of isUnique implicitly cast to a non-null NativeObject before |
| /// checking uniqueness. This allows an object reference statically typed as |
| /// BridgeObject to be treated as a native object by the runtime. |
| BUILTIN_SIL_OPERATION(IsUnique_native, "isUnique_native", Special) |
| |
| /// beginCOWMutation<T : AnyObject>(inout T) -> Int1 |
| /// |
| /// Begins a copy-on-write mutation for a buffer reference which is passed as |
| /// inout argument. It returns a true if the buffer is uniquely referenced. |
| /// In this case the buffer may be mutated after calling this builtin. |
| /// |
| /// The beginCOWMutation builtin is very similar to isUnique. It just translates |
| /// to a different SIL instruction (begin_cow_mutation), which is the preferred |
| /// representation of COW in SIL. |
| BUILTIN_SIL_OPERATION(BeginCOWMutation, "beginCOWMutation", Special) |
| |
| /// beginCOWMutation_native<T : AnyObject>(inout T) -> Int1 |
| /// |
| /// Like beginCOWMutation, but it's assumed that T has native Swift reference |
| /// counting. |
| BUILTIN_SIL_OPERATION(BeginCOWMutation_native, "beginCOWMutation_native", Special) |
| |
| /// endCOWMutation<T : AnyObject>(inout T) |
| /// |
| /// Ends a copy-on-write mutation for a buffer reference which is passed as |
| /// inout argument. After calling this builtin, the buffer must not be mutated. |
| BUILTIN_SIL_OPERATION(EndCOWMutation, "endCOWMutation", Special) |
| |
| /// bindMemory : <T> (Builtin.RawPointer, Builtin.Word, T.Type) -> () |
| BUILTIN_SIL_OPERATION(BindMemory, "bindMemory", Special) |
| |
| /// allocWithTailElems_<n>(C.Type, |
| /// Builtin.Word, E1.Type, ... , Builtin.Word, En.Type) -> C\ |
| /// |
| /// The integer suffix <n> specifies the number of tail-allocated arrays. |
| /// Each tail-allocated array adds a counter and an element meta-type parameter. |
| BUILTIN_SIL_OPERATION(AllocWithTailElems, "allocWithTailElems", Special) |
| |
| /// projectTailElems : <C,E> (C) -> Builtin.RawPointer |
| /// |
| /// Projects the first tail-allocated element of type E from a class C. |
| BUILTIN_SIL_OPERATION(ProjectTailElems, "projectTailElems", Special) |
| |
| /// Unsafely convert a value of type T to an unowned value. |
| /// |
| /// It has type (T, @inout @unowned(unsafe) T) -> (). The reason for the weird |
| /// signature is to work around issues with results in SILGen builtin emission. |
| BUILTIN_SIL_OPERATION(ConvertStrongToUnownedUnsafe, "convertStrongToUnownedUnsafe", Special) |
| |
| /// Unsafely convert a value of type @inout @unowned(unsafe) T to a loaded |
| /// guaranteed T value that has a lifetime guaranteed by the passed in base |
| /// value of type BaseTy. |
| /// |
| /// It has type (@in_guaranteed BaseTy, @in_guaranteed @unowned (unsafe) T) -> @guaranteed T. |
| /// |
| /// NOTE: Saying the result is a guaranteed T is a bit of a misnomer. We aren't |
| /// emitting a builtin call, but are just emitting SIL directly. |
| /// |
| /// NOTE: Even though the signature is as mentioned above, we actually tell the |
| /// AST we have the signature: |
| /// |
| /// <BaseT, T, U> (BaseT, T) -> U |
| /// |
| /// We then perform the actual type checking in SILGen and assert on |
| /// failure. This is an early, unsupported feature so this is sufficient for |
| /// now. |
| BUILTIN_SIL_OPERATION(ConvertUnownedUnsafeToGuaranteed, "convertUnownedUnsafeToGuaranteed", Special) |
| |
| /// applyDerivative |
| BUILTIN_SIL_OPERATION(ApplyDerivative, "applyDerivative", Special) |
| |
| /// applyTranspose |
| BUILTIN_SIL_OPERATION(ApplyTranspose, "applyTranspose", Special) |
| |
| /// differentiableFunction |
| BUILTIN_SIL_OPERATION(DifferentiableFunction, "differentiableFunction", Special) |
| |
| /// linearFunction |
| BUILTIN_SIL_OPERATION(LinearFunction, "linearFunction", Special) |
| |
| /// withUnsafeContinuation<T> : (Builtin.RawUnsafeContinuation -> ()) async -> T |
| /// |
| /// Unsafely capture the current continuation and pass it to the given |
| /// function value. Returns a value of type T when the continuation is |
| /// resumed. |
| BUILTIN_SIL_OPERATION(WithUnsafeContinuation, "withUnsafeContinuation", Special) |
| |
| /// withUnsafeThrowingContinuation<T> : (Builtin.RawUnsafeContinuation -> ()) async throws -> T |
| /// |
| /// Unsafely capture the current continuation and pass it to the given |
| /// function value. Returns a value of type T or throws an error when |
| /// the continuation is resumed. |
| BUILTIN_SIL_OPERATION(WithUnsafeThrowingContinuation, "withUnsafeThrowingContinuation", Special) |
| |
| #undef BUILTIN_SIL_OPERATION |
| |
| // BUILTIN_RUNTIME_CALL - A call into a runtime function. |
| // These functions accept a single argument of any type. |
| #ifndef BUILTIN_RUNTIME_CALL |
| #define BUILTIN_RUNTIME_CALL(Id, Name, Attrs) \ |
| BUILTIN(Id, Name, Attrs) |
| #endif |
| |
| /// unexpectedError: Error -> () |
| BUILTIN_RUNTIME_CALL(UnexpectedError, "unexpectedError", "") |
| |
| /// errorInMain: Error -> () |
| BUILTIN_RUNTIME_CALL(ErrorInMain, "errorInMain", "") |
| |
| /// IsOptionalType : T.Type -> Bool |
| /// This builtin takes a metatype and returns true if the metatype's |
| /// nominal type is Optional. |
| BUILTIN_RUNTIME_CALL(IsOptionalType, "isOptional", "") |
| |
| #undef BUILTIN_RUNTIME_CALL |
| |
| // BUILTIN_MISC_OPERATION - Miscellaneous operations without a unifying class. |
| // These have various types. |
| #ifndef BUILTIN_MISC_OPERATION |
| #define BUILTIN_MISC_OPERATION(Id, Name, Attrs, Overload) \ |
| BUILTIN(Id, Name, Attrs) |
| #endif |
| |
| /// condfail_message(Int1, RawPointer) -> () |
| /// Triggers a runtime failure if the condition is true. |
| BUILTIN_MISC_OPERATION(CondFailMessage, "condfail_message", "", Special) |
| |
| /// Sizeof has type T.Type -> Int |
| BUILTIN_MISC_OPERATION(Sizeof, "sizeof", "n", Special) |
| |
| /// Strideof has type T.Type -> Int |
| BUILTIN_MISC_OPERATION(Strideof, "strideof", "n", Special) |
| |
| /// IsPOD has type T.Type -> Bool |
| BUILTIN_MISC_OPERATION(IsPOD, "ispod", "n", Special) |
| |
| /// IsConcrete has type (T.Type) -> Bool |
| /// |
| /// If the meta type T is concrete, we can always transform this to `true` at |
| /// any time in SIL. If it's generic, then we lower it to `false` right before |
| /// IRGen in IRGenPrepare. This allows for the optimizer to specialize this at |
| /// -O and eliminate conditional code. |
| BUILTIN_MISC_OPERATION(IsConcrete, "isConcrete", "n", Special) |
| |
| /// IsBitwiseTakable has type T.Type -> Bool |
| BUILTIN_MISC_OPERATION(IsBitwiseTakable, "isbitwisetakable", "n", Special) |
| |
| /// IsSameMetatype has type (Any.Type, Any.Type) -> Bool |
| BUILTIN_MISC_OPERATION(IsSameMetatype, "is_same_metatype", "n", Special) |
| |
| /// Alignof has type T.Type -> Int |
| BUILTIN_MISC_OPERATION(Alignof, "alignof", "n", Special) |
| |
| /// AllocRaw has type (Int, Int) -> Builtin.RawPointer |
| /// |
| /// Parameters: object size, object alignment. |
| /// |
| /// This alignment is not a mask; the compiler decrements by one to provide |
| /// a mask to the runtime. |
| /// |
| /// If alignment == 0, then the runtime will use "aligned" allocation, |
| /// and the memory will be aligned to _swift_MinAllocationAlignment. |
| BUILTIN_MISC_OPERATION(AllocRaw, "allocRaw", "", Special) |
| |
| /// DeallocRaw has type (Builtin.RawPointer, Int, Int) -> () |
| /// |
| /// Parameters: object address, object size, object alignment. |
| /// |
| /// This alignment is not a mask; the compiler decrements by one to provide |
| /// a mask to the runtime. |
| /// |
| /// If alignment == 0, then the runtime will use the "aligned" deallocation |
| /// path, which assumes that "aligned" allocation was used. |
| /// |
| /// Note that the alignment value provided to `deallocRaw` must be identical to |
| /// the alignment value provided to `allocRaw` when the memory at this address |
| /// was allocated. |
| BUILTIN_MISC_OPERATION(DeallocRaw, "deallocRaw", "", Special) |
| |
| /// Fence has type () -> (). |
| BUILTIN_MISC_OPERATION(Fence, "fence", "", None) |
| |
| /// onFastPath has type () -> (). |
| BUILTIN_MISC_OPERATION(OnFastPath, "onFastPath", "n", None) |
| |
| /// CmpXChg has type (Builtin.RawPointer, T, T) -> (T, Bool). |
| BUILTIN_MISC_OPERATION(CmpXChg, "cmpxchg", "", Special) |
| |
| /// AtomicLoad has type (Builtin.RawPointer) -> T. |
| BUILTIN_MISC_OPERATION(AtomicLoad, "atomicload", "", Special) |
| |
| /// AtomicStore has type (Builtin.RawPointer, T) -> (). |
| BUILTIN_MISC_OPERATION(AtomicStore, "atomicstore", "", Special) |
| |
| /// AtomicRMW has type (Builtin.RawPointer, T) -> T. |
| BUILTIN_MISC_OPERATION(AtomicRMW, "atomicrmw", "", IntegerOrRawPointer) |
| |
| /// convertTaskToJob : (Builtin.NativePointer) -> Builtin.Job |
| /// |
| /// Convert a task pointer into a job pointer. |
| BUILTIN_MISC_OPERATION(ConvertTaskToJob, "convertTaskToJob", "n", Special) |
| |
| /// ExtractElement has type (Vector<N, T>, Int32) -> T |
| BUILTIN_MISC_OPERATION(ExtractElement, "extractelement", "n", Special) |
| |
| /// InsertElement has type (Vector<N, T>, T, Int32) -> Vector<N, T>. |
| BUILTIN_MISC_OPERATION(InsertElement, "insertelement", "n", Special) |
| |
| /// StaticReport has type (Builtin.Int1, Builtin.Int1, Builtin.RawPointer) -> () |
| BUILTIN_MISC_OPERATION(StaticReport, "staticReport", "", Special) |
| |
| /// assert_configuration has type () -> Builtin.Int32 |
| /// Returns the selected assertion configuration. |
| BUILTIN_MISC_OPERATION(AssertConf, "assert_configuration", "n", Special) |
| |
| /// StringObjectOr has type (T,T) -> T. |
| /// Sets bits in a string object. The first operand is bit-cast string literal |
| /// pointer to an integer. The second operand is the bit mask to be or'd into |
| /// the high bits of the pointer. |
| /// It is required that the or'd bits are all 0 in the first operand. So this |
| /// or-operation is actually equivalent to an addition. |
| BUILTIN_MISC_OPERATION(StringObjectOr, "stringObjectOr", "n", Integer) |
| |
| /// Special truncation builtins that check for sign and overflow errors. These |
| /// take an integer as an input and return a tuple of the truncated result and |
| /// an error bit. The name of each builtin is extended with the "from" |
| /// (sign-agnostic) builtin integer type and the "to" integer type. |
| /// We require the source type size to be larger than the destination type size |
| /// (number of bits). |
| BUILTIN_MISC_OPERATION(UToSCheckedTrunc, "u_to_s_checked_trunc", "n", Special) |
| BUILTIN_MISC_OPERATION(SToSCheckedTrunc, "s_to_s_checked_trunc", "n", Special) |
| BUILTIN_MISC_OPERATION(SToUCheckedTrunc, "s_to_u_checked_trunc", "n", Special) |
| BUILTIN_MISC_OPERATION(UToUCheckedTrunc, "u_to_u_checked_trunc", "n", Special) |
| |
| /// IntToFPWithOverflow has type (Integer) -> Float |
| BUILTIN_MISC_OPERATION(IntToFPWithOverflow, "itofp_with_overflow", "n", Special) |
| |
| // FIXME: shufflevector |
| |
| /// zeroInitializer has type <T> () -> T |
| BUILTIN_MISC_OPERATION(ZeroInitializer, "zeroInitializer", "n", Special) |
| |
| /// once has type (Builtin.RawPointer, () -> ()) |
| BUILTIN_MISC_OPERATION(Once, "once", "", Special) |
| /// onceWithContext has type (Builtin.RawPointer, (Builtin.RawPointer) -> (), Builtin.RawPointer) |
| BUILTIN_MISC_OPERATION(OnceWithContext, "onceWithContext", "", Special) |
| |
| /// unreachable has type () -> Never |
| BUILTIN_MISC_OPERATION(Unreachable, "unreachable", "", Special) |
| |
| /// conditionallyUnreachable has type () -> Never |
| BUILTIN_MISC_OPERATION(CondUnreachable, "conditionallyUnreachable", "", Special) |
| |
| /// DestroyArray has type (T.Type, Builtin.RawPointer, Builtin.Word) -> () |
| BUILTIN_MISC_OPERATION(DestroyArray, "destroyArray", "", Special) |
| |
| /// CopyArray, TakeArrayNoAlias, TakeArrayFrontToBack, and TakeArrayBackToFront |
| /// AssignCopyArrayNoAlias, AssignCopyArrayFrontToBack, |
| /// AssignCopyArrayBackToFront, AssignTakeArray all have type |
| /// (T.Type, Builtin.RawPointer, Builtin.RawPointer, Builtin.Word) -> () |
| BUILTIN_MISC_OPERATION(CopyArray, "copyArray", "", Special) |
| BUILTIN_MISC_OPERATION(TakeArrayNoAlias, "takeArrayNoAlias", "", Special) |
| BUILTIN_MISC_OPERATION(TakeArrayFrontToBack, "takeArrayFrontToBack", "", Special) |
| BUILTIN_MISC_OPERATION(TakeArrayBackToFront, "takeArrayBackToFront", "", Special) |
| BUILTIN_MISC_OPERATION(AssignCopyArrayNoAlias, "assignCopyArrayNoAlias", "", Special) |
| BUILTIN_MISC_OPERATION(AssignCopyArrayFrontToBack, "assignCopyArrayFrontToBack", "", Special) |
| BUILTIN_MISC_OPERATION(AssignCopyArrayBackToFront, "assignCopyArrayBackToFront", "", Special) |
| BUILTIN_MISC_OPERATION(AssignTakeArray, "assignTakeArray", "", Special) |
| |
| /// COWBufferForReading has type <T: AnyObject> T -> T |
| /// |
| /// Returns the buffer reference which is passed as argument. |
| /// This builtin indicates to the optimizer that the buffer is not mutable. |
| BUILTIN_MISC_OPERATION(COWBufferForReading, "COWBufferForReading", "n", Special) |
| |
| // unsafeGuaranteed has type <T: AnyObject> T -> (T, Builtin.Int8) |
| BUILTIN_MISC_OPERATION(UnsafeGuaranteed, "unsafeGuaranteed", "", Special) |
| |
| // unsafeGuaranteedEnd has type (Builtin.Int8) -> () |
| BUILTIN_MISC_OPERATION(UnsafeGuaranteedEnd, "unsafeGuaranteedEnd", "", Special) |
| |
| // getObjCTypeEncoding has type <T> T.Type -> RawPointer |
| BUILTIN_MISC_OPERATION(GetObjCTypeEncoding, "getObjCTypeEncoding", "n", Special) |
| |
| // Swift3ImplicitObjCEntrypoint has type () -> () |
| BUILTIN_MISC_OPERATION(Swift3ImplicitObjCEntrypoint, "swift3ImplicitObjCEntrypoint", "", Special) |
| |
| /// willThrow: Error -> () |
| BUILTIN_MISC_OPERATION(WillThrow, "willThrow", "", Special) |
| |
| /// poundAssert has type (Builtin.Int1, Builtin.RawPointer) -> (). |
| BUILTIN_MISC_OPERATION(PoundAssert, "poundAssert", "", Special) |
| |
| // TypePtrAuthDiscriminator has type <T> (T.Type) -> Int64 |
| BUILTIN_MISC_OPERATION(TypePtrAuthDiscriminator, "typePtrAuthDiscriminator", "n", Special) |
| |
| // int_instrprof_increment has type (Builtin.RawPointer, Builtin.Int64, Builtin.Int32, Builtin.Int32) -> (). |
| BUILTIN_MISC_OPERATION(IntInstrprofIncrement, "int_instrprof_increment", "", Special) |
| |
| /// Initialize the default-actor instance in a default actor object. |
| BUILTIN_MISC_OPERATION(InitializeDefaultActor, "initializeDefaultActor", "", Special) |
| |
| /// Destroy the default-actor instance in a default actor object. |
| BUILTIN_MISC_OPERATION(DestroyDefaultActor, "destroyDefaultActor", "", Special) |
| |
| // BUILTIN_MISC_OPERATION_WITH_SILGEN - Miscellaneous operations that are |
| // specially emitted during SIL generation. |
| // |
| // The intention is that this is meant for builtins that need a named |
| // builtin representation so one can create a builtin instruction in |
| // SIL, but that also need special SILGen behavior. If an operation |
| // just emits custom SIL and does not need to be able to form a |
| // builtin instruction, please use BUILTIN_SIL_OPERATION. |
| #ifndef BUILTIN_MISC_OPERATION_WITH_SILGEN |
| #define BUILTIN_MISC_OPERATION_WITH_SILGEN(Id, Name, Attrs, Overload) \ |
| BUILTIN_MISC_OPERATION(Id, Name, Attrs, Overload) |
| #endif |
| |
| // getCurrentAsyncTask: () -> Builtin.NativeObject |
| // |
| // Retrieve the pointer to the task in which the current asynchronous |
| // function is executing. |
| BUILTIN_MISC_OPERATION_WITH_SILGEN(GetCurrentAsyncTask, "getCurrentAsyncTask", "n", Special) |
| |
| /// cancelAsyncTask(): (Builtin.NativeObject) -> Void |
| /// |
| /// Cancel the given asynchronous task. |
| BUILTIN_MISC_OPERATION_WITH_SILGEN(CancelAsyncTask, "cancelAsyncTask", "", Special) |
| |
| /// createAsyncTask(): ( |
| /// Int, Builtin.NativeObject?, @escaping () async throws -> Void |
| /// ) -> Builtin.NativeObject |
| /// |
| /// Create a new asynchronous task, given flags, an (optional) parent task, and |
| /// a function to execute. |
| BUILTIN_MISC_OPERATION_WITH_SILGEN(CreateAsyncTask, "createAsyncTask", "", Special) |
| |
| /// createAsyncTaskFuture(): ( |
| /// Int, Builtin.NativeObject?, @escaping () async throws -> T |
| /// ) -> Builtin.NativeObject |
| /// |
| /// Create a new asynchronous task future, given flags, an (optional) parent |
| /// task and a function to execute. |
| BUILTIN_MISC_OPERATION_WITH_SILGEN(CreateAsyncTaskFuture, |
| "createAsyncTaskFuture", "", Special) |
| |
| /// globalStringTablePointer has type String -> Builtin.RawPointer. |
| /// It returns an immortal, global string table pointer for strings constructed |
| /// from string literals. We consider it effects as readnone meaning that it |
| /// does not read any memory (note that even though it reads from a string, it |
| /// is a pure value and therefore we can consider it as readnone). |
| BUILTIN_MISC_OPERATION_WITH_SILGEN(GlobalStringTablePointer, "globalStringTablePointer", "n", Special) |
| |
| // autoDiffCreateLinearMapContext: (Builtin.Word) -> Builtin.NativeObject |
| BUILTIN_MISC_OPERATION_WITH_SILGEN(AutoDiffCreateLinearMapContext, "autoDiffCreateLinearMapContext", "n", Special) |
| |
| // autoDiffProjectTopLevelSubcontext: (Builtin.NativeObject) -> Builtin.RawPointer |
| BUILTIN_MISC_OPERATION_WITH_SILGEN(AutoDiffProjectTopLevelSubcontext, "autoDiffProjectTopLevelSubcontext", "n", Special) |
| |
| // autoDiffAllocateSubcontext: (Builtin.NativeObject, Builtin.Word) -> Builtin.RawPointer |
| BUILTIN_MISC_OPERATION_WITH_SILGEN(AutoDiffAllocateSubcontext, "autoDiffAllocateSubcontext", "", Special) |
| |
| #undef BUILTIN_MISC_OPERATION_WITH_SILGEN |
| |
| #undef BUILTIN_MISC_OPERATION |
| |
| /// Builtins for instrumentation added by sanitizers during SILGen. |
| #ifndef BUILTIN_SANITIZER_OPERATION |
| #define BUILTIN_SANITIZER_OPERATION(Id, Name, Attrs) BUILTIN(Id, Name, Attrs) |
| #endif |
| |
| /// Builtin representing a call to Thread Sanitizer instrumentation. |
| /// TSanInoutAccess has type (T) -> () |
| BUILTIN_SANITIZER_OPERATION(TSanInoutAccess, "tsanInoutAccess", "") |
| |
| #undef BUILTIN_SANITIZER_OPERATION |
| |
| /// Builtins for compile-time type-checking operations used for unit testing. |
| #ifndef BUILTIN_TYPE_CHECKER_OPERATION |
| #define BUILTIN_TYPE_CHECKER_OPERATION(Id, Name) BUILTIN(Id, #Name, "n") |
| #endif |
| |
| BUILTIN_TYPE_CHECKER_OPERATION(TypeJoin, type_join) |
| BUILTIN_TYPE_CHECKER_OPERATION(TypeJoinInout, type_join_inout) |
| BUILTIN_TYPE_CHECKER_OPERATION(TypeJoinMeta, type_join_meta) |
| BUILTIN_TYPE_CHECKER_OPERATION(TriggerFallbackDiagnostic, trigger_fallback_diagnostic) |
| |
| #undef BUILTIN_TYPE_CHECKER_OPERATION |
| |
| // BUILTIN_TYPE_TRAIT_OPERATION - Compile-time type trait operations. |
| #ifndef BUILTIN_TYPE_TRAIT_OPERATION |
| #define BUILTIN_TYPE_TRAIT_OPERATION(Id, Name) \ |
| BUILTIN(Id, #Name, "n") |
| #endif |
| |
| /// canBeClass(T.Type) -> Builtin.Int8 |
| /// At compile time, evaluate whether T is or can be bound to a class or |
| /// @objc protocol type. The answer is a tri-state of 0 = No, 1 = Yes, 2 = |
| /// Maybe. |
| BUILTIN_TYPE_TRAIT_OPERATION(CanBeObjCClass, canBeClass) |
| |
| #undef BUILTIN_TYPE_TRAIT_OPERATION |
| |
| #undef BUILTIN |