aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordam <dam@gudinoff>2023-05-02 17:42:22 +0100
committerdam <dam@gudinoff>2023-05-02 17:42:22 +0100
commite39cc9078a253cf5b2adc6b0de11b54e7934bc9b (patch)
treea4cf02d11f3bd6ae33bf686df3a0e8037cd2d85c
parentf993b20d0f4400d1b9e4c918f5cbbcb3cddbb8a0 (diff)
downloadtask-time-tracker-e39cc9078a253cf5b2adc6b0de11b54e7934bc9b.tar.zst
task-time-tracker-e39cc9078a253cf5b2adc6b0de11b54e7934bc9b.zip
Prototyping branchless integer saturated arithmetics.
-rw-r--r--Math_Ext.jai172
-rw-r--r--ttt.jai120
2 files changed, 174 insertions, 118 deletions
diff --git a/Math_Ext.jai b/Math_Ext.jai
new file mode 100644
index 0000000..5a02756
--- /dev/null
+++ b/Math_Ext.jai
@@ -0,0 +1,172 @@
+#import "Basic";
+#import "Compiler";
+#import "Math";
+
+#run test_math_ext();
+
+test_math_ext :: () {
+
+ set_build_options_dc(.{do_output=false});
+
+ write_strings("=====================\n", "--- Test Math_Ext ---\n");
+
+ Test_Inputs :: struct(ia: $T, ib: T, ir: T, is: bool) {
+ // t: Type;
+ a := ia;
+ b := ib;
+ r := ir;
+ s := is;
+ };
+
+/*
+ tests := Test_Inputs.[
+ // .{1, 2, 3, false},
+ ];
+
+ for * tests {
+ result, saturated := add(cast(it.t)it.a, cast(it.t)it.b);
+ assert(result == it.r && saturated == it.s, "Failed: % %\n", result, saturated);
+ }
+*/
+
+
+ t1a := S64_MAX;
+ t1b := 0;
+ t1v, t1r := add(t1a, t1b);
+ assert(t1v == S64_MAX && t1r == false, "Failed: % %\n", t1v, t1r);
+ write_string("t1: OK\n");
+
+ // t2a := S64_MAX;
+ // t2b := 1;
+ // t2v, t2r := add(t2a, t2b);
+ // assert(t2v == S64_MAX && t2r == true, "Failed: % %\n", t2v, t2r);
+}
+
+
+add_int64 :: (x :s64, y: s64) -> s64 #dump { // TODO Comparing implementations.
+ return
+ ifx (y > 0 && x > S64_MAX - y) then S64_MAX else
+ ifx (y < 0 && x < S64_MIN - y) then S64_MIN else
+ x + y;
+}
+
+sub_int64 :: (x :s64, y :s64) -> s64 {
+ return
+ ifx (y < 0 && x > S64_MAX + y) then S64_MAX else
+ ifx (y > 0 && x < S64_MIN + y) then S64_MIN else
+ x - y;
+}
+
+add :: (value_a: s64, value_b: s64) -> result: s64, saturated: bool #dump { // TODO Comparing implementaitons using dump
+ result: s64 = ---;
+ flag: bool = ---;
+ #asm {
+ mov d: gpr === d, 9223372036854775807;
+ mov a: gpr === a, value_a;
+ mov b: gpr === b, value_b;
+ add a, b;
+ seto flag; // Flag overflow.
+ mov result, a;
+ mov a, value_a;
+ shr a, 63;
+ add a, d;
+ mov c: gpr, value_a;
+ xor c, b;
+ xor b, result;
+ not b;
+ or c, b;
+ test c, c;
+ cmovns result, a;
+ }
+ return result, flag;
+}
+
+/*
+// value_a: s64 = 2;
+// value_b: s64 = S64_MAX-1;
+value_a: s64 = -2;
+value_b: s64 = S64_MIN+1;
+print(">%\n", S64_MAX);
+argx := get_command_line_arguments();
+if argx.count > 1
+ value_a = parse_int(*argx[1]);
+if argx.count > 2
+ value_b = parse_int(*argx[2]);
+
+result: s64 = ---;
+flags: s64;// = ---;
+#asm LAHF_SAHF { // TODO Remove LAHF_SAHF it not required.
+
+ // Code from https://locklessinc.com/articles/sat_arithmetic/
+
+
+ // value_a === b;
+ // value_b === c;
+ // add value_a, value_b;
+ // mov result, value_a;
+
+ // Version 1
+ // mov b: gpr === b, value_a;
+ // mov c: gpr === c, value_b;
+ // add b, c;
+ // mov result, b;
+ // seto flags;
+ // cmovns b, c;
+
+// s64b sat_adds64b(s64b x, s64b y)
+// {
+// u64b ux = x;
+// u64b uy = y;
+// u64b res = ux + uy;
+//
+// ux = (ux >> 63) + LONG_MAX;
+//
+// /* Force compiler to use cmovns instruction */
+// if ((s64b) ((ux ^ uy) | ~(uy ^ res)) >= 0)
+// {
+// res = ux;
+// }
+//
+// return res;
+// }
+ // Version 2 - WORKS
+ mov d: gpr === d, 9223372036854775807;
+ mov a: gpr === a, value_a;
+ mov b: gpr === b, value_b;
+ add a, b;
+ seto flags; // Flag overflow.
+ mov result, a;
+ mov a, value_a;
+ shr a, 63;
+ add a, d;
+ mov c: gpr, value_a;
+ xor c, b;
+ xor b, result;
+ not b;
+ or c, b;
+ test c, c;
+ cmovns result, a;
+
+// s64b sat_subs64b(s64b x, s64b y)
+// {
+// u64b ux = x;
+// u64b uy = y;
+// u64b res = ux - uy;
+//
+// ux = (ux >> 63) + LONG_MAX;
+//
+// // Force compiler to use cmovns instruction
+// if ((s64b)((ux ^ uy) & (ux ^ res)) < 0)
+// {
+// res = ux;
+// }
+//
+// return res;
+// }
+ // TODO Use https://godbolt.org/ to help
+
+}
+print("% + % = %\n", value_a, value_b, result);
+print("flag: %\n", flags);
+return;
+*/ \ No newline at end of file
diff --git a/ttt.jai b/ttt.jai
index 503c418..554884a 100644
--- a/ttt.jai
+++ b/ttt.jai
@@ -474,6 +474,7 @@ update_total_times :: (db: *Database) {
totals: []s64 = db.total_times;
memset(totals.data, 0, NUM_WEEK_DAYS * size_of(s64));
for db.tasks {
+ // TODO Try to use local variables instead of total sub...something... the indexes thingy.
times : []s64 = it.times;
totals[0] = add_int64(totals[0], times[0]);
totals[1] = add_int64(totals[1], times[1]);
@@ -1163,121 +1164,6 @@ read_enter_confirmation :: inline (row: int, style: int, message: string) -> boo
}
main :: () {
-
-
- add :: (value_a: s64, value_b: s64) -> s64, bool #dump { // TODO Comparing implementaitons using dump
- result: s64 = ---;
- flag: bool = ---;
- #asm {
- mov d: gpr === d, 9223372036854775807;
- mov a: gpr === a, value_a;
- mov b: gpr === b, value_b;
- add a, b;
- seto flag; // Signal overflow.
- mov result, a;
- mov a, value_a;
- shr a, 63;
- add a, d;
- mov c: gpr, value_a;
- xor c, b;
- xor b, result;
- not b;
- or c, b;
- test c, c;
- cmovns result, a;
- }
- return result, flag;
- }
-
-
- // value_a: s64 = 2;
- // value_b: s64 = S64_MAX-1;
- value_a: s64 = -2;
- value_b: s64 = S64_MIN+1;
- print(">%\n", S64_MAX);
- argx := get_command_line_arguments();
- if argx.count > 1
- value_a = parse_int(*argx[1]);
- if argx.count > 2
- value_b = parse_int(*argx[2]);
-
- result: s64 = ---;
- flags: s64;// = ---;
- #asm LAHF_SAHF { // TODO Remove LAHF_SAHF it not required.
-
- // Code from https://locklessinc.com/articles/sat_arithmetic/
-
-
- // value_a === b;
- // value_b === c;
- // add value_a, value_b;
- // mov result, value_a;
-
- // Version 1
- // mov b: gpr === b, value_a;
- // mov c: gpr === c, value_b;
- // add b, c;
- // mov result, b;
- // seto flags;
- // cmovns b, c;
-
-// s64b sat_adds64b(s64b x, s64b y)
-// {
-// u64b ux = x;
-// u64b uy = y;
-// u64b res = ux + uy;
-//
-// ux = (ux >> 63) + LONG_MAX;
-//
-// /* Force compiler to use cmovns instruction */
-// if ((s64b) ((ux ^ uy) | ~(uy ^ res)) >= 0)
-// {
-// res = ux;
-// }
-//
-// return res;
-// }
- // Version 2 - WORKS
- mov d: gpr === d, 9223372036854775807;
- mov a: gpr === a, value_a;
- mov b: gpr === b, value_b;
- add a, b;
- seto flags; // Signal overflow.
- mov result, a;
- mov a, value_a;
- shr a, 63;
- add a, d;
- mov c: gpr, value_a;
- xor c, b;
- xor b, result;
- not b;
- or c, b;
- test c, c;
- cmovns result, a;
-
-// s64b sat_subs64b(s64b x, s64b y)
-// {
-// u64b ux = x;
-// u64b uy = y;
-// u64b res = ux - uy;
-//
-// ux = (ux >> 63) + LONG_MAX;
-//
-// /* Force compiler to use cmovns instruction */
-// if ((s64b)((ux ^ uy) & (ux ^ res)) < 0)
-// {
-// res = ux;
-// }
-//
-// return res;
-// }
- // TODO Use https://godbolt.org/ to help
-
- }
- print("% + % = %\n", value_a, value_b, result);
- print("flag: %\n", flags);
- return;
-
// TODO Implement signal handling and see modules/Debug.jai for examples.
@@ -1293,9 +1179,7 @@ main :: () {
}
home_path, success_path := get_absolute_path(home_dir); // Returns temporary memory.
-
-
-
+
if success_path == false {
print_error("Failed to find home directory '%'.", home_dir);
exit(1);