.direnv
.norm_fail
Makefile.tmp
-.deps.tmp
+*.tmp
+flamegraph.svg
+perf.data
+out.folded
+out.perf
+*.old
+
fclean: clean
rm -f ${NAME}
rm -fd ${BUILDDIR}
+ rm -f a.out perf.data out.perf out.folded flamegraph.svg
re: fclean all
test: a.out
./a.out
-.PHONY: all clean fclean re remakefile redeps norm watch-step watch test
+perf.data: a.out
+ perf record -F 99 -g ./$<
+
+out.perf: perf.data
+ perf script > $@
+
+out.folded: out.perf
+ stackcollapse-perf.pl $< > $@
+
+flamegraph.svg: out.folded
+ flamegraph.pl $< > $@
+
+prof: flamegraph.svg
+
+.PHONY: all clean fclean re remakefile redeps norm watch-step watch test prof
-#LTO=1
-OPT=0
-#CC=gcc
+LTO=1
+OPT=1
+CC=clang
#UBSAN=1
#TSAN=1
#ASAN=1
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/04/29 16:40:27 by agilliar #+# #+# */
-/* Updated: 2026/05/15 11:22:29 by agilliar ### ########.fr */
+/* Updated: 2026/05/27 17:23:03 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
#include "arith.h"
#include "atomic.h"
+__attribute__((no_instrument_function))
t_arc arc_new(size_t size)
{
size_t *res;
}
// Relaxed sub as we own a copy, and as such ultimately sync
+__attribute__((no_instrument_function))
void arc_copy(t_arc arc)
{
if (__atomic_add_fetch(((size_t *)arc) - 1, 1, __ATOMIC_RELAXED)
}
}
+__attribute__((no_instrument_function))
void arc_drop(t_arc arc, t_drop destructor)
{
if (__atomic_sub_fetch(((size_t *)arc) - 1, 1, __ATOMIC_RELEASE) != 0)
free(((char *)arc) - 8);
}
+__attribute__((no_instrument_function))
bool arc_is_unique(t_arc arc)
{
return (__atomic_load_n(((size_t *)arc) - 1, __ATOMIC_ACQUIRE) == 1);
}
+__attribute__((no_instrument_function))
void noop(void *ptr)
{
(void) ptr;
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/05 17:31:36 by agilliar #+# #+# */
-/* Updated: 2026/05/15 11:02:57 by agilliar ### ########.fr */
+/* Updated: 2026/05/27 17:44:04 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
#include "defer.h"
#include "panic.h"
+__attribute__((no_instrument_function))
t_defer_frame *defer_store(void)
{
static __thread t_defer_frame store;
return (&store);
}
+__attribute__((no_instrument_function))
void defer_pop(void)
{
t_defer *curr;
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/05 15:38:33 by agilliar #+# #+# */
-/* Updated: 2026/05/20 11:14:53 by agilliar ### ########.fr */
+/* Updated: 2026/05/27 17:30:40 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
#include "panic.h"
#include "defer.h"
+__attribute__((no_instrument_function))
t_panic_info *panic_store(void)
{
static __thread t_panic_info store;
// Scuffed but clang is adament on not doing proper analysis on the semantics
// of setjmp/longjmp
__attribute__((noinline))
+__attribute__((no_instrument_function))
static t_panic_info *panic_store2(void)
{
return (panic_store());
__builtin_longjmp((void *)&panic_store()->jmp, 1);
}
+__attribute__((no_instrument_function))
bool panicking(void)
{
return (panic_store()->data != NULL);
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/20 11:23:55 by agilliar #+# #+# */
-/* Updated: 2026/05/25 18:13:32 by agilliar ### ########.fr */
+/* Updated: 2026/05/27 17:24:53 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
else if (value->tag == VALUE_NIL)
printf("%*s%s\n", (int)indent, "", "nil");
else if (value->tag == VALUE_BYTES)
- printf("%*s%.*s\n", (int)indent, "", value->val.v_bytes->len,
+ printf("%*s%.*s\n", (int)indent, "", (int) value->val.v_bytes->len,
value->val.v_bytes->buf);
else
printf("%*s%s\n", (int)indent, "", "<unknown>");
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/13 22:01:24 by agilliar #+# #+# */
-/* Updated: 2026/05/20 13:24:13 by agilliar ### ########.fr */
+/* Updated: 2026/05/27 17:27:19 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
# include "value_types.h"
# include "panic.h"
+__attribute__((no_instrument_function))
__attribute__((always_inline))
static inline intptr_t *value_int(t_value *value)
{
return (&value->val.v_int);
}
+__attribute__((no_instrument_function))
__attribute__((always_inline))
static inline uintptr_t *value_uint(t_value *value)
{
return (&value->val.v_uint);
}
+__attribute__((no_instrument_function))
__attribute__((always_inline))
static inline t_list *value_list(t_value *value)
{
return (value->val.v_list);
}
+__attribute__((no_instrument_function))
__attribute__((always_inline))
static inline t_bytes *value_bytes(t_value *value)
{
return (value->val.v_bytes);
}
+__attribute__((no_instrument_function))
__attribute__((always_inline))
static inline t_builtin *value_builtin(t_value *value)
{
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/12 17:42:10 by agilliar #+# #+# */
-/* Updated: 2026/05/25 17:52:28 by agilliar ### ########.fr */
+/* Updated: 2026/05/27 17:35:16 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
#include "value.h"
#include "memutils.h"
+__attribute__((no_instrument_function))
t_value value_copy(t_value val)
{
if (val.tag == VALUE_BYTES)
return (res);
}
+__attribute__((no_instrument_function))
static void list_drop(t_list *lst)
{
size_t i;
value_drop(&lst->buf[i++]);
}
+__attribute__((no_instrument_function))
void value_drop(t_value *value)
{
if (value->tag == VALUE_LIST)
value_builtin(value)->drop(value);
}
+__attribute__((no_instrument_function))
t_value value_unique(t_value *val)
{
if ((val->tag == VALUE_BYTES && !arc_is_unique(val->val.v_bytes))
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/13 12:51:13 by agilliar #+# #+# */
-/* Updated: 2026/05/20 10:29:49 by agilliar ### ########.fr */
+/* Updated: 2026/05/27 17:33:36 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
#include "value.h"
#include "panic.h"
+__attribute__((no_instrument_function))
size_t value_list_len(t_value lst)
{
if (lst.tag != VALUE_LIST)
}
// Borrows the value
+__attribute__((no_instrument_function))
t_value *value_list_get(t_value lst, size_t i)
{
if (value_list_len(lst) <= i)
return (&lst.val.v_list->buf[i]);
}
+__attribute__((no_instrument_function))
t_value *value_list_getu(t_value *lst, size_t i)
{
value_unique(lst);
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/13 21:27:54 by agilliar #+# #+# */
-/* Updated: 2026/05/18 11:55:04 by agilliar ### ########.fr */
+/* Updated: 2026/05/27 17:41:15 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
#include "value.h"
+//__attribute__((no_instrument_function))
+// for some reason this segfaults with no instrument, use after frees detected
+// hhow i don't know but i'm warry of unnoticed UB
void value_swap(t_value *a, t_value *b)
{
t_value tmp;
*b = tmp;
}
+__attribute__((no_instrument_function))
t_value value_take(t_value *a, t_value b)
{
value_swap(a, &b);
return (b);
}
+__attribute__((no_instrument_function))
t_value value_take_nil(t_value *a)
{
return (value_take(a, value_new_nil()));
}
+__attribute__((no_instrument_function))
void value_put(t_value *a, t_value b)
{
value_swap(a, &b);
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/13 08:40:13 by agilliar #+# #+# */
-/* Updated: 2026/05/25 18:14:32 by agilliar ### ########.fr */
+/* Updated: 2026/05/27 17:43:13 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
#include "arc.h"
#include "memutils.h"
+__attribute__((no_instrument_function))
t_value value_new_bytes(size_t len)
{
t_value res;
return (res);
}
+__attribute__((no_instrument_function))
t_value value_new_str(const char *s)
{
t_value res;
// We could use arc_new_zeroed but clang and gcc cannot tell that the
// following zero writes for the nil values are no-ops
+__attribute__((no_instrument_function))
t_value value_new_list(size_t len)
{
t_value res;
return (res);
}
+__attribute__((no_instrument_function))
t_value value_new_builtin(enum e_builtin tag)
{
t_builtin *builtin;
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/13 22:05:40 by agilliar #+# #+# */
-/* Updated: 2026/05/20 13:30:34 by agilliar ### ########.fr */
+/* Updated: 2026/05/27 17:42:54 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
#ifndef VALUE_NEW_H
# define VALUE_NEW_H
+__attribute__((no_instrument_function))
__attribute__((always_inline))
static inline t_value value_new_nil(void)
{
return (res);
}
+__attribute__((no_instrument_function))
__attribute__((always_inline))
static inline t_value value_new_int(intptr_t n)
{
return (res);
}
+__attribute__((no_instrument_function))
__attribute__((always_inline))
static inline t_value value_new_uint(uintptr_t n)
{
t_value value_new_va(size_t count, ...);
t_value value_new_step(uintptr_t expr_pos, bool expr_mov,
uintptr_t arg_pos, bool arg_mov);
+t_value value_new_fn(uintptr_t len, uintptr_t pos, ...);
#endif
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/05/20 10:29:41 by agilliar #+# #+# */
-/* Updated: 2026/05/20 10:54:22 by agilliar ### ########.fr */
+/* Updated: 2026/05/27 16:32:02 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
#include "defer.h"
#include <stdarg.h>
-t_value value_new_va(size_t count, ...)
+static t_value value_new_va_inner(size_t count, va_list ap)
{
t_value res;
t_value *buf;
- va_list ap;
size_t i;
buf = cera_alloca(sizeof(t_value) * count);
- va_start(ap, count);
i = 0;
while (i < count)
buf[i++] = va_arg(ap, t_value);
- va_end(ap);
i = 0;
while (i < count)
errdefer(value_drop, &buf[i++]);
return (res);
}
+t_value value_new_va(size_t count, ...)
+{
+ t_value res;
+ va_list ap;
+
+ va_start(ap, count);
+ res = value_new_va_inner(count, ap);
+ va_end(ap);
+ return (res);
+}
+
t_value value_new_step(uintptr_t expr_pos, bool expr_mov,
uintptr_t arg_pos, bool arg_mov)
{
return (value_new_va(4, value_new_uint(expr_pos), value_new_uint(expr_mov),
value_new_uint(arg_pos), value_new_uint(arg_mov)));
}
+
+t_value value_new_fn(uintptr_t len, uintptr_t pos, ...)
+{
+ va_list ap;
+ t_value res;
+
+ va_start(ap, pos);
+ res = value_new_va(2, value_new_va_inner(len, ap), value_new_uint(pos));
+ va_end(ap);
+ return (res);
+}
/* By: agilliar <agilliar@student.42mulhouse.fr> +#+ +:+ +#+ */
/* +#+#+#+#+#+ +#+ */
/* Created: 2026/04/30 17:19:58 by agilliar #+# #+# */
-/* Updated: 2026/05/27 16:12:48 by agilliar ### ########.fr */
+/* Updated: 2026/05/27 17:25:44 by agilliar ### ########.fr */
/* */
/* ************************************************************************** */
return (value_new_va(2, comb, value_new_uint(0)));
}
+/*
// f: f' f'
-// f': f -> curr: uint -> uint
+// f': f' -> curr: uint -> uint
// f' = (ite (ulte curr 1) (true 1) (compose (arg_swap f (usub curr 1)) (umul curr))) f
t_value fact(void)
{
);
return (expr_eval(make_rec(), value_new_va(2, res, value_new_uint(9))));
}
+*/
+
+// f: f' f' 1
+// f': f' -> acc: uint -> curr: uint -> uint
+// f' = (ite (ulte curr 1) (true acc) (f' f' (umul acc curr))) (usub curr 1)
+t_value fact(void)
+{
+ t_value f_prime = value_new_fn(
+ 22,
+ 6,
+ ite(), // 0
+ value_true(), // 1
+ value_new_uint(1), // 2
+ value_new_builtin(BUILTIN_UMUL), // 3
+ value_new_builtin(BUILTIN_USUB), // 4
+ value_new_builtin(BUILTIN_ULTE), // 5
+ value_new_nil(), // 6 f'
+ value_new_nil(), // 7 acc
+ value_new_nil(), // 8 curr
+ value_new_step(5, true, 8, false), // 9 ulte curr
+ value_new_step(9, true, 2, false), // 10 ulte curr 1
+ value_new_step(0, true, 10, true), // 11 ite (ulte curr 1)
+ value_new_step(1, true, 7, false), // 12 true acc
+ value_new_step(11, true, 12, true), // 13 ite (ulte curr 1) (true acc)
+ value_new_step(6, false, 6, true), // 14 f' f'
+ value_new_step(3, true, 7, true), // 15 umul acc
+ value_new_step(15, true, 8, false), // 16 umul acc curr
+ value_new_step(14, true, 16, true), // 17 f' f' (umul acc curr)
+ value_new_step(13, true, 17, true), // 18 ite ...
+ value_new_step(4, true, 8, true), // 19 usub curr
+ value_new_step(19, true, 2, true), // 20 umul curr 1
+ value_new_step(18, true, 20, true) // res
+ );
+ return (expr_eval(value_new_fn(
+ 4,
+ 1,
+ f_prime,
+ value_new_nil,
+ value_new_step(0, false, 0, true),
+ value_new_step(2, true, 1, true)
+ ), value_new_uint(1)));
+}
t_value test_expr(void)
{
defer(free, s2);
strcpy(s2, orig);
//t_value res = expr_eval(test_expr(), value_new_uint(0));
- t_value res = expr_eval(fact(), value_new_uint(100));
+ t_value res = expr_eval(fact(), value_new_uint(1000000));
value_debug(0, &res);
defer(value_drop, &res);
printf("%s\n", s2);