aboutsummaryrefslogtreecommitdiffhomepage
path: root/test/external/metalang99/examples/duffs_device.c
diff options
context:
space:
mode:
Diffstat (limited to 'test/external/metalang99/examples/duffs_device.c')
-rw-r--r--test/external/metalang99/examples/duffs_device.c76
1 files changed, 76 insertions, 0 deletions
diff --git a/test/external/metalang99/examples/duffs_device.c b/test/external/metalang99/examples/duffs_device.c
new file mode 100644
index 0000000..cc5ade0
--- /dev/null
+++ b/test/external/metalang99/examples/duffs_device.c
@@ -0,0 +1,76 @@
+/**
+ * Duff's device [1] is a technique to implement loop unrolling through amalgamation of a switch
+ * statement with a do-while loop.
+ *
+ * In this example, we are going to implement automatic generation of Duff's device.
+ *
+ * [1]: https://en.wikipedia.org/wiki/Duff's_device
+ */
+
+#include <metalang99.h>
+
+#include <assert.h>
+
+#define DUFFS_DEVICE(unrolling_factor, counter_ty, count, ...) \
+ do { \
+ if ((count) > 0) { \
+ counter_ty DUFFS_DEVICE_n = ((count) + ML99_DEC(unrolling_factor)) / unrolling_factor; \
+ switch ((count) % unrolling_factor) { \
+ case 0: \
+ do { \
+ __VA_ARGS__ \
+ ML99_EVAL(ML99_callUneval(genCases, ML99_DEC(unrolling_factor), __VA_ARGS__)) \
+ } while (--DUFFS_DEVICE_n > 0); \
+ } \
+ } \
+ } while (0)
+
+#define genCases_IMPL(i, ...) \
+ ML99_IF( \
+ ML99_NAT_EQ(i, 0), \
+ ML99_empty(), \
+ ML99_TERMS( \
+ v(/* FALLTHROUGH */ case i \
+ : __VA_ARGS__), \
+ ML99_callUneval(genCases, ML99_DEC(i), __VA_ARGS__)))
+
+int main(void) {
+#define ARRAY_LEN 50
+#define UNROLLING_FACTOR 3
+
+ int array[ARRAY_LEN] = { ML99_EVAL(ML99_times(v(ARRAY_LEN), v(5, ))) };
+ int *n_ptr = array;
+
+ // Square all the elements in the array.
+ DUFFS_DEVICE(UNROLLING_FACTOR, int, ARRAY_LEN, {
+ *n_ptr *= *n_ptr;
+ n_ptr++;
+ });
+
+ for (int i = 0; i < ARRAY_LEN; i++) {
+ assert(25 == array[i]);
+ }
+}
+
+/*
+The generated Duff's device:
+
+int DUFFS_DEVICE_n = ((50) + 2) / 3;
+switch ((50) % 3) {
+case 0:
+ do {
+ {
+ *n_ptr *= *n_ptr;
+ n_ptr++;
+ }
+ case 2: {
+ *n_ptr *= *n_ptr;
+ n_ptr++;
+ }
+ case 1: {
+ *n_ptr *= *n_ptr;
+ n_ptr++;
+ }
+ } while (--DUFFS_DEVICE_n > 0);
+}
+*/