-
Notifications
You must be signed in to change notification settings - Fork 246
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Connect Bootrom Instrinsics #288
Merged
Merged
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
a6f2453
Fix ROM function signatures
Sizurka 81ab38f
Add ROM version check
Sizurka a70eb89
Add basic ROM intrinsics
Sizurka ce681b4
Move divider intrinsics to the new intrinsics macro
Sizurka 80c84b1
Add ROM floating point math library
Sizurka File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
use super::{Float, Int}; | ||
use crate::rom_data; | ||
|
||
trait ROMAdd { | ||
fn rom_add(self, b: Self) -> Self; | ||
} | ||
|
||
impl ROMAdd for f32 { | ||
fn rom_add(self, b: Self) -> Self { | ||
rom_data::float_funcs::fadd(self, b) | ||
} | ||
} | ||
|
||
impl ROMAdd for f64 { | ||
fn rom_add(self, b: Self) -> Self { | ||
rom_data::double_funcs::dadd(self, b) | ||
} | ||
} | ||
|
||
fn add<F: Float + ROMAdd>(a: F, b: F) -> F { | ||
if a.is_not_finite() { | ||
if b.is_not_finite() { | ||
let class_a = a.repr() & (F::SIGNIFICAND_MASK | F::SIGN_MASK); | ||
let class_b = b.repr() & (F::SIGNIFICAND_MASK | F::SIGN_MASK); | ||
|
||
if class_a == F::Int::ZERO && class_b == F::Int::ZERO { | ||
// inf + inf = inf | ||
return a; | ||
} | ||
if class_a == F::SIGN_MASK && class_b == F::SIGN_MASK { | ||
// -inf + (-inf) = -inf | ||
return a; | ||
} | ||
|
||
// Sign mismatch, or either is NaN already | ||
return F::NAN; | ||
} | ||
|
||
// [-]inf/NaN + X = [-]inf/NaN | ||
return a; | ||
} | ||
|
||
if b.is_not_finite() { | ||
// X + [-]inf/NaN = [-]inf/NaN | ||
return b; | ||
} | ||
|
||
a.rom_add(b) | ||
} | ||
|
||
intrinsics! { | ||
#[alias = __addsf3vfp] | ||
#[aeabi = __aeabi_fadd] | ||
extern "C" fn __addsf3(a: f32, b: f32) -> f32 { | ||
add(a, b) | ||
} | ||
|
||
#[bootrom_v2] | ||
#[alias = __adddf3vfp] | ||
#[aeabi = __aeabi_dadd] | ||
extern "C" fn __adddf3(a: f64, b: f64) -> f64 { | ||
add(a, b) | ||
} | ||
|
||
// The ROM just implements subtraction the same way, so just do it here | ||
// and save the work of implementing more complicated NaN/inf handling. | ||
|
||
#[alias = __subsf3vfp] | ||
#[aeabi = __aeabi_fsub] | ||
extern "C" fn __subsf3(a: f32, b: f32) -> f32 { | ||
add(a, -b) | ||
} | ||
|
||
#[bootrom_v2] | ||
#[alias = __subdf3vfp] | ||
#[aeabi = __aeabi_dsub] | ||
extern "C" fn __subdf3(a: f64, b: f64) -> f64 { | ||
add(a, -b) | ||
} | ||
|
||
extern "aapcs" fn __aeabi_frsub(a: f32, b: f32) -> f32 { | ||
add(b, -a) | ||
} | ||
|
||
#[bootrom_v2] | ||
extern "aapcs" fn __aeabi_drsub(a: f64, b: f64) -> f64 { | ||
add(b, -a) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,198 @@ | ||
use super::Float; | ||
use crate::rom_data; | ||
|
||
trait ROMCmp { | ||
fn rom_cmp(self, b: Self) -> i32; | ||
} | ||
|
||
impl ROMCmp for f32 { | ||
fn rom_cmp(self, b: Self) -> i32 { | ||
rom_data::float_funcs::fcmp(self, b) | ||
} | ||
} | ||
|
||
impl ROMCmp for f64 { | ||
fn rom_cmp(self, b: Self) -> i32 { | ||
rom_data::double_funcs::dcmp(self, b) | ||
} | ||
} | ||
|
||
fn le_abi<F: Float + ROMCmp>(a: F, b: F) -> i32 { | ||
if a.is_nan() || b.is_nan() { | ||
1 | ||
} else { | ||
a.rom_cmp(b) | ||
} | ||
} | ||
|
||
fn ge_abi<F: Float + ROMCmp>(a: F, b: F) -> i32 { | ||
if a.is_nan() || b.is_nan() { | ||
-1 | ||
} else { | ||
a.rom_cmp(b) | ||
} | ||
} | ||
|
||
intrinsics! { | ||
#[slower_than_default] | ||
#[bootrom_v2] | ||
#[alias = __eqsf2, __ltsf2, __nesf2] | ||
extern "C" fn __lesf2(a: f32, b: f32) -> i32 { | ||
le_abi(a, b) | ||
} | ||
|
||
#[slower_than_default] | ||
#[bootrom_v2] | ||
#[alias = __eqdf2, __ltdf2, __nedf2] | ||
extern "C" fn __ledf2(a: f64, b: f64) -> i32 { | ||
le_abi(a, b) | ||
} | ||
|
||
#[slower_than_default] | ||
#[bootrom_v2] | ||
#[alias = __gtsf2] | ||
extern "C" fn __gesf2(a: f32, b: f32) -> i32 { | ||
ge_abi(a, b) | ||
} | ||
|
||
#[slower_than_default] | ||
#[bootrom_v2] | ||
#[alias = __gtdf2] | ||
extern "C" fn __gedf2(a: f64, b: f64) -> i32 { | ||
ge_abi(a, b) | ||
} | ||
|
||
|
||
#[slower_than_default] | ||
#[bootrom_v2] | ||
extern "aapcs" fn __aeabi_fcmple(a: f32, b: f32) -> i32 { | ||
(le_abi(a, b) <= 0) as i32 | ||
} | ||
|
||
#[slower_than_default] | ||
#[bootrom_v2] | ||
extern "aapcs" fn __aeabi_fcmpge(a: f32, b: f32) -> i32 { | ||
(ge_abi(a, b) >= 0) as i32 | ||
} | ||
|
||
#[slower_than_default] | ||
#[bootrom_v2] | ||
extern "aapcs" fn __aeabi_fcmpeq(a: f32, b: f32) -> i32 { | ||
(le_abi(a, b) == 0) as i32 | ||
} | ||
|
||
#[slower_than_default] | ||
#[bootrom_v2] | ||
extern "aapcs" fn __aeabi_fcmplt(a: f32, b: f32) -> i32 { | ||
(le_abi(a, b) < 0) as i32 | ||
} | ||
|
||
#[slower_than_default] | ||
#[bootrom_v2] | ||
extern "aapcs" fn __aeabi_fcmpgt(a: f32, b: f32) -> i32 { | ||
(ge_abi(a, b) > 0) as i32 | ||
} | ||
|
||
#[slower_than_default] | ||
#[bootrom_v2] | ||
extern "aapcs" fn __aeabi_dcmple(a: f64, b: f64) -> i32 { | ||
(le_abi(a, b) <= 0) as i32 | ||
} | ||
|
||
#[slower_than_default] | ||
#[bootrom_v2] | ||
extern "aapcs" fn __aeabi_dcmpge(a: f64, b: f64) -> i32 { | ||
(ge_abi(a, b) >= 0) as i32 | ||
} | ||
|
||
#[slower_than_default] | ||
#[bootrom_v2] | ||
extern "aapcs" fn __aeabi_dcmpeq(a: f64, b: f64) -> i32 { | ||
(le_abi(a, b) == 0) as i32 | ||
} | ||
|
||
#[slower_than_default] | ||
#[bootrom_v2] | ||
extern "aapcs" fn __aeabi_dcmplt(a: f64, b: f64) -> i32 { | ||
(le_abi(a, b) < 0) as i32 | ||
} | ||
|
||
#[slower_than_default] | ||
#[bootrom_v2] | ||
extern "aapcs" fn __aeabi_dcmpgt(a: f64, b: f64) -> i32 { | ||
(ge_abi(a, b) > 0) as i32 | ||
} | ||
|
||
|
||
#[slower_than_default] | ||
#[bootrom_v2] | ||
extern "C" fn __gesf2vfp(a: f32, b: f32) -> i32 { | ||
(ge_abi(a, b) >= 0) as i32 | ||
} | ||
|
||
#[slower_than_default] | ||
#[bootrom_v2] | ||
extern "C" fn __gedf2vfp(a: f64, b: f64) -> i32 { | ||
(ge_abi(a, b) >= 0) as i32 | ||
} | ||
|
||
#[slower_than_default] | ||
#[bootrom_v2] | ||
extern "C" fn __gtsf2vfp(a: f32, b: f32) -> i32 { | ||
(ge_abi(a, b) > 0) as i32 | ||
} | ||
|
||
#[slower_than_default] | ||
#[bootrom_v2] | ||
extern "C" fn __gtdf2vfp(a: f64, b: f64) -> i32 { | ||
(ge_abi(a, b) > 0) as i32 | ||
} | ||
|
||
#[slower_than_default] | ||
#[bootrom_v2] | ||
extern "C" fn __ltsf2vfp(a: f32, b: f32) -> i32 { | ||
(le_abi(a, b) < 0) as i32 | ||
} | ||
|
||
#[slower_than_default] | ||
#[bootrom_v2] | ||
extern "C" fn __ltdf2vfp(a: f64, b: f64) -> i32 { | ||
(le_abi(a, b) < 0) as i32 | ||
} | ||
|
||
#[slower_than_default] | ||
#[bootrom_v2] | ||
extern "C" fn __lesf2vfp(a: f32, b: f32) -> i32 { | ||
(le_abi(a, b) <= 0) as i32 | ||
} | ||
|
||
#[slower_than_default] | ||
#[bootrom_v2] | ||
extern "C" fn __ledf2vfp(a: f64, b: f64) -> i32 { | ||
(le_abi(a, b) <= 0) as i32 | ||
} | ||
|
||
#[slower_than_default] | ||
#[bootrom_v2] | ||
extern "C" fn __nesf2vfp(a: f32, b: f32) -> i32 { | ||
(le_abi(a, b) != 0) as i32 | ||
} | ||
|
||
#[slower_than_default] | ||
#[bootrom_v2] | ||
extern "C" fn __nedf2vfp(a: f64, b: f64) -> i32 { | ||
(le_abi(a, b) != 0) as i32 | ||
} | ||
|
||
#[slower_than_default] | ||
#[bootrom_v2] | ||
extern "C" fn __eqsf2vfp(a: f32, b: f32) -> i32 { | ||
(le_abi(a, b) == 0) as i32 | ||
} | ||
|
||
#[slower_than_default] | ||
#[bootrom_v2] | ||
extern "C" fn __eqdf2vfp(a: f64, b: f64) -> i32 { | ||
(le_abi(a, b) == 0) as i32 | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand those aliases. Aren't those different operations (equal, less than, not equal and less-or-equal?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but the definition of the functions is things like "zero if strictly equal" or "negative if less" so the allow any other value if the condition isn't met. compiler-builtins does the same thing, which is actually where I got the logic from.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, fine, I think now I understand: The underlying function (bootrom function
_fcmp
, softfloat library call__cmpsf2
) distinguishes three cases,<
,==
,>
. The library also provides several alternatives which don't guarantee to distinguish all three cases, but just separate subsets. I guess they are separate in case the hardware allows for faster implementations if you are only interested in such a subset.Thanks for those pointers!