Factor out more shared math operations between RGBASM and RGBLINK

This commit is contained in:
Rangi42
2025-08-02 19:35:26 -04:00
parent fe8baaec50
commit 2eeb333be0
4 changed files with 47 additions and 30 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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:

View File

@@ -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;
}