From dfec7111e22da4275097915a5dd6d75c762e17d1 Mon Sep 17 00:00:00 2001 From: Sylvie <35663410+Rangi42@users.noreply.github.com> Date: Thu, 13 Jun 2024 11:09:39 -0400 Subject: [PATCH] `X && 0` and `X & 0` are constant 0; `X || 1` is constant 1 (#1399) Fixes #977 --- man/rgbasm.5 | 13 ++++++++++++- src/asm/rpn.cpp | 14 ++++++++++++++ test/asm/const-zero.asm | 29 +++++++++++++++++++++++++++++ test/asm/const-zero.err | 3 +++ test/asm/const-zero.out | 6 ++++++ test/asm/isconst.asm | 2 +- 6 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 test/asm/const-zero.asm create mode 100644 test/asm/const-zero.err create mode 100644 test/asm/const-zero.out diff --git a/man/rgbasm.5 b/man/rgbasm.5 index 89f09faf..958542dc 100644 --- a/man/rgbasm.5 +++ b/man/rgbasm.5 @@ -218,6 +218,9 @@ knows its value. This is generally always the case, unless a label is involved, as explained in the .Sx SYMBOLS section. +However, some operators can be constant even with non-constant operands, as explained in +.Sx Operators +further below. .Pp The instructions in the macro-language generally require constant expressions. .Ss Numeric formats @@ -306,13 +309,21 @@ equivalent to multiplying and dividing by 2 to the power of b, respectively. .Pp Comparison operators return 0 if the comparison is false, and 1 otherwise. .Pp -Unlike in a lot of languages, and for technical reasons, +Unlike in many other languages, and for technical reasons, .Nm still evaluates both operands of .Sq && and .Sq || . .Pp +The operators +.Sq && +and +.Sq & +with a zero constant as either operand will be constant 0, and +.Sq || +with a non-zero constant as either operand will be constant 1, even if the other operand is non-constant. +.Pp .Ic \&! returns 1 if the operand was 0, and 0 otherwise. .Ss Fixed-point expressions diff --git a/src/asm/rpn.cpp b/src/asm/rpn.cpp index e2952df0..34a01b42 100644 --- a/src/asm/rpn.cpp +++ b/src/asm/rpn.cpp @@ -197,6 +197,16 @@ void Expression::makeStartOfSectionType(SectionType type) { *ptr = type; } +static bool tryConstZero(Expression const &lhs, Expression const &rhs) { + Expression const &expr = lhs.isKnown() ? lhs : rhs; + return expr.isKnown() && expr.value() == 0; +} + +static bool tryConstNonzero(Expression const &lhs, Expression const &rhs) { + Expression const &expr = lhs.isKnown() ? lhs : rhs; + return expr.isKnown() && expr.value() != 0; +} + /* * Attempts to compute a constant binary AND from non-constant operands * This is possible if one operand is a symbol belonging to an `ALIGN[N]` section, and the other is @@ -422,6 +432,10 @@ void Expression::makeBinaryOp(RPNCommand op, Expression &&src1, Expression const } } else if (op == RPN_SUB && src1.isDiffConstant(src2.symbolOf())) { data = src1.symbolOf()->getValue() - src2.symbolOf()->getValue(); + } else if ((op == RPN_LOGAND || op == RPN_AND) && tryConstZero(src1, src2)) { + data = 0; + } else if (op == RPN_LOGOR && tryConstNonzero(src1, src2)) { + data = 1; } else if (int32_t constVal; op == RPN_AND && (constVal = tryConstMask(src1, src2)) != -1) { data = constVal; } else { diff --git a/test/asm/const-zero.asm b/test/asm/const-zero.asm new file mode 100644 index 00000000..f5f0bb11 --- /dev/null +++ b/test/asm/const-zero.asm @@ -0,0 +1,29 @@ +MACRO test_and + if DEF(foo) && foo == 42 + println "Life, the Universe, and Everything!" + else + println "What do you get if you multiply six by seven?" + endc +ENDM + test_and + DEF foo = 42 + test_and + + +MACRO test_or + if DEF(DEBUG) || @ == $4567 + println "Here we are!" + else + println "Where are we?" + endc +ENDM + SECTION "Test OR", ROMX + test_or ; Not constant + DEF DEBUG EQU 1 + test_or + + +SECTION "Test arithmetic", ROM0 +Floating: + println Floating & 0 + println 0 & Floating diff --git a/test/asm/const-zero.err b/test/asm/const-zero.err new file mode 100644 index 00000000..8308f857 --- /dev/null +++ b/test/asm/const-zero.err @@ -0,0 +1,3 @@ +error: const-zero.asm(21) -> const-zero.asm::test_or(14): + Expected constant expression: PC is not constant at assembly time +error: Assembly aborted (1 error)! diff --git a/test/asm/const-zero.out b/test/asm/const-zero.out new file mode 100644 index 00000000..5e6e700e --- /dev/null +++ b/test/asm/const-zero.out @@ -0,0 +1,6 @@ +What do you get if you multiply six by seven? +Life, the Universe, and Everything! +Where are we? +Here we are! +$0 +$0 diff --git a/test/asm/isconst.asm b/test/asm/isconst.asm index 4c59c9da..ebeb1267 100644 --- a/test/asm/isconst.asm +++ b/test/asm/isconst.asm @@ -6,7 +6,7 @@ MACRO test_expr DEF IS_CONST = ISCONST(\1) PRINTLN "Test #{d:TEST_NUM}: ISCONST reports {IS_CONST}" - IF (\1) || 1 ; Only test if the expression can be evaluated + IF (\1) || IS_CONST ; Only test if the expression can be evaluated WARN "Test #{d:TEST_NUM}: Compile-time constant" ENDC ENDM