diff --git a/include/asm/main.h b/include/asm/main.h index b97080f6..c79942e1 100644 --- a/include/asm/main.h +++ b/include/asm/main.h @@ -16,7 +16,9 @@ #include "helpers.h" extern bool haltnop; +extern bool warnOnHaltNop; extern bool optimizeLoads; +extern bool warnOnLdOpt; extern bool verbose; extern bool warnings; /* True to enable warnings, false to disable them. */ diff --git a/src/asm/main.c b/src/asm/main.c index 5d2bf9c4..3ee1e82f 100644 --- a/src/asm/main.c +++ b/src/asm/main.c @@ -59,7 +59,9 @@ bool generatePhonyDeps; char *targetFileName; bool haltnop; +bool warnOnHaltNop; bool optimizeLoads; +bool warnOnLdOpt; bool verbose; bool warnings; /* True to enable warnings, false to disable them. */ @@ -84,7 +86,7 @@ static char *make_escape(char const *str) } /* Short options */ -static const char *optstring = "b:D:Eg:hi:LM:o:p:r:VvW:w"; +static const char *optstring = "b:D:Eg:Hhi:LlM:o:p:r:VvW:w"; /* Variables for the long-only options */ static int depType; /* Variants of `-M` */ @@ -104,9 +106,11 @@ static struct option const longopts[] = { { "define", required_argument, NULL, 'D' }, { "export-all", no_argument, NULL, 'E' }, { "gfx-chars", required_argument, NULL, 'g' }, + { "nop-after-halt", no_argument, NULL, 'H' }, { "halt-without-nop", no_argument, NULL, 'h' }, { "include", required_argument, NULL, 'i' }, { "preserve-ld", no_argument, NULL, 'L' }, + { "auto-ldh", no_argument, NULL, 'l' }, { "dependfile", required_argument, NULL, 'M' }, { "MG", no_argument, &depType, 'G' }, { "MP", no_argument, &depType, 'P' }, @@ -170,8 +174,10 @@ int main(int argc, char *argv[]) opt_B("01"); opt_G("0123"); opt_P(0); - optimizeLoads = true; haltnop = true; + warnOnHaltNop = true; + optimizeLoads = true; + warnOnLdOpt = true; verbose = false; warnings = true; sym_SetExportAll(false); @@ -209,7 +215,14 @@ int main(int argc, char *argv[]) errx("Must specify exactly 4 characters for option 'g'"); break; + case 'H': + if (!haltnop) + errx("`-H` and `-h` don't make sense together"); + warnOnHaltNop = false; + break; case 'h': + if (!warnOnHaltNop) + errx("`-H` and `-h` don't make sense together"); haltnop = false; break; @@ -218,8 +231,15 @@ int main(int argc, char *argv[]) break; case 'L': + if (!warnOnLdOpt) + errx("`-L` and `-l` don't make sense together"); optimizeLoads = false; break; + case 'l': + if (!optimizeLoads) + errx("`-L` and `-l` don't make sense together"); + warnOnLdOpt = false; + break; case 'M': if (!strcmp("-", musl_optarg)) diff --git a/src/asm/opt.c b/src/asm/opt.c index 608289ad..4d3c7b71 100644 --- a/src/asm/opt.c +++ b/src/asm/opt.c @@ -17,7 +17,9 @@ struct OptStackEntry { char gbgfx[4]; int32_t fillByte; bool haltnop; + bool warnOnHaltNop; bool optimizeLoads; + bool warnOnLdOpt; bool warningsAreErrors; size_t maxRecursionDepth; // Don't be confused: we use the size of the **global variable** `warningStates`! @@ -48,6 +50,11 @@ void opt_R(size_t newDepth) lexer_CheckRecursionDepth(); } +void opt_H(bool warn) +{ + warnOnHaltNop = warn; +} + void opt_h(bool halt) { haltnop = halt; @@ -58,6 +65,11 @@ void opt_L(bool optimize) optimizeLoads = optimize; } +void opt_l(bool warn) +{ + warnOnLdOpt = warn; +} + void opt_W(char *flag) { processWarningFlag(flag); @@ -118,6 +130,13 @@ void opt_Parse(char *s) break; } + case 'H': + if (s[1] == '\0') + opt_H(false); + else + error("Option 'H' does not take an argument\n"); + break; + case 'h': if (s[1] == '\0') opt_h(false); @@ -132,6 +151,13 @@ void opt_Parse(char *s) error("Option 'L' does not take an argument\n"); break; + case 'l': + if (s[1] == '\0') + opt_l(false); + else + error("Option 'l' does not take an argument\n"); + break; + case 'W': if (strlen(&s[1]) > 0) opt_W(&s[1]); @@ -186,8 +212,10 @@ void opt_Push(void) entry->fillByte = fillByte; // Pulled from section.h entry->haltnop = haltnop; // Pulled from main.h + entry->warnOnHaltNop = warnOnHaltNop; entry->optimizeLoads = optimizeLoads; // Pulled from main.h + entry->warnOnLdOpt = warnOnLdOpt; // Both of these pulled from warning.h entry->warningsAreErrors = warningsAreErrors; @@ -209,8 +237,10 @@ void opt_Pop(void) opt_B(entry->binary); opt_G(entry->gbgfx); opt_P(entry->fillByte); + opt_H(entry->warnOnHaltNop); opt_h(entry->haltnop); opt_L(entry->optimizeLoads); + opt_l(entry->warnOnLdOpt); // opt_W does not apply a whole warning state; it processes one flag string warningsAreErrors = entry->warningsAreErrors; diff --git a/src/asm/parser.y b/src/asm/parser.y index 004ed28e..85dd5e63 100644 --- a/src/asm/parser.y +++ b/src/asm/parser.y @@ -1801,8 +1801,13 @@ z80_ei : T_Z80_EI { sect_AbsByte(0xFB); } z80_halt : T_Z80_HALT { sect_AbsByte(0x76); - if (haltnop) + if (haltnop) { + if (warnOnHaltNop) { + warnOnHaltNop = false; + warning(WARNING_OBSOLETE, "`nop` after `halt` will stop being the default; pass `-H` to opt into it\n"); + } sect_AbsByte(0x00); + } } ; @@ -1910,6 +1915,10 @@ z80_ld_mem : T_Z80_LD op_mem_ind T_COMMA T_MODE_SP { | T_Z80_LD op_mem_ind T_COMMA T_MODE_A { if (optimizeLoads && rpn_isKnown(&$2) && $2.val >= 0xFF00) { + if (warnOnLdOpt) { + warnOnLdOpt = false; + warning(WARNING_OBSOLETE, "ld optimization will stop being the default; pass `-l` to opt into it\n"); + } sect_AbsByte(0xE0); sect_AbsByte($2.val & 0xFF); rpn_Free(&$2); @@ -1958,6 +1967,10 @@ z80_ld_a : T_Z80_LD reg_r T_COMMA c_ind { if ($2 == REG_A) { if (optimizeLoads && rpn_isKnown(&$4) && $4.val >= 0xFF00) { + if (warnOnLdOpt) { + warnOnLdOpt = false; + warning(WARNING_OBSOLETE, "ld optimization will stop being the default; pass `-l` to opt into it\n"); + } sect_AbsByte(0xF0); sect_AbsByte($4.val & 0xFF); rpn_Free(&$4); diff --git a/test/asm/opt.asm b/test/asm/opt.asm index 7962407d..5cb02402 100644 --- a/test/asm/opt.asm +++ b/test/asm/opt.asm @@ -10,6 +10,8 @@ pusho println $8000_0000 / -1 popo + opt H, l + ds 1 ld [$ff88], a halt diff --git a/test/asm/opt.err b/test/asm/opt.err index 3945fa07..6432e66e 100644 --- a/test/asm/opt.err +++ b/test/asm/opt.err @@ -1,2 +1,2 @@ -warning: opt.asm(16): [-Wdiv] +warning: opt.asm(18): [-Wdiv] Division of -2147483648 by -1 yields -2147483648