From c96952f47b36a9369746fdc9f180409ea3afbd1f Mon Sep 17 00:00:00 2001 From: nmlgc Date: Thu, 4 Apr 2024 18:47:58 +0200 Subject: [PATCH] [Research] Discover how pointer constness affects pointer parameter codegen In most cases, this discovery will mean that we have to bite the bullet and remove `const` from pointer parameters if the generated ASM wouldn't match otherwise. That by itself doesn't really simplify the code, but at least we get to remove a single bloated `reinterpret_cast` from one function call already. Part of P0278, funded by Yanga. --- Research/Borland C++ decompilation.md | 19 ++++++++++++++----- th01/hiscore/regist.cpp | 2 +- th01/hiscore/regist.hpp | 2 +- th01/main_01.cpp | 3 +-- 4 files changed, 17 insertions(+), 9 deletions(-) diff --git a/Research/Borland C++ decompilation.md b/Research/Borland C++ decompilation.md index 6fc9e1b4..d94e3d44 100644 --- a/Research/Borland C++ decompilation.md +++ b/Research/Borland C++ decompilation.md @@ -362,8 +362,14 @@ certain local variables as `word`s when they aren't. ### Pushing pointers -When passing a `near` pointer to a function that takes a `far` one, the -segment argument is sometimes `PUSH`ed immediately, before evaluating the +Passing `far` pointers to subscripted array elements requires code to calculate +the offset. Turbo C++ emits this calculation (and not the `PUSH` itself) either +before or after the segment is `PUSH`ed. If either + +1. the pointer is `near`, or +2. the parameter is a near or far `const *`, + +the segment argument is always pushed immediately, before evaluating the offset: ```c++ @@ -375,11 +381,14 @@ struct s100 { extern s100 structs[5]; -void __cdecl process(s100 *element); +void __cdecl process_mut(s100 *element); +void __cdecl process_const(const s100 *element); void foo(int i) { - process((s100 near *)(&structs[i])); // PUSH DS; (AX = offset); PUSH AX; - process((s100 far *)(&structs[i])); // (AX = offset); PUSH DS; PUSH AX; + process_mut((s100 near *)(&structs[i])); // PUSH DS; (AX = offset); PUSH AX; + process_mut((s100 far *)(&structs[i])); // (AX = offset); PUSH DS; PUSH AX; + process_const((s100 near *)(&structs[i])); // PUSH DS; (AX = offset); PUSH AX; + process_const((s100 far *)(&structs[i])); // PUSH DS; (AX = offset); PUSH AX; } ``` diff --git a/th01/hiscore/regist.cpp b/th01/hiscore/regist.cpp index fcc3d2ff..751f32c8 100644 --- a/th01/hiscore/regist.cpp +++ b/th01/hiscore/regist.cpp @@ -603,7 +603,7 @@ static const int SCOREDAT_NOT_CLEARED = (SCOREDAT_CLEARED - 10); void regist_menu( score_t score, int16_t stage_num_or_scoredat_constant, - const sshiftjis_t route[SCOREDAT_ROUTE_LEN + 1] + sshiftjis_t route[SCOREDAT_ROUTE_LEN + 1] ) { scoredat_name_z_t names[SCOREDAT_PLACES]; diff --git a/th01/hiscore/regist.hpp b/th01/hiscore/regist.hpp index 2034e605..d252a680 100644 --- a/th01/hiscore/regist.hpp +++ b/th01/hiscore/regist.hpp @@ -18,5 +18,5 @@ void regist_menu( score_t score, int16_t stage_num_or_scoredat_constant, - const sshiftjis_t route[SCOREDAT_ROUTE_LEN + 1] + sshiftjis_t route[SCOREDAT_ROUTE_LEN + 1] ); diff --git a/th01/main_01.cpp b/th01/main_01.cpp index 9f4f7b4d..99497491 100644 --- a/th01/main_01.cpp +++ b/th01/main_01.cpp @@ -1006,8 +1006,7 @@ int main(void) } resident->score = score; - // ZUN bloat: Unnecessary cast. - regist_menu(score, (stage_id + 1), reinterpret_cast( + regist_menu(score, (stage_id + 1), ( !stage_on_route(stage_id) ? SCOREDAT_ROUTE_SHRINE : (route == ROUTE_MAKAI) ? SCOREDAT_ROUTE_MAKAI : SCOREDAT_ROUTE_JIGOKU ));