//===--- SILNodes.def - Swift SIL Metaprogramming ---------------*- 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 macros used for macro-metaprogramming with SIL nodes.
//
//===----------------------------------------------------------------------===//

/// VALUE(Id, Parent)
///   The expression enumerator value is a ValueKind.  The node's class name is
///   Id, and the name of its base class (in the SILValue hierarchy) is Parent.
#ifndef VALUE
#define VALUE(Id, Parent)
#endif

/// ARGUMENT(Id, Parent)
///   The expression enumerator value is a ValueKind. The node's class name is
///   Id and the name of its base class (in the SILValue hierarchy) is Parent.
#ifndef ARGUMENT
#define ARGUMENT(Id, Parent) VALUE(Id, Parent)
#endif

/// INST(Id, Parent, TextualName, MemBehavior, MayRelease)
///
///   The expression enumerator value is a ValueKind.  The node's class name is
///   Id, and the name of its base class (in the SILInstruction hierarchy) is
///   Parent. TextualName is the textual name of the instruction. MemBehavior is
///   an enum value that reflects the memory behavior of the
///   instruction. MayRelease indicates whether the execution of the instruction
///   may result in memory being released.
#ifndef INST
#define INST(Id, Parent, TextualName, MemBehavior, MayRelease) VALUE(Id, Parent)
#endif

/// TERMINATOR(Id, Parent, TextualName, MemBehavior, MayRelease)
///   Expands for terminator instructions. The expression enumerator value is a
///   ValueKind.  The node's class name is Id, and the name of its base class
///   (in the SILInstruction hierarchy) is Parent. TextualName is the name of
///   the instruction in textual SIL.  MemBehavior is an enum value that
///   reflects the memory behavior of the instruction. MayRelease indicates
///   whether the execution of the instruction may result in memory being
///   released.
#ifndef TERMINATOR
#define TERMINATOR(Id, Parent, TextualName, MemBehavior, MayRelease)     \
      INST(Id, Parent, TextualName, MemBehavior, MayRelease)
#endif

/// An abstract value base is an abstract base class in the hierarchy; it is
/// never a most-derived type, and it does not have an enumerator in ValueKind.
///
/// Most metaprograms do not care about abstract expressions, so the default
/// is to ignore them.
#ifndef ABSTRACT_VALUE
#define ABSTRACT_VALUE(Id, Parent)
#endif

/// A convenience for determining the range of values.  These will always
/// appear immediately after the last member.
#ifndef VALUE_RANGE
#define VALUE_RANGE(Id, First, Last)
#endif

ABSTRACT_VALUE(SILArgument, ValueBase)
  ARGUMENT(SILPHIArgument, SILArgument)
  ARGUMENT(SILFunctionArgument, SILArgument)
  VALUE_RANGE(SILArgument, SILPHIArgument, SILFunctionArgument)

VALUE(SILUndef, ValueBase)

// Please keep the order of instructions consistent with the order of their
// descriptions in the SIL reference in docs/SIL.rst.

ABSTRACT_VALUE(SILInstruction, ValueBase)
  // Allocation instructions.
  ABSTRACT_VALUE(AllocationInst, SILInstruction)
    INST(AllocStackInst, AllocationInst, alloc_stack, None, DoesNotRelease)
    INST(AllocRefInst, AllocationInst, alloc_ref, None, DoesNotRelease)
    INST(AllocRefDynamicInst, AllocationInst, alloc_ref_dynamic, None, DoesNotRelease)
    INST(AllocValueBufferInst, AllocationInst, alloc_value_buffer, None, DoesNotRelease)
    INST(AllocBoxInst, AllocationInst, alloc_box, None, DoesNotRelease)
    INST(AllocExistentialBoxInst, AllocationInst, alloc_existential_box, MayWrite, DoesNotRelease)
    VALUE_RANGE(AllocationInst, AllocStackInst, AllocExistentialBoxInst)

  // Deallocation instructions.
  ABSTRACT_VALUE(DeallocationInst, SILInstruction)
    INST(DeallocStackInst, DeallocationInst, dealloc_stack, MayHaveSideEffects, DoesNotRelease)
    INST(DeallocRefInst, DeallocationInst, dealloc_ref, MayHaveSideEffects, DoesNotRelease)
    INST(DeallocPartialRefInst, DeallocationInst, dealloc_partial_ref, MayHaveSideEffects,
         DoesNotRelease)
    INST(DeallocValueBufferInst, DeallocationInst, dealloc_value_buffer, MayHaveSideEffects,
         DoesNotRelease)
    INST(DeallocBoxInst, DeallocationInst, dealloc_box, MayHaveSideEffects, DoesNotRelease)
    INST(DeallocExistentialBoxInst, DeallocationInst, dealloc_existential_box, MayHaveSideEffects,
         DoesNotRelease)
    VALUE_RANGE(DeallocationInst, DeallocStackInst, DeallocExistentialBoxInst)

  // Accessing memory
  INST(LoadInst, SILInstruction, load, MayRead, DoesNotRelease)
  INST(LoadBorrowInst, SILInstruction, load_borrow, MayRead, DoesNotRelease)
  INST(BeginBorrowInst, SILInstruction, begin_borrow, MayHaveSideEffects, DoesNotRelease)
  INST(EndBorrowInst, SILInstruction, end_borrow, MayHaveSideEffects, DoesNotRelease)
  INST(EndBorrowArgumentInst, SILInstruction, end_borrow_argument, MayHaveSideEffects, DoesNotRelease)
  INST(BeginAccessInst, SILInstruction, begin_access, MayHaveSideEffects, DoesNotRelease)
  INST(EndAccessInst, SILInstruction, end_access, MayHaveSideEffects, DoesNotRelease)
  INST(BeginUnpairedAccessInst, SILInstruction, begin_unpaired_access, MayHaveSideEffects, DoesNotRelease)
  INST(EndUnpairedAccessInst, SILInstruction, end_unpaired_access, MayHaveSideEffects, DoesNotRelease)
  INST(LoadUnownedInst, SILInstruction, load_unowned, MayRead, DoesNotRelease)
  INST(LoadWeakInst, SILInstruction, load_weak, MayRead, DoesNotRelease)
  INST(StoreInst, SILInstruction, store, MayWrite, DoesNotRelease)
  INST(StoreBorrowInst, SILInstruction, store_borrow, MayWrite, DoesNotRelease)
  INST(AssignInst, SILInstruction, assign, MayWrite, DoesNotRelease)
  INST(MarkUninitializedInst, SILInstruction, mark_uninitialized, None, DoesNotRelease)
  INST(MarkUninitializedBehaviorInst, SILInstruction, mark_uninitialized_behavior, None, DoesNotRelease)
  INST(MarkFunctionEscapeInst, SILInstruction, mark_function_escape, None, DoesNotRelease)
  INST(DebugValueInst, SILInstruction, debug_value, None, DoesNotRelease)
  INST(DebugValueAddrInst, SILInstruction, debug_value_addr, None, DoesNotRelease)
  INST(StoreUnownedInst, SILInstruction, store_unowned, MayWrite, DoesNotRelease)
  INST(StoreWeakInst, SILInstruction, store_weak, MayWrite, DoesNotRelease)
  INST(CopyAddrInst, SILInstruction, copy_addr, MayHaveSideEffects, MayRelease)
  INST(DestroyAddrInst, SILInstruction, destroy_addr, MayHaveSideEffects, MayRelease)
  INST(ProjectValueBufferInst, SILInstruction, project_value_buffer, MayRead, DoesNotRelease)
  INST(ProjectBoxInst, SILInstruction, project_box, None, DoesNotRelease)
  INST(ProjectExistentialBoxInst, SILInstruction, project_existential_box, None, DoesNotRelease)
  ABSTRACT_VALUE(IndexingInst, SILInstruction)
    INST(IndexAddrInst, IndexingInst, index_addr, None, DoesNotRelease)
    INST(TailAddrInst, IndexingInst, tail_addr, None, DoesNotRelease)
    INST(IndexRawPointerInst, IndexingInst, index_raw_pointer, None, DoesNotRelease)
    VALUE_RANGE(IndexingInst, IndexAddrInst, IndexRawPointerInst)

  // BindMemory has no physical side effect. Semantically it writes to
  // its affected memory region because any reads or writes accessing
  // that memory must be dependent on the bind operation.
  INST(BindMemoryInst, SILInstruction, bind_memory, MayWrite, DoesNotRelease)

  // Reference Counting
  ABSTRACT_VALUE(RefCountingInst, SILInstruction)
    INST(StrongRetainInst, RefCountingInst, strong_retain, MayHaveSideEffects, DoesNotRelease)
    INST(StrongReleaseInst, RefCountingInst, strong_release, MayHaveSideEffects, MayRelease)
    INST(StrongRetainUnownedInst, RefCountingInst, strong_retain_unowned, MayHaveSideEffects,
         DoesNotRelease)
    INST(StrongPinInst, SILInstruction, strong_pin, MayHaveSideEffects, DoesNotRelease)
    INST(StrongUnpinInst, SILInstruction, strong_unpin, MayHaveSideEffects, DoesNotRelease)
    INST(UnownedRetainInst, RefCountingInst, unowned_retain, MayHaveSideEffects, DoesNotRelease)
    INST(UnownedReleaseInst, RefCountingInst, unowned_release, MayHaveSideEffects,
         MayRelease)
    INST(RetainValueInst, RefCountingInst, retain_value, MayHaveSideEffects, DoesNotRelease)
    INST(ReleaseValueInst, RefCountingInst, release_value, MayHaveSideEffects, MayRelease)
    INST(SetDeallocatingInst, RefCountingInst, set_deallocating, MayHaveSideEffects,
         DoesNotRelease)
    INST(AutoreleaseValueInst, RefCountingInst, autorelease_value, MayHaveSideEffects,
         DoesNotRelease)
    VALUE_RANGE(RefCountingInst, StrongRetainInst, AutoreleaseValueInst)
  // FIXME: Is MayHaveSideEffects appropriate?
  INST(FixLifetimeInst, SILInstruction, fix_lifetime, MayHaveSideEffects, DoesNotRelease)
  INST(MarkDependenceInst, SILInstruction, mark_dependence, None, DoesNotRelease)
  INST(CopyBlockInst, SILInstruction, copy_block, MayHaveSideEffects, DoesNotRelease)
  INST(CopyValueInst, SILInstruction, copy_value, MayHaveSideEffects, DoesNotRelease)
  INST(UnmanagedRetainValueInst, RefCountingInst, unmanaged_retain_value, MayHaveSideEffects, DoesNotRelease)
  INST(UnmanagedReleaseValueInst, RefCountingInst, unmanaged_release_value, MayHaveSideEffects, MayRelease)
  INST(UnmanagedAutoreleaseValueInst, RefCountingInst, unmanaged_autorelease_value, MayHaveSideEffects, DoesNotRelease)
  INST(CopyUnownedValueInst, SILInstruction, copy_unowned_value, MayHaveSideEffects, DoesNotRelease)
  INST(DestroyValueInst, SILInstruction, destroy_value, MayHaveSideEffects, MayRelease)
  INST(EndLifetimeInst, SILInstruction, end_lifetime, MayHaveSideEffects, MayRelease)
  INST(UncheckedOwnershipConversionInst, SILInstruction, unchecked_ownership_conversion, MayHaveSideEffects, MayRelease)

  // IsUnique does not actually write to memory but should be modeled
  // as such. Its operand is a pointer to an object reference. The
  // optimizer should not assume that the same object is pointed to after
  // the isUnique instruction. It appears to write a new object reference.
  INST(IsUniqueInst, SILInstruction, is_unique, MayHaveSideEffects, DoesNotRelease)
  INST(IsUniqueOrPinnedInst, SILInstruction, is_unique_or_pinned, MayHaveSideEffects, DoesNotRelease)

  INST(AllocGlobalInst, SILInstruction, alloc_global, MayHaveSideEffects, DoesNotRelease)

  // Literals
  ABSTRACT_VALUE(LiteralInst, SILInstruction)
    INST(FunctionRefInst, LiteralInst, function_ref, None, DoesNotRelease)
    INST(GlobalAddrInst, LiteralInst, global_addr, None, DoesNotRelease)
    INST(IntegerLiteralInst, LiteralInst, integer_literal, None, DoesNotRelease)
    INST(FloatLiteralInst, LiteralInst, float_literal, None, DoesNotRelease)
    INST(StringLiteralInst, LiteralInst, string_literal, None, DoesNotRelease)
    INST(ConstStringLiteralInst, LiteralInst, const_string_literal, None, DoesNotRelease)
    VALUE_RANGE(LiteralInst, FunctionRefInst, ConstStringLiteralInst)

  // Dynamic Dispatch
  ABSTRACT_VALUE(MethodInst, SILInstruction)
    INST(ClassMethodInst, MethodInst, class_method, None, DoesNotRelease)
    INST(SuperMethodInst, MethodInst, super_method, None, DoesNotRelease)
    INST(WitnessMethodInst, MethodInst, witness_method, None, DoesNotRelease)
    INST(DynamicMethodInst, MethodInst, dynamic_method, None, DoesNotRelease)
    VALUE_RANGE(MethodInst, ClassMethodInst, DynamicMethodInst)

  // Function Application
  INST(ApplyInst, SILInstruction, apply, MayHaveSideEffects, MayRelease)
  INST(PartialApplyInst, SILInstruction, partial_apply, MayHaveSideEffects, DoesNotRelease)
  INST(BuiltinInst, SILInstruction, builtin, MayHaveSideEffects, MayRelease)

  // Metatypes
  INST(MetatypeInst, SILInstruction, metatype, None, DoesNotRelease)
  INST(ValueMetatypeInst, SILInstruction, value_metatype, MayRead, DoesNotRelease)
  INST(ExistentialMetatypeInst, SILInstruction, existential_metatype, MayRead, DoesNotRelease)
  INST(ObjCProtocolInst, SILInstruction, objc_protocol, None, DoesNotRelease)

  // Aggregate Types
  INST(TupleInst, SILInstruction, tuple, None, DoesNotRelease)
  INST(TupleExtractInst, SILInstruction, tuple_extract, None, DoesNotRelease)
  INST(TupleElementAddrInst, SILInstruction, tuple_element_addr, None, DoesNotRelease)
  INST(StructInst, SILInstruction, struct, None, DoesNotRelease)
  INST(StructExtractInst, SILInstruction, struct_extract, None, DoesNotRelease)
  INST(StructElementAddrInst, SILInstruction, struct_element_addr, None, DoesNotRelease)
  INST(RefElementAddrInst, SILInstruction, ref_element_addr, None, DoesNotRelease)
  INST(RefTailAddrInst, SILInstruction, ref_tail_addr, None, DoesNotRelease)

  // Enums
  INST(EnumInst, SILInstruction, enum, None, DoesNotRelease)
  INST(UncheckedEnumDataInst, SILInstruction, unchecked_enum_data, None, DoesNotRelease)
  INST(InitEnumDataAddrInst, SILInstruction, init_enum_data_addr, None, DoesNotRelease)
  INST(UncheckedTakeEnumDataAddrInst, SILInstruction, unchecked_take_enum_data_addr, MayWrite, DoesNotRelease)
  INST(InjectEnumAddrInst, SILInstruction, inject_enum_addr, MayWrite, DoesNotRelease)
  INST(SelectEnumInst, SILInstruction, select_enum, None, DoesNotRelease)
  INST(SelectEnumAddrInst, SILInstruction, select_enum_addr, MayRead, DoesNotRelease)
  INST(SelectValueInst, SILInstruction, select_value, None, DoesNotRelease)

  // Protocol and Protocol Composition Types
  INST(InitExistentialAddrInst, SILInstruction, init_existential_addr, MayWrite, DoesNotRelease)
  INST(InitExistentialOpaqueInst, SILInstruction, init_existential_opaque, MayWrite, DoesNotRelease)
  INST(DeinitExistentialAddrInst, SILInstruction, deinit_existential_addr, MayHaveSideEffects,
       DoesNotRelease)
  INST(DeinitExistentialOpaqueInst, SILInstruction, deinit_existential_opaque, MayHaveSideEffects,
       DoesNotRelease)
  INST(OpenExistentialAddrInst, SILInstruction, open_existential_addr, MayRead, DoesNotRelease)
  INST(InitExistentialRefInst, SILInstruction, init_existential_ref, None, DoesNotRelease)
  INST(OpenExistentialRefInst, SILInstruction, open_existential_ref, None, DoesNotRelease)
  INST(InitExistentialMetatypeInst, SILInstruction, init_existential_metatype, None, DoesNotRelease)
  INST(OpenExistentialMetatypeInst, SILInstruction, open_existential_metatype, None, DoesNotRelease)
  INST(OpenExistentialBoxInst, SILInstruction, open_existential_box, MayRead, DoesNotRelease)
  INST(OpenExistentialOpaqueInst, SILInstruction, open_existential_opaque, MayRead, DoesNotRelease)

  // Blocks
  INST(ProjectBlockStorageInst, SILInstruction, project_block_storage, None, DoesNotRelease)
  INST(InitBlockStorageHeaderInst, SILInstruction, init_block_storage_header, None, DoesNotRelease)

  // Key paths
  INST(KeyPathInst, SILInstruction, keypath, None, DoesNotRelease)

  // Conversions
  ABSTRACT_VALUE(ConversionInst, SILInstruction)
    INST(UpcastInst, ConversionInst, upcast, None, DoesNotRelease)
    INST(AddressToPointerInst, ConversionInst, address_to_pointer, None, DoesNotRelease)
    INST(PointerToAddressInst, ConversionInst, pointer_to_address, None, DoesNotRelease)
    INST(UncheckedRefCastInst, ConversionInst, unchecked_ref_cast, None, DoesNotRelease)
    INST(UncheckedAddrCastInst, ConversionInst, unchecked_addr_cast, None, DoesNotRelease)
    INST(UncheckedTrivialBitCastInst, ConversionInst, unchecked_trivial_bit_cast, None, DoesNotRelease)
    INST(UncheckedBitwiseCastInst, ConversionInst, unchecked_bitwise_cast, None, DoesNotRelease)
    INST(RefToRawPointerInst, ConversionInst, ref_to_raw_pointer, None, DoesNotRelease)
    INST(RawPointerToRefInst, ConversionInst, raw_pointer_to_ref, None, DoesNotRelease)
    INST(RefToUnownedInst, ConversionInst, ref_to_unowned, None, DoesNotRelease)
    INST(UnownedToRefInst, ConversionInst, unowned_to_ref, None, DoesNotRelease)
    INST(RefToUnmanagedInst, ConversionInst, ref_to_unmanaged, None, DoesNotRelease)
    INST(UnmanagedToRefInst, ConversionInst, unmanaged_to_ref, None, DoesNotRelease)
    INST(ConvertFunctionInst, ConversionInst, convert_function, None, DoesNotRelease)
    INST(ThinFunctionToPointerInst, ConversionInst, thin_function_to_pointer, None, DoesNotRelease)
    INST(PointerToThinFunctionInst, ConversionInst, pointer_to_thin_function, None, DoesNotRelease)
    INST(RefToBridgeObjectInst, ConversionInst, ref_to_bridge_object, None, DoesNotRelease)
    INST(BridgeObjectToRefInst, ConversionInst, bridge_object_to_ref, None, DoesNotRelease)
    INST(BridgeObjectToWordInst, ConversionInst, bridge_object_to_word, None, DoesNotRelease)
    INST(ThinToThickFunctionInst, ConversionInst, thin_to_thick_function, None, DoesNotRelease)
    INST(ThickToObjCMetatypeInst, ConversionInst, thick_to_objc_metatype, None, DoesNotRelease)
    INST(ObjCToThickMetatypeInst, ConversionInst, objc_to_thick_metatype, None, DoesNotRelease)
    INST(ObjCMetatypeToObjectInst, ConversionInst, objc_metatype_to_object, None, DoesNotRelease)
    INST(ObjCExistentialMetatypeToObjectInst, ConversionInst, objc_existential_metatype_to_object, None,
         DoesNotRelease)
    INST(UnconditionalCheckedCastValueInst, ConversionInst, unconditional_checked_cast_value, None, DoesNotRelease)
    INST(UnconditionalCheckedCastInst, ConversionInst, unconditional_checked_cast, None, DoesNotRelease)
    VALUE_RANGE(ConversionInst, UpcastInst, UnconditionalCheckedCastInst)
  INST(IsNonnullInst, SILInstruction, is_nonnull, None, DoesNotRelease)
  INST(UnconditionalCheckedCastAddrInst, SILInstruction, unconditional_checked_cast_addr, MayHaveSideEffects,
       MayRelease)
  INST(UncheckedRefCastAddrInst, SILInstruction, unchecked_ref_cast_addr, MayHaveSideEffects,
       DoesNotRelease)

  // Runtime failure
  // FIXME: Special MemBehavior for runtime failure?
  INST(CondFailInst, SILInstruction, cond_fail, MayHaveSideEffects, DoesNotRelease)

  // Terminators
  ABSTRACT_VALUE(TermInst, SILInstruction)
    TERMINATOR(UnreachableInst, TermInst, unreachable, None, DoesNotRelease)
    TERMINATOR(ReturnInst, TermInst, return, None, DoesNotRelease)
    TERMINATOR(ThrowInst, TermInst, throw, None, DoesNotRelease)
    TERMINATOR(TryApplyInst, TermInst, try_apply, MayHaveSideEffects, MayRelease)
    TERMINATOR(BranchInst, TermInst, br, None, DoesNotRelease)
    TERMINATOR(CondBranchInst, TermInst, cond_br, None, DoesNotRelease)
    TERMINATOR(SwitchValueInst, TermInst, switch_value, None, DoesNotRelease)
    TERMINATOR(SwitchEnumInst, TermInst, switch_enum, None, DoesNotRelease)
    TERMINATOR(SwitchEnumAddrInst, TermInst, switch_enum_addr, MayRead, DoesNotRelease)
    TERMINATOR(DynamicMethodBranchInst, TermInst, dynamic_method_br, None, DoesNotRelease)
    TERMINATOR(CheckedCastBranchInst, TermInst, checked_cast_br, None, DoesNotRelease)
    TERMINATOR(CheckedCastAddrBranchInst, TermInst, checked_cast_addr_br, MayHaveSideEffects,
               MayRelease)
    TERMINATOR(CheckedCastValueBranchInst, TermInst, checked_cast_value_br, None, DoesNotRelease)
    VALUE_RANGE(TermInst, UnreachableInst, CheckedCastValueBranchInst)

  VALUE_RANGE(SILInstruction, AllocStackInst, CheckedCastValueBranchInst)

#undef VALUE_RANGE
#undef ABSTRACT_VALUE
#undef TERMINATOR
#undef INST
#undef ARGUMENT
#undef VALUE
