mirror of
https://github.com/gbdev/rgbds.git
synced 2025-11-20 10:12:06 +00:00
Factor out more shared math operations between RGBASM and RGBLINK
This commit is contained in:
@@ -8,8 +8,17 @@
|
||||
int32_t op_divide(int32_t dividend, int32_t divisor);
|
||||
int32_t op_modulo(int32_t dividend, int32_t divisor);
|
||||
int32_t op_exponent(int32_t base, uint32_t power);
|
||||
|
||||
int32_t op_shift_left(int32_t value, int32_t amount);
|
||||
int32_t op_shift_right(int32_t value, int32_t amount);
|
||||
int32_t op_shift_right_unsigned(int32_t value, int32_t amount);
|
||||
|
||||
int32_t op_neg(int32_t value);
|
||||
|
||||
int32_t op_high(int32_t value);
|
||||
int32_t op_low(int32_t value);
|
||||
|
||||
int32_t op_bitwidth(int32_t value);
|
||||
int32_t op_tzcount(int32_t value);
|
||||
|
||||
#endif // RGBDS_OP_MATH_HPP
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
#include <string.h>
|
||||
#include <string_view>
|
||||
|
||||
#include "helpers.hpp" // assume, clz, ctz
|
||||
#include "helpers.hpp" // assume
|
||||
#include "opmath.hpp"
|
||||
|
||||
#include "asm/output.hpp"
|
||||
@@ -253,7 +253,7 @@ static int32_t tryConstLow(Expression const &expr) {
|
||||
assume(sect.org == UINT32_MAX);
|
||||
int32_t symbolOfs = sym->getValue() + 1;
|
||||
|
||||
return (symbolOfs + sect.alignOfs) & 0xFF;
|
||||
return op_low(symbolOfs + sect.alignOfs);
|
||||
}
|
||||
|
||||
// Returns a constant binary AND with one non-constant operand, or -1 if it cannot be computed.
|
||||
@@ -301,12 +301,9 @@ void Expression::makeUnaryOp(RPNCommand op, Expression &&src) {
|
||||
// First, check if the expression is known
|
||||
if (src.isKnown()) {
|
||||
// If the expressions is known, just compute the value
|
||||
int32_t val = src.value();
|
||||
uint32_t uval = static_cast<uint32_t>(val);
|
||||
|
||||
switch (op) {
|
||||
switch (int32_t val = src.value(); op) {
|
||||
case RPN_NEG:
|
||||
data = static_cast<int32_t>(-uval);
|
||||
data = op_neg(val);
|
||||
break;
|
||||
case RPN_NOT:
|
||||
data = ~val;
|
||||
@@ -315,16 +312,16 @@ void Expression::makeUnaryOp(RPNCommand op, Expression &&src) {
|
||||
data = !val;
|
||||
break;
|
||||
case RPN_HIGH:
|
||||
data = static_cast<int32_t>(uval >> 8 & 0xFF);
|
||||
data = op_high(val);
|
||||
break;
|
||||
case RPN_LOW:
|
||||
data = val & 0xFF;
|
||||
data = op_low(val);
|
||||
break;
|
||||
case RPN_BITWIDTH:
|
||||
data = val != 0 ? 32 - clz(uval) : 0;
|
||||
data = op_bitwidth(val);
|
||||
break;
|
||||
case RPN_TZCOUNT:
|
||||
data = val != 0 ? ctz(uval) : 32;
|
||||
data = op_tzcount(val);
|
||||
break;
|
||||
// LCOV_EXCL_START
|
||||
default:
|
||||
@@ -397,37 +394,30 @@ void Expression::makeBinaryOp(RPNCommand op, Expression &&src1, Expression const
|
||||
if (rval < 0) {
|
||||
warning(WARNING_SHIFT_AMOUNT, "Shifting left by negative amount %" PRId32, rval);
|
||||
}
|
||||
|
||||
if (rval >= 32) {
|
||||
warning(WARNING_SHIFT_AMOUNT, "Shifting left by large amount %" PRId32, rval);
|
||||
}
|
||||
|
||||
data = op_shift_left(lval, rval);
|
||||
break;
|
||||
case RPN_SHR:
|
||||
if (lval < 0) {
|
||||
warning(WARNING_SHIFT, "Shifting right negative value %" PRId32, lval);
|
||||
}
|
||||
|
||||
if (rval < 0) {
|
||||
warning(WARNING_SHIFT_AMOUNT, "Shifting right by negative amount %" PRId32, rval);
|
||||
}
|
||||
|
||||
if (rval >= 32) {
|
||||
warning(WARNING_SHIFT_AMOUNT, "Shifting right by large amount %" PRId32, rval);
|
||||
}
|
||||
|
||||
data = op_shift_right(lval, rval);
|
||||
break;
|
||||
case RPN_USHR:
|
||||
if (rval < 0) {
|
||||
warning(WARNING_SHIFT_AMOUNT, "Shifting right by negative amount %" PRId32, rval);
|
||||
}
|
||||
|
||||
if (rval >= 32) {
|
||||
warning(WARNING_SHIFT_AMOUNT, "Shifting right by large amount %" PRId32, rval);
|
||||
}
|
||||
|
||||
data = op_shift_right_unsigned(lval, rval);
|
||||
break;
|
||||
case RPN_MUL:
|
||||
@@ -437,7 +427,6 @@ void Expression::makeBinaryOp(RPNCommand op, Expression &&src1, Expression const
|
||||
if (rval == 0) {
|
||||
fatal("Division by zero");
|
||||
}
|
||||
|
||||
if (lval == INT32_MIN && rval == -1) {
|
||||
warning(
|
||||
WARNING_DIV,
|
||||
@@ -454,7 +443,6 @@ void Expression::makeBinaryOp(RPNCommand op, Expression &&src1, Expression const
|
||||
if (rval == 0) {
|
||||
fatal("Modulo by zero");
|
||||
}
|
||||
|
||||
if (lval == INT32_MIN && rval == -1) {
|
||||
data = 0;
|
||||
} else {
|
||||
@@ -465,7 +453,6 @@ void Expression::makeBinaryOp(RPNCommand op, Expression &&src1, Expression const
|
||||
if (rval < 0) {
|
||||
fatal("Exponentiation by negative power");
|
||||
}
|
||||
|
||||
data = op_exponent(lval, rval);
|
||||
break;
|
||||
// LCOV_EXCL_START
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
#include "helpers.hpp" // assume, clz, ctz
|
||||
#include "helpers.hpp" // assume
|
||||
#include "linkdefs.hpp"
|
||||
#include "opmath.hpp"
|
||||
#include "verbosity.hpp"
|
||||
@@ -96,7 +96,6 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
|
||||
|
||||
while (size > 0) {
|
||||
RPNCommand command = static_cast<RPNCommand>(getRPNByte(expression, size, patch));
|
||||
int32_t value;
|
||||
|
||||
isError = false;
|
||||
|
||||
@@ -104,6 +103,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
|
||||
// C++ does not guarantee order of evaluation of operands!
|
||||
// So, if there are two `popRPN` in the same expression, make
|
||||
// sure the operation is commutative.
|
||||
int32_t value;
|
||||
switch (command) {
|
||||
case RPN_ADD:
|
||||
value = popRPN(patch) + popRPN(patch);
|
||||
@@ -145,7 +145,7 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
|
||||
}
|
||||
break;
|
||||
case RPN_NEG:
|
||||
value = -popRPN(patch);
|
||||
value = op_neg(popRPN(patch));
|
||||
break;
|
||||
case RPN_EXP:
|
||||
value = popRPN(patch);
|
||||
@@ -159,19 +159,17 @@ static int32_t computeRPNExpr(Patch const &patch, std::vector<Symbol> const &fil
|
||||
break;
|
||||
|
||||
case RPN_HIGH:
|
||||
value = (popRPN(patch) >> 8) & 0xFF;
|
||||
value = op_high(popRPN(patch));
|
||||
break;
|
||||
case RPN_LOW:
|
||||
value = popRPN(patch) & 0xFF;
|
||||
value = op_low(popRPN(patch));
|
||||
break;
|
||||
|
||||
case RPN_BITWIDTH:
|
||||
value = popRPN(patch);
|
||||
value = value != 0 ? 32 - clz(static_cast<uint32_t>(value)) : 0;
|
||||
value = op_bitwidth(popRPN(patch));
|
||||
break;
|
||||
case RPN_TZCOUNT:
|
||||
value = popRPN(patch);
|
||||
value = value != 0 ? ctz(static_cast<uint32_t>(value)) : 32;
|
||||
value = op_tzcount(popRPN(patch));
|
||||
break;
|
||||
|
||||
case RPN_OR:
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "helpers.hpp" // clz, ctz
|
||||
|
||||
int32_t op_divide(int32_t dividend, int32_t divisor) {
|
||||
// Adjust division to floor toward negative infinity,
|
||||
// not truncate toward zero
|
||||
@@ -96,3 +98,24 @@ int32_t op_shift_right_unsigned(int32_t value, int32_t amount) {
|
||||
|
||||
return static_cast<uint32_t>(value) >> amount;
|
||||
}
|
||||
|
||||
int32_t op_neg(int32_t value) {
|
||||
// Avoid negating signed INT_MIN
|
||||
return static_cast<int32_t>(-static_cast<uint32_t>(value));
|
||||
}
|
||||
|
||||
int32_t op_high(int32_t value) {
|
||||
return static_cast<int32_t>(static_cast<uint32_t>(value) >> 8 & 0xFF);
|
||||
}
|
||||
|
||||
int32_t op_low(int32_t value) {
|
||||
return value & 0xFF;
|
||||
}
|
||||
|
||||
int32_t op_bitwidth(int32_t value) {
|
||||
return value != 0 ? 32 - clz(static_cast<uint32_t>(value)) : 0;
|
||||
}
|
||||
|
||||
int32_t op_tzcount(int32_t value) {
|
||||
return value != 0 ? ctz(static_cast<uint32_t>(value)) : 32;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user