// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef V8_COMPILER_BACKEND_INSTRUCTION_CODES_H_
#define V8_COMPILER_BACKEND_INSTRUCTION_CODES_H_

#include <iosfwd>

#if V8_TARGET_ARCH_ARM
#include "src/compiler/backend/arm/instruction-codes-arm.h"
#elif V8_TARGET_ARCH_ARM64
#include "src/compiler/backend/arm64/instruction-codes-arm64.h"
#elif V8_TARGET_ARCH_IA32
#include "src/compiler/backend/ia32/instruction-codes-ia32.h"
#elif V8_TARGET_ARCH_MIPS
#include "src/compiler/backend/mips/instruction-codes-mips.h"
#elif V8_TARGET_ARCH_MIPS64
#include "src/compiler/backend/mips64/instruction-codes-mips64.h"
#elif V8_TARGET_ARCH_X64
#include "src/compiler/backend/x64/instruction-codes-x64.h"
#elif V8_TARGET_ARCH_PPC
#include "src/compiler/backend/ppc/instruction-codes-ppc.h"
#elif V8_TARGET_ARCH_S390
#include "src/compiler/backend/s390/instruction-codes-s390.h"
#else
#define TARGET_ARCH_OPCODE_LIST(V)
#define TARGET_ADDRESSING_MODE_LIST(V)
#endif
#include "src/compiler/write-barrier-kind.h"
#include "src/utils/utils.h"

namespace v8 {
namespace internal {
namespace compiler {

// Modes for ArchStoreWithWriteBarrier below.
enum class RecordWriteMode {
  kValueIsMap,
  kValueIsPointer,
  kValueIsEphemeronKey,
  kValueIsAny,
};

inline RecordWriteMode WriteBarrierKindToRecordWriteMode(
    WriteBarrierKind write_barrier_kind) {
  switch (write_barrier_kind) {
    case kMapWriteBarrier:
      return RecordWriteMode::kValueIsMap;
    case kPointerWriteBarrier:
      return RecordWriteMode::kValueIsPointer;
    case kEphemeronKeyWriteBarrier:
      return RecordWriteMode::kValueIsEphemeronKey;
    case kFullWriteBarrier:
      return RecordWriteMode::kValueIsAny;
    case kNoWriteBarrier:
    // Should not be passed as argument.
    default:
      break;
  }
  UNREACHABLE();
}

// Target-specific opcodes that specify which assembly sequence to emit.
// Most opcodes specify a single instruction.
#define COMMON_ARCH_OPCODE_LIST(V)        \
  V(ArchCallCodeObject)                   \
  V(ArchTailCallCodeObjectFromJSFunction) \
  V(ArchTailCallCodeObject)               \
  V(ArchCallJSFunction)                   \
  V(ArchTailCallAddress)                  \
  V(ArchPrepareCallCFunction)             \
  V(ArchSaveCallerRegisters)              \
  V(ArchRestoreCallerRegisters)           \
  V(ArchCallCFunction)                    \
  V(ArchPrepareTailCall)                  \
  V(ArchCallWasmFunction)                 \
  V(ArchTailCallWasm)                     \
  V(ArchCallBuiltinPointer)               \
  V(ArchJmp)                              \
  V(ArchBinarySearchSwitch)               \
  V(ArchLookupSwitch)                     \
  V(ArchTableSwitch)                      \
  V(ArchNop)                              \
  V(ArchAbortCSAAssert)                   \
  V(ArchDebugBreak)                       \
  V(ArchComment)                          \
  V(ArchThrowTerminator)                  \
  V(ArchDeoptimize)                       \
  V(ArchRet)                              \
  V(ArchFramePointer)                     \
  V(ArchParentFramePointer)               \
  V(ArchTruncateDoubleToI)                \
  V(ArchStoreWithWriteBarrier)            \
  V(ArchStackSlot)                        \
  V(ArchWordPoisonOnSpeculation)          \
  V(ArchStackPointerGreaterThan)          \
  V(Word32AtomicLoadInt8)                 \
  V(Word32AtomicLoadUint8)                \
  V(Word32AtomicLoadInt16)                \
  V(Word32AtomicLoadUint16)               \
  V(Word32AtomicLoadWord32)               \
  V(Word32AtomicStoreWord8)               \
  V(Word32AtomicStoreWord16)              \
  V(Word32AtomicStoreWord32)              \
  V(Word32AtomicExchangeInt8)             \
  V(Word32AtomicExchangeUint8)            \
  V(Word32AtomicExchangeInt16)            \
  V(Word32AtomicExchangeUint16)           \
  V(Word32AtomicExchangeWord32)           \
  V(Word32AtomicCompareExchangeInt8)      \
  V(Word32AtomicCompareExchangeUint8)     \
  V(Word32AtomicCompareExchangeInt16)     \
  V(Word32AtomicCompareExchangeUint16)    \
  V(Word32AtomicCompareExchangeWord32)    \
  V(Word32AtomicAddInt8)                  \
  V(Word32AtomicAddUint8)                 \
  V(Word32AtomicAddInt16)                 \
  V(Word32AtomicAddUint16)                \
  V(Word32AtomicAddWord32)                \
  V(Word32AtomicSubInt8)                  \
  V(Word32AtomicSubUint8)                 \
  V(Word32AtomicSubInt16)                 \
  V(Word32AtomicSubUint16)                \
  V(Word32AtomicSubWord32)                \
  V(Word32AtomicAndInt8)                  \
  V(Word32AtomicAndUint8)                 \
  V(Word32AtomicAndInt16)                 \
  V(Word32AtomicAndUint16)                \
  V(Word32AtomicAndWord32)                \
  V(Word32AtomicOrInt8)                   \
  V(Word32AtomicOrUint8)                  \
  V(Word32AtomicOrInt16)                  \
  V(Word32AtomicOrUint16)                 \
  V(Word32AtomicOrWord32)                 \
  V(Word32AtomicXorInt8)                  \
  V(Word32AtomicXorUint8)                 \
  V(Word32AtomicXorInt16)                 \
  V(Word32AtomicXorUint16)                \
  V(Word32AtomicXorWord32)                \
  V(Ieee754Float64Acos)                   \
  V(Ieee754Float64Acosh)                  \
  V(Ieee754Float64Asin)                   \
  V(Ieee754Float64Asinh)                  \
  V(Ieee754Float64Atan)                   \
  V(Ieee754Float64Atanh)                  \
  V(Ieee754Float64Atan2)                  \
  V(Ieee754Float64Cbrt)                   \
  V(Ieee754Float64Cos)                    \
  V(Ieee754Float64Cosh)                   \
  V(Ieee754Float64Exp)                    \
  V(Ieee754Float64Expm1)                  \
  V(Ieee754Float64Log)                    \
  V(Ieee754Float64Log1p)                  \
  V(Ieee754Float64Log10)                  \
  V(Ieee754Float64Log2)                   \
  V(Ieee754Float64Pow)                    \
  V(Ieee754Float64Sin)                    \
  V(Ieee754Float64Sinh)                   \
  V(Ieee754Float64Tan)                    \
  V(Ieee754Float64Tanh)

#define ARCH_OPCODE_LIST(V)  \
  COMMON_ARCH_OPCODE_LIST(V) \
  TARGET_ARCH_OPCODE_LIST(V)

enum ArchOpcode {
#define DECLARE_ARCH_OPCODE(Name) k##Name,
  ARCH_OPCODE_LIST(DECLARE_ARCH_OPCODE)
#undef DECLARE_ARCH_OPCODE
#define COUNT_ARCH_OPCODE(Name) +1
      kLastArchOpcode = -1 ARCH_OPCODE_LIST(COUNT_ARCH_OPCODE)
#undef COUNT_ARCH_OPCODE
};

V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
                                           const ArchOpcode& ao);

// Addressing modes represent the "shape" of inputs to an instruction.
// Many instructions support multiple addressing modes. Addressing modes
// are encoded into the InstructionCode of the instruction and tell the
// code generator after register allocation which assembler method to call.
#define ADDRESSING_MODE_LIST(V) \
  V(None)                       \
  TARGET_ADDRESSING_MODE_LIST(V)

enum AddressingMode {
#define DECLARE_ADDRESSING_MODE(Name) kMode_##Name,
  ADDRESSING_MODE_LIST(DECLARE_ADDRESSING_MODE)
#undef DECLARE_ADDRESSING_MODE
#define COUNT_ADDRESSING_MODE(Name) +1
      kLastAddressingMode = -1 ADDRESSING_MODE_LIST(COUNT_ADDRESSING_MODE)
#undef COUNT_ADDRESSING_MODE
};

V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
                                           const AddressingMode& am);

// The mode of the flags continuation (see below).
enum FlagsMode {
  kFlags_none = 0,
  kFlags_branch = 1,
  kFlags_branch_and_poison = 2,
  kFlags_deoptimize = 3,
  kFlags_deoptimize_and_poison = 4,
  kFlags_set = 5,
  kFlags_trap = 6
};

V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
                                           const FlagsMode& fm);

// The condition of flags continuation (see below).
enum FlagsCondition {
  kEqual,
  kNotEqual,
  kSignedLessThan,
  kSignedGreaterThanOrEqual,
  kSignedLessThanOrEqual,
  kSignedGreaterThan,
  kUnsignedLessThan,
  kUnsignedGreaterThanOrEqual,
  kUnsignedLessThanOrEqual,
  kUnsignedGreaterThan,
  kFloatLessThanOrUnordered,
  kFloatGreaterThanOrEqual,
  kFloatLessThanOrEqual,
  kFloatGreaterThanOrUnordered,
  kFloatLessThan,
  kFloatGreaterThanOrEqualOrUnordered,
  kFloatLessThanOrEqualOrUnordered,
  kFloatGreaterThan,
  kUnorderedEqual,
  kUnorderedNotEqual,
  kOverflow,
  kNotOverflow,
  kPositiveOrZero,
  kNegative
};

static constexpr FlagsCondition kStackPointerGreaterThanCondition =
    kUnsignedGreaterThan;

inline FlagsCondition NegateFlagsCondition(FlagsCondition condition) {
  return static_cast<FlagsCondition>(condition ^ 1);
}

FlagsCondition CommuteFlagsCondition(FlagsCondition condition);

V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
                                           const FlagsCondition& fc);

enum MemoryAccessMode {
  kMemoryAccessDirect = 0,
  kMemoryAccessProtected = 1,
  kMemoryAccessPoisoned = 2
};

// The InstructionCode is an opaque, target-specific integer that encodes
// what code to emit for an instruction in the code generator. It is not
// interesting to the register allocator, as the inputs and flags on the
// instructions specify everything of interest.
using InstructionCode = int32_t;

// Helpers for encoding / decoding InstructionCode into the fields needed
// for code generation. We encode the instruction, addressing mode, and flags
// continuation into a single InstructionCode which is stored as part of
// the instruction.
using ArchOpcodeField = BitField<ArchOpcode, 0, 9>;
using AddressingModeField = BitField<AddressingMode, 9, 5>;
using FlagsModeField = BitField<FlagsMode, 14, 3>;
using FlagsConditionField = BitField<FlagsCondition, 17, 5>;
using MiscField = BitField<int, 22, 10>;

}  // namespace compiler
}  // namespace internal
}  // namespace v8

#endif  // V8_COMPILER_BACKEND_INSTRUCTION_CODES_H_
