unroll macro
This commit is contained in:
parent
2b42519e30
commit
e6b0fb7cdf
3 changed files with 157 additions and 16 deletions
|
|
@ -7,8 +7,8 @@
|
||||||
#import,file "./hash/module.jai"(true);
|
#import,file "./hash/module.jai"(true);
|
||||||
|
|
||||||
rmath :: #import,file "./math/module.jai"(.radians, true);
|
rmath :: #import,file "./math/module.jai"(.radians, true);
|
||||||
dmath :: #import,file "./math/module.jai"(.degrees, true);
|
// dmath :: #import,file "./math/module.jai"(.degrees, true);
|
||||||
tmath :: #import,file "./math/module.jai"(.turns, true);
|
// tmath :: #import,file "./math/module.jai"(.turns, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
150
macros.jai
150
macros.jai
|
|
@ -71,25 +71,49 @@ operator | :: with;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Creates a named block that can exit early (via 'break' or 'continue').
|
Creates a named block that can exit early (via 'break' or 'continue').
|
||||||
|
|
||||||
This mostly replaces the case where you'd like to jump to
|
This mostly replaces the case where you'd like to jump to
|
||||||
the end of a scope based on some logic within. Without
|
the end of a scope based on some logic within. Without
|
||||||
gotos, this is the next best thing.
|
gotos, this is the next best thing.
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
// within a loop
|
// within a loop
|
||||||
for this_block() { // this is named 'block' by default
|
for this_block() { // this is named 'block' by default
|
||||||
if !moving break;
|
if !moving break;
|
||||||
// do movement here
|
// do movement here
|
||||||
}
|
}
|
||||||
for this_block("render_player") {
|
for this_block("render_player") {
|
||||||
if invisible break render_player;
|
if invisible break render_player;
|
||||||
// do rendering here
|
// do rendering here
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
this_block :: ($name: string = Default_Name) -> Named_Block(name) #expand { return .{}; }
|
this_block :: ($name: string = Default_Name) -> Named_Block(name) #expand { return .{}; }
|
||||||
|
|
||||||
|
/*
|
||||||
|
Drop-in loop unrolling macro.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
for unroll(5) {
|
||||||
|
// duplicates this body 5 times exactly
|
||||||
|
}
|
||||||
|
|
||||||
|
known_size: [3]float;
|
||||||
|
for unroll(known_size) {
|
||||||
|
// duplicates this body 3 times exactly
|
||||||
|
}
|
||||||
|
|
||||||
|
var_size: []float;
|
||||||
|
for unroll(var_size) {
|
||||||
|
// duplicates this body a set number of times,
|
||||||
|
// falling back to a regular for loop to handle
|
||||||
|
// the remaining iterations.
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
unroll :: ($count: int) -> Unrolled_Loop(count) { return .{}; }
|
||||||
|
unroll :: (arr: [$N]$T) -> Unrolled_Loop(N, T) { return .{ array = arr }; }
|
||||||
|
unroll :: (arr: []$T) -> Unrolled_Loop(-1, T) { return .{ array = arr }; }
|
||||||
|
|
||||||
// Call #c_call procedures inline with the current context: 'c_call(some_c_call_proc(10, 20))'
|
// Call #c_call procedures inline with the current context: 'c_call(some_c_call_proc(10, 20))'
|
||||||
c_call :: (call: Code) #expand {
|
c_call :: (call: Code) #expand {
|
||||||
push_context context { #insert,scope(call) call; }
|
push_context context { #insert,scope(call) call; }
|
||||||
|
|
@ -118,6 +142,104 @@ for_expansion :: (v: *Named_Block, code: Code, _: For_Flags) #expand {
|
||||||
ifx v.NAME.count != 0 v.NAME else Default_Name);
|
ifx v.NAME.count != 0 v.NAME else Default_Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Unrolled_Loop :: struct(N: int, T: Type = void) {
|
||||||
|
// Only store arrays when we absolutely have to.
|
||||||
|
#if T != void {
|
||||||
|
// @todo(judah): because this will only be created via 'unroll',
|
||||||
|
// should these be pointers to the underlying arrays so we don't
|
||||||
|
// pay for a copy?
|
||||||
|
#if N == -1 {
|
||||||
|
array: []T = ---;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
array: [N]T = ---;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for_expansion :: (loop: *Unrolled_Loop, body: Code, flags: For_Flags, loc := #caller_location) #expand {
|
||||||
|
#assert flags & .REVERSE == 0 "reverse iteration not supported with loop unrolling (for now)";
|
||||||
|
#assert flags & .POINTER == 0 "pointer iteration not supported with loop unrolling (for now)";
|
||||||
|
|
||||||
|
// runtime unroll
|
||||||
|
#if loop.N == -1 {
|
||||||
|
for i: 0..loop.array.count - 1 {
|
||||||
|
`it := #no_abc loop.array[i];
|
||||||
|
`it_index := i;
|
||||||
|
#insert,scope(body) body;
|
||||||
|
}
|
||||||
|
|
||||||
|
// @todo(judah): below doesn't properly handle counts not divisible by 4,
|
||||||
|
// so we end up going over the bounds of the array.
|
||||||
|
|
||||||
|
// UNROLL_AMOUNT :: 4; // @todo(judah): make this configurable?
|
||||||
|
// unrolled_loops := loop.array.count / UNROLL_AMOUNT;
|
||||||
|
// remainder_loops := loop.array.count % UNROLL_AMOUNT;
|
||||||
|
// `it: loop.T;
|
||||||
|
// for i: 0..unrolled_loops #no_abc {
|
||||||
|
// basic.print("I: %\n", i);
|
||||||
|
// index := i * UNROLL_AMOUNT;
|
||||||
|
|
||||||
|
// it_index = index + 0;
|
||||||
|
// it = loop.array[it_index];
|
||||||
|
// #insert,scope(body) body;
|
||||||
|
|
||||||
|
// it_index = index + 1;
|
||||||
|
// it = loop.array[it_index];
|
||||||
|
// #insert,scope(body) body;
|
||||||
|
|
||||||
|
// it_index = index + 2;
|
||||||
|
// it = loop.array[it_index];
|
||||||
|
// #insert,scope(body) body;
|
||||||
|
|
||||||
|
// it_index = index + 3;
|
||||||
|
// it = loop.array[it_index];
|
||||||
|
// #insert,scope(body) body;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// after_big_loop := it_index;
|
||||||
|
// for i: 0..remainder_loops #no_abc {
|
||||||
|
// it_index = after_big_loop + i;
|
||||||
|
// it = loop.array[it_index];
|
||||||
|
// #insert,scope(body) body;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
// compile-time unroll
|
||||||
|
else {
|
||||||
|
`it_index := 0;
|
||||||
|
|
||||||
|
#insert -> string {
|
||||||
|
b: basic.String_Builder;
|
||||||
|
basic.print_to_builder(*b, "// inserted unrolled loop (N = %) at %:%\n", loop.N, loc.fully_pathed_filename, loc.line_number);
|
||||||
|
|
||||||
|
if loop.T == void {
|
||||||
|
basic.append(*b, "`it: int = ---;\n");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
basic.append(*b, "`it: loop.T = ---;\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
for 0..loop.N - 1 {
|
||||||
|
basic.append(*b, "{\n");
|
||||||
|
|
||||||
|
if loop.T == void {
|
||||||
|
basic.print_to_builder(*b, "\tit = %;\n", it);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
basic.print_to_builder(*b, "\tit = #no_abc loop.array[%];\n", it);
|
||||||
|
}
|
||||||
|
|
||||||
|
basic.print_to_builder(*b, "\tit_index = %;\n", it);
|
||||||
|
basic.append(*b, "\t#insert,scope(body) body;\n");
|
||||||
|
basic.append(*b, "}\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return basic.builder_to_string(*b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
pp :: #import "Program_Print";
|
pp :: #import "Program_Print";
|
||||||
compiler :: #import "Compiler";
|
compiler :: #import "Compiler";
|
||||||
|
|
||||||
|
|
|
||||||
19
math/vec.jai
19
math/vec.jai
|
|
@ -97,24 +97,28 @@ for_expansion :: (v: *Vec, body: Code, flags: For_Flags) #expand {
|
||||||
|
|
||||||
operator + :: inline (l: Vec, r: Vec(l.N, l.T)) -> Vec(l.N, l.T) #no_abc {
|
operator + :: inline (l: Vec, r: Vec(l.N, l.T)) -> Vec(l.N, l.T) #no_abc {
|
||||||
res: Vec(l.N, l.T) = ---;
|
res: Vec(l.N, l.T) = ---;
|
||||||
|
// @todo(judah): unroll for N <= 4
|
||||||
for l res[it_index] = it + r[it_index];
|
for l res[it_index] = it + r[it_index];
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
operator - :: inline (l: Vec, r: Vec(l.N, l.T)) -> Vec(l.N, l.T) #no_abc {
|
operator - :: inline (l: Vec, r: Vec(l.N, l.T)) -> Vec(l.N, l.T) #no_abc {
|
||||||
res: Vec(l.N, l.T) = ---;
|
res: Vec(l.N, l.T) = ---;
|
||||||
|
// @todo(judah): unroll for N <= 4
|
||||||
for l res[it_index] = it - r[it_index];
|
for l res[it_index] = it - r[it_index];
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
operator * :: inline (l: Vec, r: Vec(l.N, l.T)) -> Vec(l.N, l.T) #no_abc {
|
operator * :: inline (l: Vec, r: Vec(l.N, l.T)) -> Vec(l.N, l.T) #no_abc {
|
||||||
res: Vec(l.N, l.T) = ---;
|
res: Vec(l.N, l.T) = ---;
|
||||||
|
// @todo(judah): unroll for N <= 4
|
||||||
for l res[it_index] = it * r[it_index];
|
for l res[it_index] = it * r[it_index];
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
operator / :: inline (l: Vec, r: Vec(l.N, l.T)) -> Vec(l.N, l.T) #no_abc {
|
operator / :: inline (l: Vec, r: Vec(l.N, l.T)) -> Vec(l.N, l.T) #no_abc {
|
||||||
res: Vec(l.N, l.T) = ---;
|
res: Vec(l.N, l.T) = ---;
|
||||||
|
// @todo(judah): unroll for N <= 4
|
||||||
for l res[it_index] = it / r[it_index];
|
for l res[it_index] = it / r[it_index];
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
@ -165,3 +169,18 @@ v4i :: (x: $T = 0, y: T = 0, z: T = 0, w: T = 0) -> Vec(4, T)
|
||||||
quat :: (x: float = 0, y: float = 0, z: float = 0, w: float = 0) -> Quat #expand {
|
quat :: (x: float = 0, y: float = 0, z: float = 0, w: float = 0) -> Quat #expand {
|
||||||
return .{ x = x, y = y, z = z, w = w };
|
return .{ x = x, y = y, z = z, w = w };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if RUN_TESTS #run,stallable {
|
||||||
|
test.run("vec2:ops", t => {
|
||||||
|
a := v2f(10.0, 1);
|
||||||
|
b := v2f(20.0, 2);
|
||||||
|
c := a + b;
|
||||||
|
|
||||||
|
test.expect(t, c.x == 30 && c.y == 3);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#scope_file;
|
||||||
|
|
||||||
|
jx :: #import,file "../module.jai";
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue