Skip to content
Draft

Simd #11

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
b773dce
Support for SIMD vector instructions (incomplete)
dstogov Jul 3, 2026
819b7b8
Allow opeartions between vectors and scalar constants if the constant…
dstogov Jul 6, 2026
565535f
Fix incorrect warning
dstogov Jul 6, 2026
413d9c7
Fix incorrect IR generation for vector initialization
dstogov Jul 7, 2026
64ae596
Fix nested vector initialization
dstogov Jul 7, 2026
cf2f2c0
Support for __builtin_convertvector()
dstogov Jul 7, 2026
77be7cf
Support for __builtin_shufflevector()
dstogov Jul 7, 2026
7c9056d
Support for __builtin_shuffle()
dstogov Jul 7, 2026
fd6080b
Add "--emit-c" options (just for verification)
dstogov Jul 7, 2026
da55f6a
Fix memory leaks
dstogov Jul 7, 2026
2470163
Vectors can't be used as boolean condition with "if", "&&", "||", "!"
dstogov Jul 7, 2026
a42f52d
Don't emit symbols for global register variables
dstogov Jul 8, 2026
68aace9
Fix vectors handling
dstogov Jul 8, 2026
809e8d5
Disallow "%", "|", "&", "^", "<<", ">>" for floating point vectors
dstogov Jul 9, 2026
0c03019
Add "-m[no-]avx2" option
dstogov Jul 9, 2026
e81dbbc
Fix empty vector initialzation "t v = {};"
dstogov Jul 10, 2026
ec51e5d
Add tests for x86 SIMD vector instructions
dstogov Jul 10, 2026
f5f7577
Fix missing EXTRACT
dstogov Jul 14, 2026
bbdc648
Add more test for vector opearations
dstogov Jul 14, 2026
66eaf2b
Convert second operand of vector shifts according to x86 sematick
dstogov Jul 14, 2026
9bdcd40
Avoid memset() for vectors
dstogov Jul 14, 2026
e4b42e3
Fix type conversion
dstogov Jul 14, 2026
a9b53cb
Improve vector SIMD instruction support
dstogov Jul 15, 2026
534a16b
Fix IR vector types encoding
dstogov Jul 15, 2026
c37efcb
Update SHUFFLE tests
dstogov Jul 15, 2026
29c084e
Construct SHL/SHR/SAR with vector and scalar operand (without SPLAT f…
dstogov Jul 16, 2026
25f4a52
Add more tests
dstogov Jul 16, 2026
f4b9df7
Run test suite for SIMD branch
dstogov Jul 21, 2026
6765623
Run test suite for SIMD branch
dstogov Jul 21, 2026
82310c3
Add vector truncation tests
dstogov Jul 23, 2026
cb30826
Add AVX tests
dstogov Jul 24, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/push.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ jobs:
uses: actions/checkout@v5
with:
repository: dstogov/ir
ref: simd
path: ir
- name: make ir
run: |
Expand Down Expand Up @@ -73,6 +74,7 @@ jobs:
uses: actions/checkout@v5
with:
repository: dstogov/ir
ref: simd
path: ir
- name: make ir
run: |
Expand Down Expand Up @@ -103,6 +105,7 @@ jobs:
uses: actions/checkout@v5
with:
repository: dstogov/ir
ref: simd
path: ir
- name: make ir
run: |
Expand All @@ -128,6 +131,7 @@ jobs:
uses: actions/checkout@v5
with:
repository: dstogov/ir
ref: simd
path: ir
- name: Prepare env
shell: powershell
Expand Down
10 changes: 9 additions & 1 deletion c.g
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ attrib(rcc_ctx *rcc, c_dcl *d): {c_name name = sym;}
"(" constant_expression(rcc, &v) ")" {c_gcc_attribute_regparm(rcc, d, name, &v);}
| ("unused"|"__unused__") {d->attr |= C_ATTR_UNUSED;}
| ("vector_size"|"__vector_size__") {c_value_clear(&v);}
( "(" constant_expression(rcc, &v) ")" )? {yy_error_fmt("unsupported attribute \"%s\"", yy_sym2str(rcc, name));}
( "(" constant_expression(rcc, &v) ")" )? {c_gcc_attribute_vector_size(rcc, d, name, &v);}
| ("weak"|"__weak__") {d->attr |= C_ATTR_WEAK;}
| ID(rcc, &name) {sym = c_gcc_attribute(rcc, d, name, sym);}
)?
Expand Down Expand Up @@ -1205,6 +1205,8 @@ unary_expression(rcc_ctx *rcc, c_value *val):
| "__builtin_umul_overflow"
| "__builtin_umull_overflow"
| "__builtin_umulll_overflow"
| "__builtin_shuffle"
| "__builtin_shufflevector"
)
"(" builtin_parameters(rcc, &v, name) ")"
| {ir_ref old = c_do_nocode(rcc);}
Expand All @@ -1218,6 +1220,12 @@ unary_expression(rcc_ctx *rcc, c_value *val):
","
type_name(rcc, &t) {c_do_builtin_va_arg(rcc, &v, t);}
")"
| "__builtin_convertvector"
"("
assignment_expression(rcc, &v)
","
type_name(rcc, &t) {c_do_builtin_convertvector(rcc, &v, t);}
")"
)
( {c_value dim;}
{c_value_clear(&dim);}
Expand Down
115 changes: 110 additions & 5 deletions rcc.c
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,8 @@

#define C_DUMP_LIVE_RANGES (1<<25)

#define C_DUMP_C (1<<26)

#define C_SINGLE_FILE (1<<29)
#define C_DO_LINK_INTERNAL (1<<30)
#define C_DO_LINK_EXTERNAL (1U<<31)
Expand Down Expand Up @@ -595,9 +597,15 @@ static void* c_linker_resolve_sym_name(ir_loader *loader, ir_ctx *ctx, ir_str _n
return NULL;
}

void *c_linker_allocate_data(rcc_ctx *rcc, c_name name, size_t size, size_t align)
void *c_linker_allocate_data(rcc_ctx *rcc, c_name name, size_t size, size_t align, bool is_array)
{
void *data = ir_arena_alloc_aligned(&rcc->c_linker_arena, size, align);
void *data;

if (is_array && size >= 16 && align < 16) {
/* global array variable of length at least 16 bytes always has alignment of at least 16 byte */
align = 16;
}
data = ir_arena_alloc_aligned(&rcc->c_linker_arena, size, align);
if (UNEXPECTED(!data)) yy_error("not enough memory to allocate data");
if (align < 8) {
align = 8;
Expand Down Expand Up @@ -1144,7 +1152,7 @@ static void rcc_fix_flexible_data(rcc_ctx *rcc)
p->sym->value.type = type;

p->sym->value.u.optx = IR_OPT(C_VAL_CONST, IR_ADDR);
p->sym->value.u.val.ptr = c_linker_allocate_data(rcc, i, type->size, c_attr2align(type->attr));
p->sym->value.u.val.ptr = c_linker_allocate_data(rcc, i, type->size, c_attr2align(type->attr), 1);
p->sym->is_implemented = 1;

//yy_warning_fmt("array \"%s\" assumed to have one element", p->str); // error position ???
Expand Down Expand Up @@ -1303,6 +1311,15 @@ static size_t rcc_emit_ir_data(rcc_ctx *rcc, FILE *f, const c_type *type, const
offset++;
}
return offset;
} else if (type->kind == C_TYPE_VECTOR) {
size_t offset = 0, el_offset = 0;
int i;

for (i = 0; i < type->vec.length; el_offset += type->vec.type->size, i++) {
IR_ASSERT(offset == el_offset);
offset += rcc_emit_ir_data(rcc, f, type->vec.type, (const char*)addr + el_offset, base + el_offset, rel);
}
return offset;
} else {
IR_ASSERT(0);
}
Expand Down Expand Up @@ -1389,7 +1406,9 @@ static void rcc_emit_ir(rcc_ctx *rcc, FILE *f)
if (p->sym && p->sym->kind == C_SYM_VAR) {
size_t size;

if (p->sym->linkage == C_LINK_INTERNAL) {
if (p->sym->linkage == C_LINK_NONE) {
continue;
} else if (p->sym->linkage == C_LINK_INTERNAL) {
fprintf(f, "static ");
} else if (p->sym->is_external || !c_value_is_set(&p->sym->value)) {
if (p->sym->alias) continue;
Expand Down Expand Up @@ -1493,6 +1512,80 @@ static void rcc_emit_llvm(rcc_ctx *rcc, FILE *f)
}
}

static void rcc_emit_c_proto(rcc_ctx *rcc, const char *name, c_sym *func, FILE *f)
{
const c_type *t = func->value.type;
uint32_t flags;
ir_type ret_type;
uint32_t params_count;
uint8_t *param_types;

IR_ASSERT(t->kind == C_TYPE_FUNC);
param_types = alloca(t->func.num_params + 16);
c_type2proto_ex(rcc, t, &flags, &ret_type, &params_count, param_types);
if (func->linkage == C_LINK_INTERNAL) {
flags |= IR_STATIC;
} else if (func->linkage == C_LINK_BUILTIN) {
flags |= IR_CC_BUILTIN;
}
ir_emit_c_func_decl(name, flags, ret_type, params_count, param_types, f);
}

static void rcc_emit_c(rcc_ctx *rcc, FILE *f)
{
uint32_t i;
yy_hash_bucket *p;

for (i = YY_LAST_KEYWORD + 1, p = rcc->yy_hash.data + i; i < rcc->yy_hash.count; p++, i++) {
if (p->sym && p->sym->kind == C_SYM_FUNC && !p->sym->ctx) {
if ((p->sym->is_external || !p->sym->ctx) && p->sym->alias) continue;
rcc_emit_c_proto(rcc, p->str, p->sym, f);
}
}

for (i = YY_LAST_KEYWORD + 1, p = rcc->yy_hash.data + i; i < rcc->yy_hash.count; p++, i++) {
if (p->sym && p->sym->kind == C_SYM_VAR) {
uint32_t flags = 0;
const char *str;

if (p->sym->linkage == C_LINK_INTERNAL) {
flags |= IR_STATIC;
} else if (p->sym->is_external || !c_value_is_set(&p->sym->value)) {
flags |= IR_EXTERN;
}
if (c_is_type_const(p->sym->value.type)) {
flags |= IR_CONST;
}
if (p->sym->alias) {
str = rcc->yy_hash.data[p->sym->alias].str;
} else {
str = p->str;
}
//TODO: type ???
ir_emit_c_sym_decl(str, flags, f);
//TODO: initializer ???
}
}

for (i = YY_LAST_KEYWORD + 1, p = rcc->yy_hash.data + i; i < rcc->yy_hash.count; p++, i++) {
if (p->sym && p->sym->kind == C_SYM_FUNC && p->sym->ctx) {
ir_ctx *ctx = p->sym->ctx;
bool cleanup = 0;

if (!ctx->vregs) {
ir_assign_virtual_registers(ctx);
ir_compute_dessa_moves(ctx);
cleanup = 1;
}
ir_emit_c(ctx, p->str, f);
if (cleanup) {
ir_mem_free(ctx->vregs);
ctx->vregs = NULL;
}
}
}
}

static int rcc_preprocess(rcc_ctx *rcc, const char *file_name, FILE *f)
{
if (!rcc_read(rcc, file_name)) {
Expand Down Expand Up @@ -1520,6 +1613,9 @@ static int rcc_compile(rcc_ctx *rcc, const char *file_name)
if (rcc->c_flags & C_DUMP_LLVM) {
rcc_emit_llvm(rcc, rcc->output);
}
if (rcc->c_flags & C_DUMP_C) {
rcc_emit_c(rcc, rcc->output);
}
if (ir_list_capasity(&rcc->codegen_queue)) {
do {
c_name name = ir_list_pop(&rcc->codegen_queue);
Expand Down Expand Up @@ -1852,6 +1948,7 @@ static void rcc_help(const char *cmd)
" -m[no-]sse4 - enable/disable SSE4 instruction set\n"
" -m[no-]sse4.1 - enable/disable SSE4.1 instruction set\n"
" -m[no-]sse4.2 - enable/disable SSE4.2 instruction set\n"
" -m[no-]avx2 - enable/disable AVX2 instruction set\n"
#endif
" -muse-fp - use base frame pointer register\n"
#if defined(IR_TARGET_X86)
Expand Down Expand Up @@ -2091,6 +2188,12 @@ static int rcc_parse_option(rcc_ctx *rcc, const char *opt, const char *arg, bool
} else if (strcmp(opt, "-mno-sse4.2") == 0) {
rcc->ir_mflags &= ~IR_X86_SSE42;
rcc->ir_mflags_disabled |= IR_X86_SSE42;
} else if (strcmp(opt, "-mavx2") == 0) {
rcc->ir_mflags |= IR_X86_AVX2;
rcc->ir_mflags_disabled &= ~IR_X86_AVX2;
} else if (strcmp(opt, "-mno-avx2") == 0) {
rcc->ir_mflags &= ~IR_X86_AVX2;
rcc->ir_mflags_disabled |= IR_X86_AVX2;
#endif
} else if (strcmp(opt, "-muse-fp") == 0) {
rcc->ir_flags |= IR_USE_FRAME_POINTER;
Expand Down Expand Up @@ -2316,6 +2419,8 @@ int main(int argc, const char **argv)
rcc->c_flags |= C_DUMP_IR;
} else if (strcmp(argv[i], "--emit-llvm") == 0) {
rcc->c_flags |= C_DUMP_LLVM;
} else if (strcmp(argv[i], "--emit-c") == 0) {
rcc->c_flags |= C_DUMP_C;
} else if (strcmp(argv[i], "-S") == 0) {
rcc->c_flags |= C_DUMP_ASM;
} else if (strcmp(argv[i], "--dump-size") == 0) {
Expand Down Expand Up @@ -2479,7 +2584,7 @@ int main(int argc, const char **argv)
return 1;
}
}
rcc->ir_mflags |= (cpuinfo & (IR_X86_SSE3|IR_X86_SSSE3|IR_X86_SSE41|IR_X86_SSE42|IR_X86_BMI1)) & ~rcc->ir_mflags_disabled;
rcc->ir_mflags |= (cpuinfo & (IR_X86_SSE3|IR_X86_SSSE3|IR_X86_SSE41|IR_X86_SSE42|IR_X86_AVX2|IR_X86_BMI1)) & ~rcc->ir_mflags_disabled;
#endif
}

Expand Down
21 changes: 19 additions & 2 deletions rcc.h
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,9 @@
_("__builtin_umul_overflow", YY___BUILTIN_UMUL_OVERFLOW) \
_("__builtin_umull_overflow", YY___BUILTIN_UMULL_OVERFLOW) \
_("__builtin_umulll_overflow", YY___BUILTIN_UMULLL_OVERFLOW) \
_("__builtin_convertvector", YY___BUILTIN_CONVERTVECTOR) \
_("__builtin_shuffle", YY___BUILTIN_SHUFFLE) \
_("__builtin_shufflevector", YY___BUILTIN_SHUFFLEVECTOR) \
_("__builtin_expect", YY___BUILTIN_EXPECT) \
_("__builtin_prefetch", YY___BUILTIN_PREFETCH) \
_("__builtin_unreachable", YY___BUILTIN_UNREACHABLE) \
Expand Down Expand Up @@ -730,6 +733,7 @@ typedef enum {
C_TYPE_ARRAY,
C_TYPE_STRUCT,
C_TYPE_UNION,
C_TYPE_VECTOR,
C_TYPE_FLOAT_COMPLEX,
C_TYPE_DOUBLE_COMPLEX,
C_TYPE_LONG_DOUBLE_COMPLEX,
Expand All @@ -756,6 +760,7 @@ typedef enum {
C_TYPE_INPROGRESS = (1<<1), /* incomplete (not completely defined) struct, union */
C_TYPE_GLOBAL = (1<<2),
C_TYPE_IN_FUNC = (1<<3),
C_TYPE_OPAQUE = (1<<4), /* opaque vector */
} c_type_flag;

typedef yy_sym c_name;
Expand Down Expand Up @@ -797,6 +802,10 @@ struct _c_type {
const c_type *ret_type;
c_param *params;
} func;
struct {
const c_type *type;
int32_t length;
} vec;
c_name tag;
};
};
Expand Down Expand Up @@ -824,6 +833,7 @@ struct _c_dcl {
c_name cleanup_func; /* may be set for local variables */
int8_t reg;
uint32_t attr2;
uint32_t vector_size;
};

typedef enum {
Expand Down Expand Up @@ -892,14 +902,19 @@ struct _c_tag {
#define C_CODE_STARTED 2
#define C_CODE_DONE 3

#define C_IS_BIT_FIELD(bit_field) ((bit_field) != 0)
#define C_IS_SIMPLE_VAL(bit_field) ((bit_field) == 0)
#define C_IS_BIT_FIELD(bit_field) ((bit_field) & (1 << 12))
#define C_BIT_FIELD(start, lenght) ((1 << 12) | ((start) << 6) | (lenght))
#define C_BIT_FIELD_START(bit_field) (((bit_field) >> 6) & 0x3f)
#define C_BIT_FIELD_SIZE(bit_field) ((bit_field) & 0x3f)

#define C_IS_BIT_FIELD_PACKED(bit_field) ((bit_field) & (1 << 13))
#define C_SET_BIT_FIELD_PACKED(bit_field) do {(bit_field) |= (1 << 13);} while (0)

#define C_IS_VECTOR_DIM(proto) ((proto) & (1 << 14))
#define C_VECTOR_DIM(type) ((1 << 14) | (type))
#define C_VECTOR_DIM_TYPE(proto) (proto & 0xff)

struct _c_field {
c_name name;
uint16_t bit_field; /* 1-bit - is bit-field, 6-bits - first bit, 6-bits - bit lenght */
Expand Down Expand Up @@ -1099,6 +1114,7 @@ void c_gcc_attribute_aligned(rcc_ctx *rcc, c_dcl *d, c_name attr, c_value *v);
void c_gcc_attribute_packed(rcc_ctx *rcc, c_dcl *d, c_name attr);
void c_gcc_attribute_cleanup(rcc_ctx *rcc, c_dcl *d, c_name attr, c_name func);
void c_gcc_attribute_regparm(rcc_ctx *rcc, c_dcl *d, c_name attr, c_value *v);
void c_gcc_attribute_vector_size(rcc_ctx *rcc, c_dcl *d, c_name attr, c_value *v);
yy_sym c_gcc_attribute(rcc_ctx *rcc, c_dcl *dcl, c_name attr, yy_sym sym);
void c_gcc_attribute_alias(rcc_ctx *rcc, c_dcl *d, c_name attr, c_value *v);
void c_asm_alias(rcc_ctx *rcc, c_dcl *d, c_value *v);
Expand Down Expand Up @@ -1143,6 +1159,7 @@ c_value *c_do_grow_actual_parameters(c_value *args, int32_t num_args);
void c_do_builtin(rcc_ctx *rcc, c_value *val, c_name name, int32_t num_args, c_value *args);
void c_do_builtin_constant_p(rcc_ctx *rcc, c_value *val);
void c_do_builtin_va_arg(rcc_ctx *rcc, c_value *val, const c_type *type);
void c_do_builtin_convertvector(rcc_ctx *rcc, c_value *val, const c_type *type);
void c_do_call(rcc_ctx *rcc, c_value *func, int32_t num_args, c_value *args, c_value *res);
void c_do_binary_op(rcc_ctx *rcc, yy_sym sym, c_value *v, c_value *op2);
void c_do_assign_op(rcc_ctx *rcc, yy_sym sym, c_value *v, c_value *op2);
Expand Down Expand Up @@ -1288,7 +1305,7 @@ void yy_warning_(rcc_ctx *rcc, uint32_t kind, const char *msg);
void yy_warning_fmt_(rcc_ctx *rcc, uint32_t kind, const char *fmt, ...);

/* Linker */
void *c_linker_allocate_data(rcc_ctx *rcc, c_name name, size_t size, size_t align);
void *c_linker_allocate_data(rcc_ctx *rcc, c_name name, size_t size, size_t align, bool is_array);
bool c_linker_fix_reloc(rcc_ctx *rcc, c_sym *obj, size_t obj_offset, c_value *val);
void c_linker_del_reloc(rcc_ctx *rcc, c_sym *obj, size_t obj_offset);

Expand Down
Loading
Loading