mirror of
https://github.com/odin-lang/Odin.git
synced 2026-04-18 12:30:28 +00:00
Update Tilde; Add min and max
This commit is contained in:
@@ -196,6 +196,8 @@ struct cgProcedure {
|
||||
Scope *curr_scope;
|
||||
i32 scope_index;
|
||||
bool in_multi_assignment;
|
||||
isize split_returns_index;
|
||||
bool return_by_ptr;
|
||||
|
||||
|
||||
PtrMap<Entity *, cgAddr> variable_map;
|
||||
|
||||
BIN
src/tilde/tb.lib
BIN
src/tilde/tb.lib
Binary file not shown.
@@ -91,6 +91,18 @@ gb_internal cgValue cg_builtin_raw_data(cgProcedure *p, cgValue const &value) {
|
||||
return res;
|
||||
}
|
||||
|
||||
gb_internal cgValue cg_builtin_min(cgProcedure *p, Type *t, cgValue x, cgValue y) {
|
||||
x = cg_emit_conv(p, x, t);
|
||||
y = cg_emit_conv(p, y, t);
|
||||
return cg_emit_select(p, cg_emit_comp(p, Token_Lt, x, y), x, y);
|
||||
}
|
||||
gb_internal cgValue cg_builtin_max(cgProcedure *p, Type *t, cgValue x, cgValue y) {
|
||||
x = cg_emit_conv(p, x, t);
|
||||
y = cg_emit_conv(p, y, t);
|
||||
return cg_emit_select(p, cg_emit_comp(p, Token_Gt, x, y), x, y);
|
||||
}
|
||||
|
||||
|
||||
gb_internal cgValue cg_build_builtin(cgProcedure *p, BuiltinProcId id, Ast *expr) {
|
||||
ast_node(ce, CallExpr, expr);
|
||||
|
||||
@@ -137,6 +149,32 @@ gb_internal cgValue cg_build_builtin(cgProcedure *p, BuiltinProcId id, Ast *expr
|
||||
return cg_builtin_len(p, v);
|
||||
}
|
||||
|
||||
case BuiltinProc_min:
|
||||
if (ce->args.count == 2) {
|
||||
Type *t = type_of_expr(expr);
|
||||
return cg_builtin_min(p, t, cg_build_expr(p, ce->args[0]), cg_build_expr(p, ce->args[1]));
|
||||
} else {
|
||||
Type *t = type_of_expr(expr);
|
||||
cgValue x = cg_build_expr(p, ce->args[0]);
|
||||
for (isize i = 1; i < ce->args.count; i++) {
|
||||
x = cg_builtin_min(p, t, x, cg_build_expr(p, ce->args[i]));
|
||||
}
|
||||
return x;
|
||||
}
|
||||
break;
|
||||
case BuiltinProc_max:
|
||||
if (ce->args.count == 2) {
|
||||
Type *t = type_of_expr(expr);
|
||||
return cg_builtin_max(p, t, cg_build_expr(p, ce->args[0]), cg_build_expr(p, ce->args[1]));
|
||||
} else {
|
||||
Type *t = type_of_expr(expr);
|
||||
cgValue x = cg_build_expr(p, ce->args[0]);
|
||||
for (isize i = 1; i < ce->args.count; i++) {
|
||||
x = cg_builtin_max(p, t, x, cg_build_expr(p, ce->args[i]));
|
||||
}
|
||||
return x;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
gb_internal TB_DebugType *cg_debug_type_internal(cgModule *m, Type *type);
|
||||
gb_internal TB_DebugType *cg_debug_type(cgModule *m, Type *type) {
|
||||
type = reduce_tuple_to_single_type(type);
|
||||
|
||||
mutex_lock(&m->debug_type_mutex);
|
||||
defer (mutex_unlock(&m->debug_type_mutex));
|
||||
TB_DebugType **found = map_get(&m->debug_type_map, type);
|
||||
@@ -235,7 +237,8 @@ gb_internal TB_DebugType *cg_debug_type_internal(cgModule *m, Type *type) {
|
||||
case Basic_uint: return tb_debug_get_integer(m->mod, is_signed, bits);
|
||||
case Basic_uintptr: return tb_debug_get_integer(m->mod, is_signed, bits);
|
||||
|
||||
case Basic_rawptr: return tb_debug_create_ptr(m->mod, tb_debug_get_void(m->mod));
|
||||
case Basic_rawptr:
|
||||
return tb_debug_create_ptr(m->mod, tb_debug_get_void(m->mod));
|
||||
case Basic_string:
|
||||
{
|
||||
String name = basic_types[type->Basic.kind].Basic.name;
|
||||
|
||||
@@ -15,6 +15,15 @@ gb_internal cgValue cg_flatten_value(cgProcedure *p, cgValue value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
gb_internal cgValue cg_emit_select(cgProcedure *p, cgValue const &cond, cgValue const &x, cgValue const &y) {
|
||||
GB_ASSERT(x.kind == y.kind);
|
||||
GB_ASSERT(cond.kind == cgValue_Value);
|
||||
cgValue res = x;
|
||||
res.node = tb_inst_select(p->func, cond.node, x.node, y.node);
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
gb_internal bool cg_is_expr_untyped_const(Ast *expr) {
|
||||
auto const &tv = type_and_value_of_expr(expr);
|
||||
if (is_type_untyped(tv.type)) {
|
||||
@@ -1724,36 +1733,35 @@ gb_internal cgValue cg_build_binary_expr(cgProcedure *p, Ast *expr) {
|
||||
|
||||
case Token_CmpEq:
|
||||
case Token_NotEq:
|
||||
GB_PANIC("TODO(bill): comparisons");
|
||||
// if (is_type_untyped_nil(be->right->tav.type)) {
|
||||
// // `x == nil` or `x != nil`
|
||||
// cgValue left = cg_build_expr(p, be->left);
|
||||
// cgValue cmp = cg_emit_comp_against_nil(p, be->op.kind, left);
|
||||
// Type *type = default_type(tv.type);
|
||||
// return cg_emit_conv(p, cmp, type);
|
||||
// } else if (is_type_untyped_nil(be->left->tav.type)) {
|
||||
// // `nil == x` or `nil != x`
|
||||
// cgValue right = cg_build_expr(p, be->right);
|
||||
// cgValue cmp = cg_emit_comp_against_nil(p, be->op.kind, right);
|
||||
// Type *type = default_type(tv.type);
|
||||
// return cg_emit_conv(p, cmp, type);
|
||||
// } else if (cg_is_empty_string_constant(be->right)) {
|
||||
// // `x == ""` or `x != ""`
|
||||
// cgValue s = cg_build_expr(p, be->left);
|
||||
// s = cg_emit_conv(p, s, t_string);
|
||||
// cgValue len = cg_string_len(p, s);
|
||||
// cgValue cmp = cg_emit_comp(p, be->op.kind, len, cg_const_int(p->module, t_int, 0));
|
||||
// Type *type = default_type(tv.type);
|
||||
// return cg_emit_conv(p, cmp, type);
|
||||
// } else if (cg_is_empty_string_constant(be->left)) {
|
||||
// // `"" == x` or `"" != x`
|
||||
// cgValue s = cg_build_expr(p, be->right);
|
||||
// s = cg_emit_conv(p, s, t_string);
|
||||
// cgValue len = cg_string_len(p, s);
|
||||
// cgValue cmp = cg_emit_comp(p, be->op.kind, len, cg_const_int(p->module, t_int, 0));
|
||||
// Type *type = default_type(tv.type);
|
||||
// return cg_emit_conv(p, cmp, type);
|
||||
// }
|
||||
if (is_type_untyped_nil(be->right->tav.type)) {
|
||||
// `x == nil` or `x != nil`
|
||||
cgValue left = cg_build_expr(p, be->left);
|
||||
cgValue cmp = cg_emit_comp_against_nil(p, be->op.kind, left);
|
||||
Type *type = default_type(tv.type);
|
||||
return cg_emit_conv(p, cmp, type);
|
||||
} else if (is_type_untyped_nil(be->left->tav.type)) {
|
||||
// `nil == x` or `nil != x`
|
||||
cgValue right = cg_build_expr(p, be->right);
|
||||
cgValue cmp = cg_emit_comp_against_nil(p, be->op.kind, right);
|
||||
Type *type = default_type(tv.type);
|
||||
return cg_emit_conv(p, cmp, type);
|
||||
}/* else if (cg_is_empty_string_constant(be->right)) {
|
||||
// `x == ""` or `x != ""`
|
||||
cgValue s = cg_build_expr(p, be->left);
|
||||
s = cg_emit_conv(p, s, t_string);
|
||||
cgValue len = cg_string_len(p, s);
|
||||
cgValue cmp = cg_emit_comp(p, be->op.kind, len, cg_const_int(p->module, t_int, 0));
|
||||
Type *type = default_type(tv.type);
|
||||
return cg_emit_conv(p, cmp, type);
|
||||
} else if (cg_is_empty_string_constant(be->left)) {
|
||||
// `"" == x` or `"" != x`
|
||||
cgValue s = cg_build_expr(p, be->right);
|
||||
s = cg_emit_conv(p, s, t_string);
|
||||
cgValue len = cg_string_len(p, s);
|
||||
cgValue cmp = cg_emit_comp(p, be->op.kind, len, cg_const_int(p->module, t_int, 0));
|
||||
Type *type = default_type(tv.type);
|
||||
return cg_emit_conv(p, cmp, type);
|
||||
}*/
|
||||
/*fallthrough*/
|
||||
case Token_Lt:
|
||||
case Token_LtEq:
|
||||
@@ -2255,7 +2263,6 @@ gb_internal cgValue cg_build_expr_internal(cgProcedure *p, Ast *expr) {
|
||||
token_pos_to_string(token.pos));
|
||||
return {};
|
||||
} else if (e->kind == Entity_Nil) {
|
||||
GB_PANIC("TODO: cg_find_ident nil");
|
||||
// TODO(bill): is this correct?
|
||||
return cg_value(cast(TB_Node *)nullptr, e->type);
|
||||
}
|
||||
|
||||
@@ -63,6 +63,7 @@ gb_internal cgProcedure *cg_procedure_create(cgModule *m, Entity *entity, bool i
|
||||
p->is_foreign = entity->Procedure.is_foreign;
|
||||
p->is_export = entity->Procedure.is_export;
|
||||
p->is_entry_point = false;
|
||||
p->split_returns_index = -1;
|
||||
|
||||
gbAllocator a = heap_allocator();
|
||||
p->children.allocator = a;
|
||||
@@ -122,6 +123,7 @@ gb_internal cgProcedure *cg_procedure_create_dummy(cgModule *m, String const &li
|
||||
p->is_foreign = false;
|
||||
p->is_export = false;
|
||||
p->is_entry_point = false;
|
||||
p->split_returns_index = -1;
|
||||
|
||||
gbAllocator a = heap_allocator();
|
||||
p->children.allocator = a;
|
||||
@@ -188,6 +190,7 @@ gb_internal void cg_procedure_begin(cgProcedure *p) {
|
||||
TB_DebugType *debug_type = cg_debug_type(p->module, result_type);
|
||||
TB_PassingRule rule = tb_get_passing_rule_from_dbg(p->module->mod, debug_type, true);
|
||||
if (rule == TB_PASSING_INDIRECT) {
|
||||
p->return_by_ptr = true;
|
||||
param_index++;
|
||||
}
|
||||
}
|
||||
@@ -272,7 +275,7 @@ gb_internal void cg_procedure_begin(cgProcedure *p) {
|
||||
// }
|
||||
}
|
||||
|
||||
// isize split_offset = param_index;
|
||||
p->split_returns_index = param_index;
|
||||
|
||||
if (pt->calling_convention == ProcCC_Odin) {
|
||||
// NOTE(bill): Push context on to stack from implicit parameter
|
||||
@@ -323,24 +326,6 @@ gb_internal void cg_procedure_end(cgProcedure *p) {
|
||||
tb_inst_ret(p->func, 0, nullptr);
|
||||
}
|
||||
bool emit_asm = false;
|
||||
// if (p->name == "main") {
|
||||
if (
|
||||
p->name == "runtime" ABI_PKG_NAME_SEPARATOR "print_string" ||
|
||||
// p->name == "bug" ABI_PKG_NAME_SEPARATOR "main" ||
|
||||
// p->name == "main" ||
|
||||
false
|
||||
) {
|
||||
TB_Arena *arena = tb_default_arena();
|
||||
defer (arena->free(arena));
|
||||
TB_FuncOpt *opt = tb_funcopt_enter(p->func, arena);
|
||||
defer (tb_funcopt_exit(opt));
|
||||
tb_funcopt_print(opt);
|
||||
|
||||
// emit_asm = true;
|
||||
|
||||
// GraphViz printing
|
||||
// tb_function_print(p->func, tb_default_print_callback, stdout);
|
||||
}
|
||||
TB_FunctionOutput *output = tb_module_compile_function(p->module->mod, p->func, TB_ISEL_FAST, emit_asm);
|
||||
if (emit_asm) {
|
||||
TB_Assembly *assembly = tb_output_get_asm(output);
|
||||
@@ -361,17 +346,33 @@ gb_internal void cg_procedure_generate(cgProcedure *p) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool build_body = false;
|
||||
|
||||
if (
|
||||
p->name == "runtime" ABI_PKG_NAME_SEPARATOR "print_string" ||
|
||||
string_starts_with(p->name, str_lit("runtime" ABI_PKG_NAME_SEPARATOR "_os_write")) ||
|
||||
// p->name == "bug" ABI_PKG_NAME_SEPARATOR "main" ||
|
||||
// p->name == "main" ||
|
||||
false
|
||||
) {
|
||||
build_body = true;
|
||||
}
|
||||
|
||||
if (build_body) {
|
||||
cg_procedure_begin(p);
|
||||
cg_build_stmt(p, p->body);
|
||||
}
|
||||
|
||||
cg_procedure_end(p);
|
||||
|
||||
if (build_body) {
|
||||
TB_Arena *arena = tb_default_arena();
|
||||
defer (arena->free(arena));
|
||||
TB_FuncOpt *opt = tb_funcopt_enter(p->func, arena);
|
||||
defer (tb_funcopt_exit(opt));
|
||||
tb_funcopt_print(opt);
|
||||
|
||||
// GraphViz printing
|
||||
// tb_function_print(p->func, tb_default_print_callback, stdout);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -543,9 +544,11 @@ gb_internal cgValue cg_emit_call(cgProcedure * p, cgValue value, Slice<cgValue>
|
||||
case 1:
|
||||
if (return_is_indirect) {
|
||||
return cg_lvalue_addr(params[0], pt->results->Tuple.variables[0]->type);
|
||||
} else {
|
||||
GB_ASSERT(multi_output.count == 1);
|
||||
TB_Node *node = multi_output.single;
|
||||
return cg_value(node, pt->results->Tuple.variables[0]->type);
|
||||
}
|
||||
GB_ASSERT(multi_output.count == 1);
|
||||
return cg_value(multi_output.single, pt->results->Tuple.variables[0]->type);
|
||||
}
|
||||
|
||||
cgValueMulti *multi = gb_alloc_item(permanent_allocator(), cgValueMulti);
|
||||
|
||||
@@ -1011,31 +1011,91 @@ gb_internal void cg_build_assign_stmt(cgProcedure *p, AstAssignStmt *as) {
|
||||
gb_internal void cg_build_return_stmt(cgProcedure *p, Slice<Ast *> const &return_results) {
|
||||
TypeTuple *tuple = &p->type->Proc.results->Tuple;
|
||||
isize return_count = p->type->Proc.result_count;
|
||||
gb_unused(tuple);
|
||||
isize res_count = return_results.count;
|
||||
gb_unused(res_count);
|
||||
|
||||
if (return_count == 0) {
|
||||
tb_inst_ret(p->func, 0, nullptr);
|
||||
return;
|
||||
} else if (return_count == 1) {
|
||||
Entity *e = tuple->variables[0];
|
||||
if (res_count == 0) {
|
||||
cgValue zero = cg_const_nil(p, tuple->variables[0]->type);
|
||||
if (zero.kind == cgValue_Value) {
|
||||
tb_inst_ret(p->func, 1, &zero.node);
|
||||
}
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
|
||||
auto results = array_make<cgValue>(temporary_allocator(), 0, return_count);
|
||||
|
||||
if (return_results.count != 0) {
|
||||
for (isize i = 0; i < return_results.count; i++) {
|
||||
cgValue res = cg_build_expr(p, return_results[i]);
|
||||
cg_append_tuple_values(p, &results, res);
|
||||
}
|
||||
} else {
|
||||
for_array(i, tuple->variables) {
|
||||
Entity *e = tuple->variables[i];
|
||||
cgAddr addr = map_must_get(&p->variable_map, e);
|
||||
cgValue res = cg_addr_load(p, addr);
|
||||
array_add(&results, res);
|
||||
}
|
||||
}
|
||||
GB_ASSERT(results.count == return_count);
|
||||
|
||||
if (return_results.count != 0 && p->type->Proc.has_named_results) {
|
||||
// NOTE(bill): store the named values before returning
|
||||
for_array(i, tuple->variables) {
|
||||
Entity *e = tuple->variables[i];
|
||||
cgAddr addr = map_must_get(&p->variable_map, e);
|
||||
cg_addr_store(p, addr, results[i]);
|
||||
}
|
||||
}
|
||||
for_array(i, tuple->variables) {
|
||||
Entity *e = tuple->variables[i];
|
||||
results[i] = cg_emit_conv(p, results[i], e->type);
|
||||
}
|
||||
|
||||
|
||||
if (p->split_returns_index >= 0) {
|
||||
GB_ASSERT(is_calling_convention_odin(p->type->Proc.calling_convention));
|
||||
|
||||
for (isize i = 0; i < return_count-1; i++) {
|
||||
Entity *e = tuple->variables[i];
|
||||
TB_Node *ret_ptr = tb_inst_param(p->func, cast(int)(p->split_returns_index+i));
|
||||
cgValue ptr = cg_value(ret_ptr, alloc_type_pointer(e->type));
|
||||
cg_emit_store(p, ptr, results[i]);
|
||||
}
|
||||
|
||||
if (p->return_by_ptr) {
|
||||
Entity *e = tuple->variables[return_count-1];
|
||||
TB_Node *ret_ptr = tb_inst_param(p->func, 0);
|
||||
cgValue ptr = cg_value(ret_ptr, alloc_type_pointer(e->type));
|
||||
cg_emit_store(p, ptr, results[return_count-1]);
|
||||
|
||||
tb_inst_ret(p->func, 0, nullptr);
|
||||
return;
|
||||
} else {
|
||||
GB_ASSERT(p->proto->return_count == 1);
|
||||
TB_DataType dt = TB_PROTOTYPE_RETURNS(p->proto)->dt;
|
||||
|
||||
cgValue result = cg_flatten_value(p, results[0]);
|
||||
TB_Node *final_res = nullptr;
|
||||
if (result.kind == cgValue_Addr) {
|
||||
TB_CharUnits align = cast(TB_CharUnits)type_align_of(result.type);
|
||||
final_res = tb_inst_load(p->func, dt, result.node, align, false);
|
||||
} else {
|
||||
GB_ASSERT(result.kind == cgValue_Value);
|
||||
if (result.node->dt.raw == dt.raw) {
|
||||
final_res = result.node;
|
||||
} else {
|
||||
final_res = tb_inst_bitcast(p->func, result.node, dt);
|
||||
}
|
||||
}
|
||||
GB_ASSERT(final_res != nullptr);
|
||||
|
||||
tb_inst_ret(p->func, 1, &final_res);
|
||||
return;
|
||||
}
|
||||
cgValue res = cg_build_expr(p, return_results[0]);
|
||||
res = cg_emit_conv(p, res, e->type);
|
||||
if (res.kind == cgValue_Value) {
|
||||
tb_inst_ret(p->func, 1, &res.node);
|
||||
}
|
||||
return;
|
||||
|
||||
} else {
|
||||
GB_PANIC("TODO(bill): MUTLIPLE RETURN VALUES");
|
||||
GB_ASSERT(!is_calling_convention_odin(p->type->Proc.calling_convention));
|
||||
}
|
||||
|
||||
|
||||
GB_PANIC("TODO(bill): %.*s MUTLIPLE RETURN VALUES %td %td", LIT(p->name), results.count, return_results.count);
|
||||
}
|
||||
|
||||
gb_internal void cg_build_if_stmt(cgProcedure *p, Ast *node) {
|
||||
|
||||
Reference in New Issue
Block a user