Warn about signed 8-bit truncation for add sp, e8 and ld hl, sp + e8

This commit is contained in:
Rangi
2026-09-07 19:28:45 +02:00
committed by Eldred Habert
parent db9509fba0
commit fdd6cece30
5 changed files with 70 additions and 3 deletions
+2
View File
@@ -57,10 +57,12 @@ struct Expression {
void addCheckBitIndex(uint8_t mask); void addCheckBitIndex(uint8_t mask);
void checkNBit(uint8_t n) const; void checkNBit(uint8_t n) const;
void checkSignedNBit(uint8_t n) const;
void encode(std::vector<uint8_t> &buffer) const; void encode(std::vector<uint8_t> &buffer) const;
}; };
bool checkNBit(int32_t v, uint8_t n, char const *name); bool checkNBit(int32_t v, uint8_t n, char const *name);
bool checkSignedNBit(int32_t v, uint8_t n, char const *name);
#endif // RGBDS_ASM_RPN_HPP #endif // RGBDS_ASM_RPN_HPP
+11 -3
View File
@@ -340,6 +340,7 @@
%type <Expression> reloc_3bit %type <Expression> reloc_3bit
%type <Expression> reloc_8bit %type <Expression> reloc_8bit
%type <Expression> reloc_16bit %type <Expression> reloc_16bit
%type <Expression> reloc_8bit_signed
// Constant numbers // Constant numbers
%type <int32_t> iconst %type <int32_t> iconst
@@ -1241,6 +1242,13 @@ reloc_8bit:
} }
; ;
reloc_8bit_signed:
relocexpr {
$$ = std::move($1);
$$.checkSignedNBit(8);
}
;
reloc_16bit: reloc_16bit:
relocexpr { relocexpr {
$$ = std::move($1); $$ = std::move($1);
@@ -1886,7 +1894,7 @@ sm83_add:
| SM83_ADD MODE_HL COMMA reg_ss { | SM83_ADD MODE_HL COMMA reg_ss {
sect_ConstByte(0x09 | ($4 << 4)); sect_ConstByte(0x09 | ($4 << 4));
} }
| SM83_ADD MODE_SP COMMA reloc_8bit { | SM83_ADD MODE_SP COMMA reloc_8bit_signed {
sect_ConstByte(0xE8); sect_ConstByte(0xE8);
sect_RelByte($4, 1); sect_RelByte($4, 1);
} }
@@ -2434,11 +2442,11 @@ op_a_n:
op_sp_offset: op_sp_offset:
OP_ADD relocexpr { OP_ADD relocexpr {
$$ = std::move($2); $$ = std::move($2);
$$.checkNBit(8); $$.checkSignedNBit(8);
} }
| OP_SUB relocexpr { | OP_SUB relocexpr {
$$.makeUnaryOp(RPN_NEG, std::move($2)); $$.makeUnaryOp(RPN_NEG, std::move($2));
$$.checkNBit(8); $$.checkSignedNBit(8);
} }
| %empty { | %empty {
::error("\"LD HL, SP\" is not a valid instruction; use \"LD HL, SP + 0\""); ::error("\"LD HL, SP\" is not a valid instruction; use \"LD HL, SP + 0\"");
+19
View File
@@ -512,6 +512,25 @@ bool checkNBit(int32_t v, uint8_t n, char const *name) {
return true; return true;
} }
// Checks that an RPN expression's value fits within N bits (must be signed)
void Expression::checkSignedNBit(uint8_t n) const {
if (isKnown()) {
::checkSignedNBit(value(), n, nullptr);
}
}
bool checkSignedNBit(int32_t v, uint8_t n, char const *name) {
assume(n != 0); // That doesn't make sense
assume(n < CHAR_BIT * sizeof(int) - 1); // Otherwise `1 << n` is UB
if (v < -(1 << (n - 1)) || v >= 1 << (n - 1)) {
warning(WARNING_TRUNCATION_1, "%s must be signed %u-bit", name ? name : "Expression", n);
return false;
}
return true;
}
void Expression::encode(std::vector<uint8_t> &buffer) const { void Expression::encode(std::vector<uint8_t> &buffer) const {
assume(buffer.empty()); assume(buffer.empty());
+22
View File
@@ -0,0 +1,22 @@
section "test", rom0
opt Wtruncation=1
; good
ld hl, sp + 0
ld hl, sp + 127
ld hl, sp - 128
ld hl, sp + -128
add sp, 0
add sp, 127
add sp, -128
; bad
ld hl, sp + 128
ld hl, sp - 129
ld hl, sp + 255
ld hl, sp - 256
add sp, 128
add sp, -129
add sp, 255
add sp, -256
+16
View File
@@ -0,0 +1,16 @@
warning: Expression must be signed 8-bit [-Wtruncation]
at sp-signed-truncation.asm(15)
warning: Expression must be signed 8-bit [-Wtruncation]
at sp-signed-truncation.asm(16)
warning: Expression must be signed 8-bit [-Wtruncation]
at sp-signed-truncation.asm(17)
warning: Expression must be signed 8-bit [-Wtruncation]
at sp-signed-truncation.asm(18)
warning: Expression must be signed 8-bit [-Wtruncation]
at sp-signed-truncation.asm(19)
warning: Expression must be signed 8-bit [-Wtruncation]
at sp-signed-truncation.asm(20)
warning: Expression must be signed 8-bit [-Wtruncation]
at sp-signed-truncation.asm(21)
warning: Expression must be signed 8-bit [-Wtruncation]
at sp-signed-truncation.asm(22)