Skip to content

Commit f88079c

Browse files
committed
so/mem: generic macro
1 parent 0492d80 commit f88079c

19 files changed

Lines changed: 512 additions & 275 deletions

File tree

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,6 @@ run-c:
9797
.PHONY: bench
9898
bench:
9999
@cd bench/$(name) && go test -bench=.
100-
@CFLAGS="-Ofast -march=native -flto -funroll-loops" \
100+
@CFLAGS="-Ofast -march=native -flto -funroll-loops -DNDEBUG" \
101101
$(MIMALLOC_PRELOAD) \
102102
go run ./cmd/so run ./bench/$(name)

internal/clang/array.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ func (g *Generator) emitSliceLit(n *ast.CompositeLit) {
4949
elemType := g.mapType(n, sl.Elem())
5050
size := len(n.Elts)
5151
if size == 0 {
52-
fmt.Fprintf(w, "(so_Slice){0}")
52+
fmt.Fprintf(w, "(so_Slice){&so_Nil, 0, 0}")
5353
return
5454
}
5555
fmt.Fprintf(w, "(so_Slice){(%s[%d]){", elemType, size)

internal/clang/expr.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -106,11 +106,11 @@ func (g *Generator) emitBinaryExpr(n *ast.BinaryExpr) {
106106
}
107107
}
108108

109-
// Slice nil comparisons: emit s.ptr == NULL / != NULL.
109+
// Slice nil comparisons: emit s.ptr == &so_Nil / != &so_Nil.
110110
if n.Op == token.EQL || n.Op == token.NEQ {
111111
if _, ok := g.types.TypeOf(n.X).Underlying().(*types.Slice); ok && isNilType(g.types.TypeOf(n.Y)) {
112112
g.emitExpr(n.X)
113-
fmt.Fprintf(w, ".ptr %s NULL", n.Op.String())
113+
fmt.Fprintf(w, ".ptr %s &so_Nil", n.Op.String())
114114
return
115115
}
116116
}
@@ -535,9 +535,9 @@ func (g *Generator) emitExprAsType(node ast.Node, expr ast.Expr, targetType type
535535
return
536536
}
537537
}
538-
// Slice nil assignment: emit zero-initialized struct instead of NULL.
538+
// Slice nil assignment: emit sentinel-initialized struct instead of NULL.
539539
if _, ok := targetType.Underlying().(*types.Slice); ok && isNilType(g.types.TypeOf(expr)) {
540-
fmt.Fprintf(g.state.writer, "(so_Slice){0}")
540+
fmt.Fprintf(g.state.writer, "(so_Slice){&so_Nil, 0, 0}")
541541
return
542542
}
543543
// Map nil assignment: emit NULL.

internal/clang/types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ func (g *Generator) zeroValue(node ast.Node, typ types.Type) string {
177177

178178
// Slices.
179179
if _, ok := typ.Underlying().(*types.Slice); ok {
180-
return "{0}"
180+
return "{&so_Nil, 0, 0}"
181181
}
182182

183183
// Maps.

internal/compiler/builtin/builtin.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22
#include <stdio.h>
33
#include "builtin.h"
44

5+
// Nil sentinel: address used as the pointer for nil/empty slices.
6+
so_byte so_Nil = 0;
7+
58
// utf8_decode decodes one UTF-8 rune from string s at byte offset i.
69
// Stores the byte width in *w.
710
// Returns the decoded rune, or 0xFFFD for invalid UTF-8.

internal/compiler/builtin/builtin.h

Lines changed: 157 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -152,14 +152,18 @@ typedef struct {
152152
size_t cap;
153153
} so_Slice;
154154

155+
// Nil sentinel: address used as the pointer for nil/empty slices.
156+
// Non-NULL to satisfy static analyzers; never dereferenced.
157+
extern so_byte so_Nil;
158+
155159
// make_slice creates a zero-initialized slice on the stack.
156160
// Allocates memory on the stack until the calling function returns.
157-
#define so_make_slice(T, len, cap) ({ \
158-
size_t _cap = (cap); \
159-
size_t _n = sizeof(T) * _cap; \
160-
void* _p = so_alloca(_n); \
161-
if (_p) memset(_p, 0, _n); \
162-
(so_Slice){_p, (len), _cap}; \
161+
#define so_make_slice(T, len, cap) ({ \
162+
size_t _cap = (cap); \
163+
size_t _n = sizeof(T) * _cap; \
164+
void* _p = _n ? so_alloca(_n) : &so_Nil; \
165+
if (_n) memset(_p, 0, _n); \
166+
(so_Slice){_p, (len), _cap}; \
163167
})
164168

165169
// slice creates a slice from another slice
@@ -528,43 +532,148 @@ typedef struct so_Error_* so_Error;
528532
// --- Result types ---
529533

530534
// Result types for (T, error):
531-
typedef struct { bool val; so_Error err; } so_R_bool_err;
532-
typedef struct { double val; so_Error err; } so_R_f64_err;
533-
typedef struct { float val; so_Error err; } so_R_f32_err;
534-
typedef struct { int32_t val; so_Error err; } so_R_i32_err;
535-
typedef struct { int64_t val; so_Error err; } so_R_i64_err;
536-
typedef struct { so_byte val; so_Error err; } so_R_byte_err;
537-
typedef struct { so_int val; so_Error err; } so_R_int_err;
538-
typedef struct { so_rune val; so_Error err; } so_R_rune_err;
539-
typedef struct { so_Slice val; so_Error err; } so_R_slice_err;
540-
typedef struct { so_String val; so_Error err; } so_R_str_err;
541-
typedef struct { so_uint val; so_Error err; } so_R_uint_err;
542-
typedef struct { uint32_t val; so_Error err; } so_R_u32_err;
543-
typedef struct { uint64_t val; so_Error err; } so_R_u64_err;
544-
typedef struct { void* val; so_Error err; } so_R_ptr_err;
535+
typedef struct {
536+
bool val;
537+
so_Error err;
538+
} so_R_bool_err;
539+
typedef struct {
540+
double val;
541+
so_Error err;
542+
} so_R_f64_err;
543+
typedef struct {
544+
float val;
545+
so_Error err;
546+
} so_R_f32_err;
547+
typedef struct {
548+
int32_t val;
549+
so_Error err;
550+
} so_R_i32_err;
551+
typedef struct {
552+
int64_t val;
553+
so_Error err;
554+
} so_R_i64_err;
555+
typedef struct {
556+
so_byte val;
557+
so_Error err;
558+
} so_R_byte_err;
559+
typedef struct {
560+
so_int val;
561+
so_Error err;
562+
} so_R_int_err;
563+
typedef struct {
564+
so_rune val;
565+
so_Error err;
566+
} so_R_rune_err;
567+
typedef struct {
568+
so_Slice val;
569+
so_Error err;
570+
} so_R_slice_err;
571+
typedef struct {
572+
so_String val;
573+
so_Error err;
574+
} so_R_str_err;
575+
typedef struct {
576+
so_uint val;
577+
so_Error err;
578+
} so_R_uint_err;
579+
typedef struct {
580+
uint32_t val;
581+
so_Error err;
582+
} so_R_u32_err;
583+
typedef struct {
584+
uint64_t val;
585+
so_Error err;
586+
} so_R_u64_err;
587+
typedef struct {
588+
void* val;
589+
so_Error err;
590+
} so_R_ptr_err;
545591

546592
// Result types for (T, T):
547-
typedef struct { bool val; bool val2; } so_R_bool_bool;
548-
typedef struct { bool val; so_int val2; } so_R_bool_int;
549-
typedef struct { double val; bool val2; } so_R_f64_bool;
550-
typedef struct { double val; double val2; } so_R_f64_f64;
551-
typedef struct { double val; so_int val2; } so_R_f64_int;
552-
typedef struct { float val; bool val2; } so_R_f32_bool;
553-
typedef struct { int64_t val; int32_t val2; } so_R_i64_i32;
554-
typedef struct { so_int val; bool val2; } so_R_int_bool;
555-
typedef struct { so_int val; so_int val2; } so_R_int_int;
556-
typedef struct { so_int val; uint64_t val2; } so_R_int_u64;
557-
typedef struct { so_rune val; bool val2; } so_R_rune_bool;
558-
typedef struct { so_rune val; so_int val2; } so_R_rune_int;
559-
typedef struct { so_String val; bool val2; } so_R_str_bool;
560-
typedef struct { so_String val; so_String val2; } so_R_str_str;
561-
typedef struct { so_uint val; so_uint val2; } so_R_uint_uint;
562-
typedef struct { uint32_t val; bool val2; } so_R_u32_bool;
563-
typedef struct { uint32_t val; so_int val2; } so_R_u32_int;
564-
typedef struct { uint32_t val; uint32_t val2; } so_R_u32_u32;
565-
typedef struct { uint64_t val; bool val2; } so_R_u64_bool;
566-
typedef struct { uint64_t val; so_int val2; } so_R_u64_int;
567-
typedef struct { uint64_t val; uint64_t val2; } so_R_u64_u64;
593+
typedef struct {
594+
bool val;
595+
bool val2;
596+
} so_R_bool_bool;
597+
typedef struct {
598+
bool val;
599+
so_int val2;
600+
} so_R_bool_int;
601+
typedef struct {
602+
double val;
603+
bool val2;
604+
} so_R_f64_bool;
605+
typedef struct {
606+
double val;
607+
double val2;
608+
} so_R_f64_f64;
609+
typedef struct {
610+
double val;
611+
so_int val2;
612+
} so_R_f64_int;
613+
typedef struct {
614+
float val;
615+
bool val2;
616+
} so_R_f32_bool;
617+
typedef struct {
618+
int64_t val;
619+
int32_t val2;
620+
} so_R_i64_i32;
621+
typedef struct {
622+
so_int val;
623+
bool val2;
624+
} so_R_int_bool;
625+
typedef struct {
626+
so_int val;
627+
so_int val2;
628+
} so_R_int_int;
629+
typedef struct {
630+
so_int val;
631+
uint64_t val2;
632+
} so_R_int_u64;
633+
typedef struct {
634+
so_rune val;
635+
bool val2;
636+
} so_R_rune_bool;
637+
typedef struct {
638+
so_rune val;
639+
so_int val2;
640+
} so_R_rune_int;
641+
typedef struct {
642+
so_String val;
643+
bool val2;
644+
} so_R_str_bool;
645+
typedef struct {
646+
so_String val;
647+
so_String val2;
648+
} so_R_str_str;
649+
typedef struct {
650+
so_uint val;
651+
so_uint val2;
652+
} so_R_uint_uint;
653+
typedef struct {
654+
uint32_t val;
655+
bool val2;
656+
} so_R_u32_bool;
657+
typedef struct {
658+
uint32_t val;
659+
so_int val2;
660+
} so_R_u32_int;
661+
typedef struct {
662+
uint32_t val;
663+
uint32_t val2;
664+
} so_R_u32_u32;
665+
typedef struct {
666+
uint64_t val;
667+
bool val2;
668+
} so_R_u64_bool;
669+
typedef struct {
670+
uint64_t val;
671+
so_int val2;
672+
} so_R_u64_int;
673+
typedef struct {
674+
uint64_t val;
675+
uint64_t val2;
676+
} so_R_u64_u64;
568677

569678
// --- Printing ---
570679

@@ -585,12 +694,18 @@ static inline void* unsafe_Add(void* ptr, size_t offset) {
585694
return (char*)ptr + offset;
586695
}
587696
static inline so_String unsafe_String(void* ptr, size_t len) {
588-
return (so_String){(const char*)ptr, len};
697+
if (ptr == NULL) {
698+
return (so_String){(char*)&so_Nil, 0};
699+
}
700+
return (so_String){(char*)ptr, len};
589701
}
590702
static inline so_byte* unsafe_StringData(so_String s) {
591703
return (so_byte*)s.ptr;
592704
}
593705
static inline so_Slice unsafe_Slice(void* ptr, size_t len) {
706+
if (ptr == NULL) {
707+
return (so_Slice){&so_Nil, 0, 0};
708+
}
594709
return (so_Slice){ptr, len, len};
595710
}
596711
static inline void* unsafe_SliceData(so_Slice s) {

0 commit comments

Comments
 (0)