forked from ValeLang/Vale
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Evan Ovadia
committed
Aug 21, 2023
1 parent
12e4f64
commit ba4b474
Showing
2 changed files
with
191 additions
and
0 deletions.
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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
|
||
# Sparse Array | ||
|
||
A sparse array is conceptually an array of optionals (we could even have the backend lower optionals arrays to sparse arrays). | ||
|
||
A sparse array will look like this: | ||
|
||
``` | ||
struct SparseArray_Ship { | ||
uint64_t slicesAvailableSlots[0]; // Goes backwards in memory | ||
uint64_t capacity; | ||
Ship[] ships; | ||
}; | ||
``` | ||
|
||
A "slice" is a part of the array that's up to 64 elements long. If capacity <= 64, then `slicesAvailableSlots` has 1 u64. If <= 128, there are 2 u64, and so on. | ||
|
||
Each slice's integer will have some bits, each corresponding to a slot in the array, 0 to represent available, 1 for unavailable. Anything for past the end of the array will contain 1. | ||
|
||
The `findFirstEmpty` function will loop over `slicesAvailableSlots`, doing `count_lzero(slicesAvailableSlots[i])` to check if there are any 1s that we can use. We can unroll that loop to pipeline a little better too, and maybe even SIMD it. | ||
|
||
|
||
# Sparse List | ||
|
||
This is really just a sparse array that has a `size`, to know when it needs to expand. | ||
|
||
``` | ||
struct SparseListData_Ship { | ||
uint64_t[] availabilities; // goes backwards | ||
Ship[] ships; // Goes forwards | ||
}; | ||
struct SparseList_Ship { | ||
uint64_t capacity; | ||
uint64_t size; | ||
SparseListData_Ship* data; | ||
}; | ||
``` | ||
|
||
When `size` hits `capacity`, we reallocate the `SparseListData_Ship` to be twice as big. | ||
|
||
|
||
# Sparse Stable Array | ||
|
||
|
||
|
||
# Sparse Stable List | ||
|
||
A sparse list is a linked list of exponentially bigger sparse arrays. However, there are some differences in how it would be represented. | ||
|
||
``` | ||
struct SparseList_Ship { | ||
uint64_t slicesAvailableSlots[0]; // Goes backwards in memory | ||
uint64_t numSlices; | ||
uint64_t capacity; | ||
uint64_t size; | ||
Ship[] ships; // Goes forwards in memory | ||
}; | ||
``` | ||
|
||
Every ptr in the `slicesPtrsTagged` array-of-pointers is a pointer to an array of `Ship`. However, every pointer's top bit is 0 if it's pointing at the beginning of the allocation, 1 if it's pointing to the middle of the allocation. | ||
|
||
|
||
`slices` could point at | ||
|
||
|
||
# Bunch | ||
|
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,123 @@ | ||
|
||
|
||
``` | ||
results = | ||
interleaved(4) foreach ship in myShipsList { | ||
totalFuel = ship.leftEngine.fuel + ship.rightEngine.fuel; | ||
if totalFuel < 10 { | ||
set totalFuel = totalFuel * 2; | ||
} else { | ||
sequential { println(totalFuel); } | ||
} | ||
totalFuel | ||
}; | ||
``` | ||
|
||
interleaved(4) implies unroll(4) and pure. | ||
|
||
would become: | ||
|
||
|
||
``` | ||
len = myShipsList.len(); | ||
results = List<i64>(len); | ||
for (int i = 0; i < len; i += 4) { | ||
iA = i; | ||
iB = i + 1 < len ? i + 1 : i; | ||
iC = i + 2 < len ? i + 2 : i; | ||
iD = i + 3 < len ? i + 3 : i; | ||
shipA = myShipsList.get(iA); // inlined | ||
shipB = myShipsList.get(iB); // inlined | ||
shipC = myShipsList.get(iC); // inlined | ||
shipD = myShipsList.get(iD); // inlined | ||
sleA = shipA.leftEngine; sleB = shipB.leftEngine; sleC = shipC.leftEngine; sleD = shipD.leftEngine; | ||
slefA = sleA.fuel; slefB = sleB.fuel; slefC = sleC.fuel; slefD = sleD.fuel; | ||
sreA = shipA.rightEngine; sreB = shipB.rightEngine; sreC = shipC.rightEngine; sreD = shipD.rightEngine; | ||
srefA = sreA.fuel; srefB = sreB.fuel; srefC = sreC.fuel; srefD = sreD.fuel; | ||
totalFuelA = slefA + srefA; totalFuelB = slefB + srefB; totalFuelC = slefC + srefC; totalFuelD = slefD + srefD; | ||
condA = totalFuelA < 10; condB = totalFuelB < 10; condC = totalFuelC < 10; condD = totalFuelD < 10; | ||
// Find a true | ||
trueTotalFuelDefault = condB ? &totalFuelB : &totalFuelA; | ||
trueTotalFuelDefault = condC ? &totalFuelC : trueTotalFuelDefault; | ||
trueTotalFuelDefault = condD ? &totalFuelD : trueTotalFuelDefault; | ||
trueTotalFuelPtrA = condA ? &totalFuelA : trueTotalFuelDefault; | ||
trueTotalFuelPtrB = condB ? &totalFuelB : trueTotalFuelDefault; | ||
trueTotalFuelPtrC = condC ? &totalFuelC : trueTotalFuelDefault; | ||
trueTotalFuelPtrD = condD ? &totalFuelD : trueTotalFuelDefault; | ||
if condA or condB or condC or condD { | ||
// Load | ||
trueTotalFuelA = *trueTotalFuelPtrA; | ||
trueTotalFuelB = *trueTotalFuelPtrB; | ||
trueTotalFuelC = *trueTotalFuelPtrC; | ||
trueTotalFuelD = *trueTotalFuelPtrD; | ||
// Do actual instructions | ||
trueTotalFuelA = trueTotalFuelA * 2; | ||
trueTotalFuelB = trueTotalFuelB * 2; | ||
trueTotalFuelC = trueTotalFuelC * 2; | ||
trueTotalFuelD = trueTotalFuelD * 2; | ||
// Send back into parent scope | ||
*trueTotalFuelPtrA = trueTotalFuelA; | ||
*trueTotalFuelPtrB = trueTotalFuelB; | ||
*trueTotalFuelPtrC = trueTotalFuelC; | ||
*trueTotalFuelPtrD = trueTotalFuelD; | ||
} | ||
// Collect into an array | ||
falseNextI = 0; | ||
falseTotalFuels = [#8]i64(null); | ||
falseTotalFuels[falseNextI] = &totalFuelA; falseNextI += !condA; | ||
falseTotalFuels[falseNextI] = &totalFuelB; falseNextI += !condB; | ||
falseTotalFuels[falseNextI] = &totalFuelC; falseNextI += !condC; | ||
falseTotalFuels[falseNextI] = &totalFuelD; falseNextI += !condD; | ||
for (int x = 0; x < falseNextI; x++) { | ||
println(falseTotalFuels[x]); | ||
} | ||
trueTotalFuels[falseNext] = &totalFuelA; falseNext -= condA; | ||
trueTotalFuels[falseNext] = &totalFuelB; falseNext -= condB; | ||
trueTotalFuels[falseNext] = &totalFuelC; falseNext -= condC; | ||
trueTotalFuels[falseNext] = &totalFuelD; falseNext -= condD; | ||
set totalFuel = totalFuel * 2; | ||
switch (trueNext) { | ||
case 0: // None true, all false | ||
println(trueTotalFuels[0]); | ||
println(trueTotalFuels[1]); | ||
println(trueTotalFuels[2]); | ||
println(trueTotalFuels[3]); | ||
break; | ||
case 1: // 1 true, 3 false | ||
set totalFuel = totalFuel * 2; | ||
trueTotalFuels | ||
case 2: // 2 true, 2 false | ||
case 3: // 3 true, 1 false | ||
} | ||
a = get(i * 4 < len ? i * 4 | ||
} | ||
foreach slice in myShipsList | ||
unroll(8) pure interleaved foreach ship in myShipsList { | ||
averageFuel = (ship.leftEngine.fuel + ship.rightEngine.fuel) / 2; | ||
if averageFuel < 10 { | ||
set averageFuel = averageFuel * 2; | ||
} else { | ||
sequential { println("hello"); } | ||
} | ||
}; | ||
``` |