/*
 * Copyright (C) 2018-2020 Western Digital Corporation or its affiliates
 * Copyright (C) 2017-2018 Wearable, Inc.
 * Copyright (C) 2000-2012 leJOS Contributors
 * Copyright (C) 2000 Jose H. Solorzano and TinyVM Contributors
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 * 
 * This Source Code Form is “Incompatible With Secondary Licenses”,
 * as defined by the Mozilla Public License, v. 2.0.
 */

/**
 * This is included inside a switch statement.
 */

OPCODE(OP_ISUB)
  // Arguments: 0
  // Stack: -2 +1
  {
    STACKWORD tempStackWord = pop_word();
    just_set_top_word (get_top_word() - tempStackWord);
  }
  DISPATCH;

OPCODE(OP_IADD)
  // Arguments: 0
  // Stack: -2 +1
  {
    STACKWORD tempStackWord = pop_word();
    just_set_top_word (get_top_word() + tempStackWord);
  }
  DISPATCH;

OPCODE(OP_IMUL)
  // Arguments: 0
  // Stack: -2 +1
  {
    STACKWORD tempStackWord = pop_word();
    just_set_top_word (get_top_word() * tempStackWord);
  }
  DISPATCH;

// FIXME: UB on -2^31 / -1 ?

OPCODE(OP_IDIV)
OPCODE(OP_IREM)
  {
    int tempInt = word2jint(pop_word());
    if (tempInt == 0) {
      goto LABEL_THROW_ARITHMETIC_EXCEPTION;
    }
    just_set_top_word ((*(pc-1) == OP_IDIV) ? word2jint(get_top_word()) / tempInt :
                                              word2jint(get_top_word()) % tempInt);
  }
  DISPATCH;

OPCODE(OP_INEG)
  just_set_top_word (-get_top_word());
  DISPATCH;

#if FP_ARITHMETIC

OPCODE(OP_FSUB)
  {
    STACKWORD tempStackWord = pop_word();
    just_set_top_word (jfloat2word(word2jfloat(get_top_word()) - 
                      word2jfloat(tempStackWord)));
  }
  DISPATCH;

OPCODE(OP_FADD)
  {
    STACKWORD tempStackWord = pop_word();
    just_set_top_word (jfloat2word(word2jfloat(get_top_word()) + 
                      word2jfloat(tempStackWord)));
  }
  DISPATCH;

OPCODE(OP_FMUL)
  {
    STACKWORD tempStackWord = pop_word();
    just_set_top_word (jfloat2word(word2jfloat(get_top_word()) * 
                      word2jfloat(tempStackWord)));
  }
  DISPATCH;

OPCODE(OP_FDIV)
  // TBD: no division by zero?
  {
    STACKWORD tempStackWord = pop_word();
    just_set_top_word (jfloat2word(word2jfloat(get_top_word()) / 
                      word2jfloat(tempStackWord)));
  }
  DISPATCH;

OPCODE(OP_FNEG)
  just_set_top_word (jfloat2word(-word2jfloat(get_top_word())));
  DISPATCH;

OPCODE(OP_FREM)
  {
    STACKWORD tempStackWord = pop_word();
    just_set_top_word(jfloat2word((float)fmodf(word2jfloat(get_top_word()), word2jfloat(tempStackWord))));
  }
  DISPATCH;

#endif // FP_ARITHMETIC

#if FP_DOUBLE_ARITHMETIC

OPCODE(OP_DNEG)
  {
    JDOUBLE d1;
    pop_jdouble(&d1);
    d1 = -d1;
    push_jdouble(&d1);
  }
  DISPATCH;

OPCODE(OP_DSUB)
  {
    JDOUBLE d1, d2;
    pop_jdouble(&d1);
    pop_jdouble(&d2);
    d2 -= d1;
    push_jdouble(&d2);
  }
  DISPATCH;

OPCODE(OP_DADD)
  {
    JDOUBLE d1, d2;
    pop_jdouble(&d1);
    pop_jdouble(&d2);
    d2 += d1;
    push_jdouble(&d2);
  }
  DISPATCH;

OPCODE(OP_DMUL)
  {
    JDOUBLE d1, d2;
    pop_jdouble(&d1);
    pop_jdouble(&d2);
    d2 *= d1;
    push_jdouble(&d2);
  }
  DISPATCH;

OPCODE(OP_DDIV)
  {
    JDOUBLE d1, d2;
    pop_jdouble(&d1);
    pop_jdouble(&d2);
    d2 /= d1;
    push_jdouble(&d2);
  }
  DISPATCH;

OPCODE(OP_DREM)
  {
    JDOUBLE d1, d2;
    pop_jdouble(&d1);
    pop_jdouble(&d2);
    d2 = fmod(d2, d1);
    push_jdouble(&d2);
  }
  DISPATCH;
#endif // FP_DOUBLE_ARITHMETIC

OPCODE(OP_LNEG)
  {
    JLONG l1;
    pop_jlong(&l1);
    l1 = - (ULLONG) l1;
    push_jlong(&l1);
  }
  DISPATCH;

OPCODE(OP_LADD)
  {
    JLONG l1, l2;
    pop_jlong(&l1);
    pop_jlong(&l2);
    l2 = ((ULLONG) l1) + (ULLONG) l2;
    push_jlong(&l2);
  }
  DISPATCH;

OPCODE(OP_LSUB)
  {
    JLONG l1, l2;
    pop_jlong(&l1);
    pop_jlong(&l2);
    l2 = ((ULLONG) l2) - (ULLONG) l1;
    push_jlong(&l2);
  }
  DISPATCH;

OPCODE(OP_LMUL)
  {
    JLONG l1, l2;
    pop_jlong(&l1);
    pop_jlong(&l2);
    l2 = ((ULLONG) l2) * (ULLONG) l1;
    push_jlong(&l2);
  }
  DISPATCH;

// FIXME: UB on -2^63 / -1 ?

OPCODE(OP_LDIV)
  {
    JLONG l1, l2;
    pop_jlong(&l1);
    pop_jlong(&l2);
    if (l1 == 0) {
      goto LABEL_THROW_ARITHMETIC_EXCEPTION;
    }
    l2 /= l1;
    push_jlong(&l2);
  }
  DISPATCH;

OPCODE(OP_LREM)
  {
    JLONG l1, l2;
    pop_jlong(&l1);
    pop_jlong(&l2);
    if (l1 == 0) {
      goto LABEL_THROW_ARITHMETIC_EXCEPTION;
    }
    l2 %= l1;
    push_jlong(&l2);
  }
  DISPATCH;

/*end*/
