mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-02 12:48:14 +00:00
Remove scalar*vector; swizzle; broadcast
This commit is contained in:
@@ -123,6 +123,7 @@ enum BuiltinProcId {
|
||||
BuiltinProc_cap,
|
||||
BuiltinProc_copy,
|
||||
BuiltinProc_append,
|
||||
BuiltinProc_swizzle,
|
||||
BuiltinProc_print,
|
||||
BuiltinProc_println,
|
||||
|
||||
@@ -149,8 +150,12 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
|
||||
{STR_LIT("cap"), 1, false, Expression_Expression},
|
||||
{STR_LIT("copy"), 2, false, Expression_Expression},
|
||||
{STR_LIT("append"), 2, false, Expression_Expression},
|
||||
|
||||
{STR_LIT("swizzle"), 1, true, Expression_Expression},
|
||||
|
||||
{STR_LIT("print"), 1, true, Expression_Statement},
|
||||
{STR_LIT("println"), 1, true, Expression_Statement},
|
||||
|
||||
};
|
||||
|
||||
struct CheckerContext {
|
||||
|
||||
+65
-6
@@ -409,10 +409,7 @@ Type *check_type(Checker *c, AstNode *e, Type *named_type) {
|
||||
case_ast_node(pt, ProcType, e);
|
||||
type = alloc_type(c->allocator, Type_Proc);
|
||||
set_base_type(named_type, type);
|
||||
CheckerContext context = c->context;
|
||||
c->context.scope = make_scope(c->context.scope, c->allocator);
|
||||
check_procedure_type(c, type, e);
|
||||
c->context = context;
|
||||
goto end;
|
||||
case_end;
|
||||
|
||||
@@ -979,7 +976,10 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (token_is_shift(be->op)) {
|
||||
Token op = be->op;
|
||||
|
||||
|
||||
if (token_is_shift(op)) {
|
||||
check_shift(c, x, y, node);
|
||||
return;
|
||||
}
|
||||
@@ -992,7 +992,6 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
|
||||
return;
|
||||
}
|
||||
|
||||
Token op = be->op;
|
||||
if (token_is_comparison(op)) {
|
||||
check_comparison(c, x, y, op);
|
||||
return;
|
||||
@@ -1616,6 +1615,54 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
operand->mode = Addressing_Value;
|
||||
} break;
|
||||
|
||||
case BuiltinProc_swizzle: {
|
||||
// swizzle :: proc(v: {N}T, T...) -> {M}T
|
||||
Type *vector_type = get_base_type(operand->type);
|
||||
if (!is_type_vector(vector_type)) {
|
||||
gbString type_str = type_to_string(operand->type);
|
||||
defer (gb_string_free(type_str));
|
||||
error(&c->error_collector, ast_node_token(call),
|
||||
"You can only `swizzle` a vector, got `%s`",
|
||||
type_str);
|
||||
return false;
|
||||
}
|
||||
|
||||
isize max_count = vector_type->vector.count;
|
||||
isize arg_count = 0;
|
||||
for (AstNode *arg = ce->arg_list->next; arg != NULL; arg = arg->next) {
|
||||
Operand op = {};
|
||||
check_expr(c, &op, arg);
|
||||
if (op.mode == Addressing_Invalid)
|
||||
return false;
|
||||
Type *arg_type = get_base_type(op.type);
|
||||
if (!is_type_integer(arg_type) || op.mode != Addressing_Constant) {
|
||||
error(&c->error_collector, ast_node_token(op.expr), "Indices to `swizzle` must be constant integers");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (op.value.value_integer < 0) {
|
||||
error(&c->error_collector, ast_node_token(op.expr), "Negative `swizzle` index");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (max_count <= op.value.value_integer) {
|
||||
error(&c->error_collector, ast_node_token(op.expr), "`swizzle` index exceeds vector length");
|
||||
return false;
|
||||
}
|
||||
|
||||
arg_count++;
|
||||
}
|
||||
|
||||
if (arg_count > max_count) {
|
||||
error(&c->error_collector, ast_node_token(call), "Too many `swizzle` indices, %td > %td", arg_count, max_count);
|
||||
return false;
|
||||
}
|
||||
|
||||
Type *elem_type = vector_type->vector.elem;
|
||||
operand->type = make_type_vector(c->allocator, elem_type, arg_count);
|
||||
operand->mode = Addressing_Value;
|
||||
}
|
||||
|
||||
case BuiltinProc_print:
|
||||
case BuiltinProc_println: {
|
||||
for (AstNode *arg = ce->arg_list; arg != NULL; arg = arg->next) {
|
||||
@@ -1958,7 +2005,12 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ
|
||||
if (t->kind == Type_Array &&
|
||||
t->array.count >= 0 &&
|
||||
index >= t->array.count) {
|
||||
error(&c->error_collector, ast_node_token(elem), "Index %lld is out of bounds (>= %lld)", index, t->array.count);
|
||||
error(&c->error_collector, ast_node_token(elem), "Index %lld is out of bounds (>= %lld) for array literal", index, t->array.count);
|
||||
}
|
||||
if (t->kind == Type_Vector &&
|
||||
t->vector.count >= 0 &&
|
||||
index >= t->vector.count) {
|
||||
error(&c->error_collector, ast_node_token(elem), "Index %lld is out of bounds (>= %lld) for vector literal", index, t->vector.count);
|
||||
}
|
||||
|
||||
Operand o = {};
|
||||
@@ -1968,6 +2020,13 @@ ExpressionKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *typ
|
||||
if (max < index)
|
||||
max = index;
|
||||
|
||||
if (t->kind == Type_Vector) {
|
||||
if (t->vector.count > 1 && gb_is_between(index, 2, t->vector.count-1)) {
|
||||
error(&c->error_collector, ast_node_token(cl->elem_list),
|
||||
"Expected either 1 (broadcast) or %td elements in vector literal, got %td", t->vector.count, index);
|
||||
}
|
||||
}
|
||||
|
||||
if (t->kind == Type_Array && ellipsis_array) {
|
||||
t->array.count = max;
|
||||
}
|
||||
|
||||
@@ -369,18 +369,6 @@ void check_type_decl(Checker *c, Entity *e, AstNode *type_expr, Type *named_type
|
||||
set_base_type(named, get_base_type(get_base_type(named)));
|
||||
}
|
||||
|
||||
void check_alias_decl(Checker *c, Entity *e, AstNode *type_expr, Type *alias_type) {
|
||||
GB_ASSERT(e->type == NULL);
|
||||
Type *named = make_type_alias(c->allocator, e->token.string, NULL, e);
|
||||
named->alias.alias_name = e;
|
||||
set_base_type(alias_type, named);
|
||||
e->type = named;
|
||||
|
||||
check_type(c, type_expr, named);
|
||||
|
||||
set_base_type(named, get_base_type(get_base_type(named)));
|
||||
}
|
||||
|
||||
void check_proc_body(Checker *c, Token token, DeclInfo *decl, Type *type, AstNode *body) {
|
||||
GB_ASSERT(body->kind == AstNode_BlockStmt);
|
||||
|
||||
@@ -496,9 +484,6 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
|
||||
case Entity_TypeName:
|
||||
check_type_decl(c, e, d->type_expr, named_type);
|
||||
break;
|
||||
case Entity_AliasName:
|
||||
check_alias_decl(c, e, d->type_expr, named_type);
|
||||
break;
|
||||
case Entity_Procedure:
|
||||
check_proc_decl(c, e, d, true);
|
||||
break;
|
||||
|
||||
+2
-36
@@ -64,7 +64,6 @@ struct BasicType {
|
||||
TYPE_KIND(Structure), \
|
||||
TYPE_KIND(Pointer), \
|
||||
TYPE_KIND(Named), \
|
||||
TYPE_KIND(Alias), \
|
||||
TYPE_KIND(Tuple), \
|
||||
TYPE_KIND(Proc), \
|
||||
TYPE_KIND(Count),
|
||||
@@ -110,11 +109,6 @@ struct Type {
|
||||
Type * base;
|
||||
Entity *type_name; // Entity_TypeName
|
||||
} named;
|
||||
struct {
|
||||
String name;
|
||||
Type * base;
|
||||
Entity *alias_name; // Entity_AliasName
|
||||
} alias;
|
||||
struct {
|
||||
Entity **variables; // Entity_Variable
|
||||
isize variable_count;
|
||||
@@ -130,12 +124,8 @@ struct Type {
|
||||
};
|
||||
|
||||
Type *get_base_type(Type *t) {
|
||||
while (t->kind == Type_Named || t->kind == Type_Alias) {
|
||||
if (t->kind == Type_Named) {
|
||||
t = t->named.base;
|
||||
} else {
|
||||
t = t->alias.base;
|
||||
}
|
||||
while (t->kind == Type_Named) {
|
||||
t = t->named.base;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
@@ -143,8 +133,6 @@ Type *get_base_type(Type *t) {
|
||||
void set_base_type(Type *t, Type *base) {
|
||||
if (t && t->kind == Type_Named) {
|
||||
t->named.base = base;
|
||||
} else if (t && t->kind == Type_Alias) {
|
||||
t->alias.base = base;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,14 +189,6 @@ Type *make_type_named(gbAllocator a, String name, Type *base, Entity *type_name)
|
||||
return t;
|
||||
}
|
||||
|
||||
Type *make_type_alias(gbAllocator a, String name, Type *base, Entity *alias_name) {
|
||||
Type *t = alloc_type(a, Type_Alias);
|
||||
t->alias.name = name;
|
||||
t->alias.base = base;
|
||||
t->alias.alias_name = alias_name;
|
||||
return t;
|
||||
}
|
||||
|
||||
Type *make_type_tuple(gbAllocator a) {
|
||||
Type *t = alloc_type(a, Type_Tuple);
|
||||
return t;
|
||||
@@ -465,16 +445,11 @@ b32 are_types_identical(Type *x, Type *y) {
|
||||
return are_types_identical(x->pointer.elem, y->pointer.elem);
|
||||
break;
|
||||
|
||||
|
||||
case Type_Alias:
|
||||
return are_types_identical(get_base_type(x), y);
|
||||
|
||||
case Type_Named:
|
||||
if (y->kind == Type_Named)
|
||||
return x->named.base == y->named.base;
|
||||
break;
|
||||
|
||||
|
||||
case Type_Tuple:
|
||||
if (y->kind == Type_Tuple) {
|
||||
if (x->tuple.variable_count == y->tuple.variable_count) {
|
||||
@@ -737,15 +712,6 @@ gbString write_type_to_string(gbString str, Type *type) {
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_Alias:
|
||||
if (type->alias.alias_name != NULL) {
|
||||
str = gb_string_append_length(str, type->alias.name.text, type->alias.name.len);
|
||||
} else {
|
||||
// NOTE(bill): Just in case
|
||||
str = gb_string_appendc(str, "<alias type>");
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_Tuple:
|
||||
if (type->tuple.variable_count > 0) {
|
||||
for (isize i = 0; i < type->tuple.variable_count; i++) {
|
||||
|
||||
@@ -164,9 +164,6 @@ void ssa_print_type(gbFile *f, BaseTypeSizes s, Type *t) {
|
||||
case Type_Named:
|
||||
ssa_print_encoded_local(f, t->named.name);
|
||||
break;
|
||||
case Type_Alias:
|
||||
ssa_print_type(f, s, t->alias.base);
|
||||
break;
|
||||
case Type_Tuple:
|
||||
if (t->tuple.variable_count == 1) {
|
||||
ssa_print_type(f, s, t->tuple.variables[0]->type);
|
||||
@@ -635,6 +632,29 @@ void ssa_print_instr(gbFile *f, ssaModule *m, ssaValue *value) {
|
||||
ssa_fprintf(f, "\n");
|
||||
} break;
|
||||
|
||||
case ssaInstr_ShuffleVector: {
|
||||
auto *sv = &instr->shuffle_vector;
|
||||
Type *vt = ssa_value_type(sv->vector);
|
||||
ssa_fprintf(f, "%%%d = shufflevector ", value->id);
|
||||
|
||||
ssa_print_type(f, m->sizes, vt);
|
||||
ssa_fprintf(f, " ");
|
||||
ssa_print_value(f, m, sv->vector, vt);
|
||||
ssa_fprintf(f, ", ");
|
||||
ssa_print_type(f, m->sizes, vt);
|
||||
ssa_fprintf(f, " undef,");
|
||||
|
||||
ssa_fprintf(f, " <%td x i32> <", sv->index_count);
|
||||
for (isize i = 0; i < sv->index_count; i++) {
|
||||
if (i > 0) {
|
||||
ssa_fprintf(f, ", ");
|
||||
}
|
||||
ssa_fprintf(f, "i32 %d", sv->indices[i]);
|
||||
}
|
||||
ssa_fprintf(f, ">");
|
||||
ssa_fprintf(f, "\n");
|
||||
} break;
|
||||
|
||||
|
||||
default: {
|
||||
GB_PANIC("<unknown instr> %d\n", instr->kind);
|
||||
|
||||
+72
-1
@@ -208,6 +208,12 @@ struct ssaInstr {
|
||||
ssaValue *elem;
|
||||
ssaValue *index;
|
||||
} insert_element;
|
||||
struct {
|
||||
ssaValue *vector;
|
||||
i32 *indices;
|
||||
isize index_count;
|
||||
Type *type;
|
||||
} shuffle_vector;
|
||||
|
||||
struct {} startup_runtime;
|
||||
};
|
||||
@@ -291,8 +297,9 @@ ssaLvalue ssa_make_lvalue_vector(ssaValue *address, ssaValue *index, AstNode *ex
|
||||
|
||||
|
||||
void ssa_module_init(ssaModule *m, Checker *c) {
|
||||
// TODO(bill): Determine a decent size for the arena
|
||||
isize token_count = c->parser->total_token_count;
|
||||
isize arena_size = 3 * token_count * gb_size_of(ssaValue);
|
||||
isize arena_size = 4 * token_count * gb_size_of(ssaValue);
|
||||
gb_arena_init_from_allocator(&m->arena, gb_heap_allocator(), arena_size);
|
||||
m->allocator = gb_arena_allocator(&m->arena);
|
||||
m->info = &c->info;
|
||||
@@ -354,6 +361,8 @@ Type *ssa_instr_type(ssaInstr *instr) {
|
||||
} break;
|
||||
case ssaInstr_InsertElement:
|
||||
return ssa_value_type(instr->insert_element.vector);
|
||||
case ssaInstr_ShuffleVector:
|
||||
return instr->shuffle_vector.type;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -651,6 +660,21 @@ ssaValue *ssa_make_instr_insert_element(ssaProcedure *p, ssaValue *vector, ssaVa
|
||||
return v;
|
||||
}
|
||||
|
||||
ssaValue *ssa_make_instr_shuffle_vector(ssaProcedure *p, ssaValue *vector, i32 *indices, isize index_count) {
|
||||
ssaValue *v = ssa_alloc_instr(p->module->allocator, ssaInstr_ShuffleVector);
|
||||
v->instr.shuffle_vector.vector = vector;
|
||||
v->instr.shuffle_vector.indices = indices;
|
||||
v->instr.shuffle_vector.index_count = index_count;
|
||||
|
||||
Type *vt = get_base_type(ssa_value_type(vector));
|
||||
v->instr.shuffle_vector.type = make_type_vector(p->module->allocator, vt->vector.elem, index_count);
|
||||
|
||||
if (p->curr_block) {
|
||||
gb_array_append(p->curr_block->values, v);
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
ssaValue *ssa_make_instr_no_op(ssaProcedure *p) {
|
||||
ssaValue *v = ssa_alloc_instr(p->module->allocator, ssaInstr_NoOp);
|
||||
if (p->curr_block) {
|
||||
@@ -1379,6 +1403,23 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t) {
|
||||
return ssa_emit_load(proc, slice);
|
||||
}
|
||||
|
||||
if (is_type_vector(dst)) {
|
||||
Type *dst_elem = dst->vector.elem;
|
||||
value = ssa_emit_conv(proc, value, dst_elem);
|
||||
ssaValue *v = ssa_add_local_generated(proc, t);
|
||||
v = ssa_emit_load(proc, v);
|
||||
v = ssa_emit(proc, ssa_make_instr_insert_element(proc, v, value, v_zero32));
|
||||
// NOTE(bill): Broadcast lowest value to all values
|
||||
isize index_count = dst->vector.count;
|
||||
i32 *indices = gb_alloc_array(proc->module->allocator, i32, index_count);
|
||||
for (isize i = 0; i < index_count; i++) {
|
||||
indices[i] = 0;
|
||||
}
|
||||
|
||||
v = ssa_emit(proc, ssa_make_instr_shuffle_vector(proc, v, indices, index_count));
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
gb_printf_err("Not Identical %s != %s\n", type_to_string(src_type), type_to_string(t));
|
||||
gb_printf_err("Not Identical %s != %s\n", type_to_string(src), type_to_string(dst));
|
||||
@@ -1574,6 +1615,15 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
||||
ssaValue *i = ssa_make_value_constant(proc->module->allocator, t_int, make_exact_value_integer(index));
|
||||
result = ssa_emit(proc, ssa_make_instr_insert_element(proc, result, ev, i));
|
||||
}
|
||||
if (index == 1 && base_type->vector.count > 1) {
|
||||
isize index_count = base_type->vector.count;
|
||||
i32 *indices = gb_alloc_array(proc->module->allocator, i32, index_count);
|
||||
for (isize i = 0; i < index_count; i++) {
|
||||
indices[i] = 0;
|
||||
}
|
||||
return ssa_emit(proc, ssa_make_instr_shuffle_vector(proc, result, indices, index_count));
|
||||
}
|
||||
|
||||
return result;
|
||||
} break;
|
||||
|
||||
@@ -1750,6 +1800,27 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
||||
|
||||
return ssa_emit_conv(proc, cond, t_bool);
|
||||
} break;
|
||||
|
||||
case BuiltinProc_swizzle: {
|
||||
ssaValue *vector = ssa_build_expr(proc, ce->arg_list);
|
||||
isize index_count = ce->arg_list_count-1;
|
||||
if (index_count == 0) {
|
||||
return vector;
|
||||
}
|
||||
|
||||
i32 *indices = gb_alloc_array(proc->module->allocator, i32, index_count);
|
||||
isize index = 0;
|
||||
for (AstNode *arg = ce->arg_list->next; arg != NULL; arg = arg->next) {
|
||||
TypeAndValue *tv = type_and_value_of_expression(proc->module->info, arg);
|
||||
GB_ASSERT(is_type_integer(tv->type));
|
||||
GB_ASSERT(tv->value.kind == ExactValue_Integer);
|
||||
indices[index++] = cast(i32)tv->value.value_integer;
|
||||
}
|
||||
|
||||
return ssa_emit(proc, ssa_make_instr_shuffle_vector(proc, vector, indices, index_count));
|
||||
|
||||
} break;
|
||||
|
||||
case BuiltinProc_print: {
|
||||
// print :: proc(...)
|
||||
GB_PANIC("TODO(bill): BuiltinProc_print");
|
||||
|
||||
+2
-2
@@ -84,8 +84,8 @@ int main(int argc, char **argv) {
|
||||
if (exit_code == 0) {
|
||||
win32_exec_command_line_app(
|
||||
"clang -o %.*s.exe %.*s.bc -Wno-override-module "
|
||||
" ../c_libs/stb_image.c -DSTB_IMAGE_IMPLEMENTATION "
|
||||
"-lkernel32.lib -luser32.lib -lgdi32.lib -lopengl32.lib",
|
||||
"-lkernel32.lib -luser32.lib -lgdi32.lib -lopengl32.lib "
|
||||
"-l../c_libs/stb_image.lib",
|
||||
cast(int)base_name_len, output_name,
|
||||
cast(int)base_name_len, output_name);
|
||||
if (run_output) {
|
||||
|
||||
Reference in New Issue
Block a user