X && 0 and X & 0 are constant 0; X || 1 is constant 1 (#1399)

Fixes #977
This commit is contained in:
Sylvie
2024-06-13 11:09:39 -04:00
committed by GitHub
parent c5c6cc9794
commit dfec7111e2
6 changed files with 65 additions and 2 deletions

View File

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

View File

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

29
test/asm/const-zero.asm Normal file
View File

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

3
test/asm/const-zero.err Normal file
View File

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

6
test/asm/const-zero.out Normal file
View File

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

View File

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