Skip to content

Commit 086c903

Browse files
committed
Fix floats on Wasm
On wasm32, terms are aligned by 4 bytes. `memory_heap_allocation` returns a pointer for `n` terms. We used float_term_t to create an union between a term and float. However, floats are aligned to 8 bytes which made casting between union and term pointers unsafe. We replaced union usage to `memcpy` which allows unaligned memory access. The true solution would be to return correctly aligned memory from memory_heap_alloc but fix for that would need a lot more testing. Signed-off-by: Jakub Gonet <[email protected]>
1 parent 40f9705 commit 086c903

File tree

1 file changed

+16
-1
lines changed

1 file changed

+16
-1
lines changed

src/libAtomVM/term.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2627,16 +2627,31 @@ static inline term term_from_float(avm_float_t f, Heap *heap)
26272627
term *boxed_value = memory_heap_alloc(heap, FLOAT_SIZE);
26282628
boxed_value[0] = ((FLOAT_SIZE - 1) << 6) | TERM_BOXED_FLOAT;
26292629

2630+
// `alignof(avm_float_t)` is different than `alignof(term)` on some archs (e.g. wasm32).
2631+
// `memory_heap_alloc` returns memory aligned to term size.
2632+
//
2633+
// Xtensa unaligned memcpy has bad codegen and this arch doesn't suffer from the alignment problem.
2634+
// See: https://gcc.gnu.org/pipermail/gcc-bugs/2023-October/839353.html
2635+
#if defined(__XTENSA__)
26302636
float_term_t *boxed_float = (float_term_t *) (boxed_value + 1);
26312637
boxed_float->f = f;
2632-
2638+
#else
2639+
memcpy(boxed_value + 1, &f, sizeof(avm_float_t));
2640+
#endif
26332641
return ((term) boxed_value) | TERM_PRIMARY_BOXED;
26342642
}
26352643

26362644
static inline avm_float_t term_to_float(term t)
26372645
{
2646+
// see `term_from_float`
2647+
#if defined(__XTENSA__)
26382648
const float_term_t *boxed_float = (float_term_t *) (term_to_const_term_ptr(t) + 1);
26392649
return boxed_float->f;
2650+
#else
2651+
avm_float_t result;
2652+
memcpy(&result, term_to_const_term_ptr(t) + 1, sizeof(avm_float_t));
2653+
return result;
2654+
#endif
26402655
}
26412656

26422657
static inline bool term_is_number(term t)

0 commit comments

Comments
 (0)