Port code for lb_build_call_expr

This commit is contained in:
gingerBill
2020-02-02 23:36:15 +00:00
parent d56807095a
commit 0103cedad7
2 changed files with 435 additions and 50 deletions

View File

@@ -1,45 +1,39 @@
package demo
import "core:os"
// Foo :: struct {
// x, y: int,
// };
// foo :: proc(x: int) -> (f: Foo) {
// return;
// }
BarBar :: struct {
x, y: int,
};
foo :: proc(x: int) -> (b: BarBar) {
return;
}
main :: proc() {
Foo :: enum {A=1, B, C, D};
Foo_Set :: bit_set[Foo];
x := Foo_Set{.A, .C};
foo_set := Foo_Set{.A, .C};
y := [4]int{3 = 1, 0 .. 1 = 3, 2 = 9};
z := []int{1, 2, 3, 4};
array := [4]int{3 = 1, 0 .. 1 = 3, 2 = 9};
slice := []int{1, 2, 3, 4};
// @thread_local a: int;
@thread_local a: int;
// x := i32(1);
// y := i32(2);
// z := x + y;
// w := z - 2;
x := i32(1);
y := i32(2);
z := x + y;
w := z - 2;
// foo(123);
f := foo;
c := 1 + 2i;
q := 1 + 2i + 3j + 4k;
// c := 1 + 2i;
// q := 1 + 2i + 3j + 4k;
s := "Hellope";
// s := "Hellope";
// f := Foo{1, 2};
// pc: proc "contextless" (x: i32) -> Foo;
// po: proc "odin" (x: i32) -> Foo;
// e: enum{A, B, C};
// u: union{i32, bool};
// u1: union{i32};
// um: union #maybe {^int};
// os.write_string(os.stdout, "Hellope\n");
return;
bb := BarBar{1, 2};
pc: proc "contextless" (x: i32) -> BarBar;
po: proc "odin" (x: i32) -> BarBar;
e: enum{A, B, C};
u: union{i32, bool};
u1: union{i32};
um: union #maybe {^int};
}

View File

@@ -27,6 +27,11 @@ void lb_addr_store(lbProcedure *p, lbAddr const &addr, lbValue const &value) {
}
void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) {
GB_ASSERT(value.value != nullptr);
LLVMValueRef v = LLVMBuildStore(p->builder, value.value, ptr.value);
}
lbValue lb_emit_load(lbProcedure *p, lbValue value) {
GB_ASSERT(value.value != nullptr);
Type *t = type_deref(value.type);
@@ -99,14 +104,25 @@ String lb_mangle_name(lbModule *m, Entity *e) {
return make_string(new_name, new_name_len-1);
}
String lb_get_entity_name(lbModule *m, Entity *e, String name) {
String lb_get_entity_name(lbModule *m, Entity *e, String default_name) {
if (e != nullptr && e->kind == Entity_TypeName && e->TypeName.ir_mangled_name.len != 0) {
return e->TypeName.ir_mangled_name;
}
String name = {};
bool no_name_mangle = false;
if (e->kind == Entity_Variable) {
bool is_foreign = e->Variable.is_foreign;
bool is_export = e->Variable.is_export;
no_name_mangle = e->Variable.link_name.len > 0 || is_foreign || is_export;
} else if (e->kind == Entity_Procedure && e->Procedure.is_export) {
no_name_mangle = true;
} else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) {
no_name_mangle = true;
}
if (!no_name_mangle) {
name = lb_mangle_name(m, e);
}
@@ -116,8 +132,10 @@ String lb_get_entity_name(lbModule *m, Entity *e, String name) {
if (e != nullptr && e->kind == Entity_TypeName) {
e->TypeName.ir_mangled_name = name;
} else if (e != nullptr && e->kind == Entity_Procedure) {
e->Procedure.link_name = name;
}
return name;
}
@@ -519,6 +537,8 @@ LLVMTypeRef lb_type_internal(Type *type) {
}
LLVMTypeRef lb_type(Type *type) {
type = default_type(type);
if (type->llvm_type) {
return type->llvm_type;
}
@@ -726,11 +746,20 @@ lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e=nullptr) {
val.value = ptr;
val.type = alloc_type_pointer(type);
lb_add_entity(p->module, e, val);
if (e != nullptr) {
lb_add_entity(p->module, e, val);
}
return lb_addr(val);
}
lbAddr lb_add_local_generated(lbProcedure *p, Type *type, bool zero_init) {
lbAddr addr = lb_add_local(p, type, nullptr);
lb_addr_store(p, addr, lb_const_nil(type));
return addr;
}
bool lb_init_generator(lbGenerator *gen, Checker *c) {
if (global_error_collector.count != 0) {
@@ -994,7 +1023,7 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
// res = lb_emit_load(p, *found);
} else {
res = lb_build_expr(p, rs->results[0]);
// res = ir_emit_conv(p, v, e->type);
res = lb_emit_conv(p, res, e->type);
}
} else {
@@ -1041,6 +1070,13 @@ lbValue lb_const_nil(Type *type) {
return lbValue{v, type};
}
lbValue lb_const_int(Type *type, u64 value) {
lbValue res = {};
res.value = LLVMConstInt(lb_type(type), value, !is_type_unsigned(type));
res.type = type;
return res;
}
LLVMValueRef llvm_const_f32(f32 f, Type *type=t_f32) {
u32 u = bit_cast<u32>(f);
LLVMValueRef i = LLVMConstInt(LLVMInt32Type(), u, false);
@@ -1048,6 +1084,8 @@ LLVMValueRef llvm_const_f32(f32 f, Type *type=t_f32) {
}
lbValue lb_find_or_add_entity_string(lbModule *m, String const &str) {
HashKey key = hash_string(str);
lbValue *found = map_get(&m->const_strings, key);
@@ -1662,6 +1700,31 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value) {
return lb_const_nil(original_type);
}
u64 lb_generate_source_code_location_hash(TokenPos const &pos) {
u64 h = 0xcbf29ce484222325;
for (isize i = 0; i < pos.file.len; i++) {
h = (h ^ u64(pos.file[i])) * 0x100000001b3;
}
h = h ^ (u64(pos.line) * 0x100000001b3);
h = h ^ (u64(pos.column) * 0x100000001b3);
return h;
}
lbValue lb_emit_source_code_location(lbProcedure *p, String const &procedure, TokenPos const &pos) {
LLVMValueRef fields[5] = {};
fields[0]/*file*/ = lb_find_or_add_entity_string(p->module, pos.file).value;
fields[1]/*line*/ = lb_const_int(t_int, pos.line).value;
fields[2]/*column*/ = lb_const_int(t_int, pos.column).value;
fields[3]/*procedure*/ = lb_find_or_add_entity_string(p->module, procedure).value;
fields[4]/*hash*/ = lb_const_int(t_u64, lb_generate_source_code_location_hash(pos)).value;
lbValue res = {};
res.value = LLVMConstNamedStruct(lb_type(t_source_code_location), fields, 5);
res.type = t_source_code_location;
return res;
}
lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type) {
lbValue res = {};
res.type = type;
@@ -1784,6 +1847,339 @@ lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) {
return {};
}
lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
// TODO(bill): lb_emit_conv
return value;
}
lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue > const &args, ProcInlining inlining = ProcInlining_none, bool use_return_ptr_hint = false) {
return {};
}
lbValue lb_emit_ev(lbProcedure *p, lbValue value, i32 index) {
return {};
}
lbValue lb_emit_array_epi(lbProcedure *p, lbValue value, i32 index){
return {};
}
void lb_fill_slice(lbProcedure *p, lbAddr slice, lbValue base_elem, lbValue len) {
}
lbValue lb_build_call_expr(lbProcedure *p, Ast *expr) {
TypeAndValue tv = type_and_value_of_expr(expr);
ast_node(ce, CallExpr, expr);
TypeAndValue proc_tv = type_and_value_of_expr(ce->proc);
AddressingMode proc_mode = proc_tv.mode;
if (proc_mode == Addressing_Type) {
GB_ASSERT(ce->args.count == 1);
lbValue x = lb_build_expr(p, ce->args[0]);
lbValue y = lb_emit_conv(p, x, tv.type);
return y;
}
Ast *pexpr = unparen_expr(ce->proc);
if (proc_mode == Addressing_Builtin) {
Entity *e = entity_of_node(pexpr);
BuiltinProcId id = BuiltinProc_Invalid;
if (e != nullptr) {
id = cast(BuiltinProcId)e->Builtin.id;
} else {
id = BuiltinProc_DIRECTIVE;
}
GB_PANIC("lb_build_builtin_proc");
// return lb_build_builtin_proc(p, expr, tv, id);
}
// NOTE(bill): Regular call
lbValue value = {};
Ast *proc_expr = unparen_expr(ce->proc);
if (proc_expr->tav.mode == Addressing_Constant) {
ExactValue v = proc_expr->tav.value;
switch (v.kind) {
case ExactValue_Integer:
{
u64 u = big_int_to_u64(&v.value_integer);
lbValue x = {};
x.value = LLVMConstInt(lb_type(t_uintptr), u, false);
x.type = t_uintptr;
x = lb_emit_conv(p, x, t_rawptr);
value = lb_emit_conv(p, x, proc_expr->tav.type);
break;
}
case ExactValue_Pointer:
{
u64 u = cast(u64)v.value_pointer;
lbValue x = {};
x.value = LLVMConstInt(lb_type(t_uintptr), u, false);
x.type = t_uintptr;
x = lb_emit_conv(p, x, t_rawptr);
value = lb_emit_conv(p, x, proc_expr->tav.type);
break;
}
}
}
if (value.value == nullptr) {
value = lb_build_expr(p, proc_expr);
}
GB_ASSERT(value.value != nullptr);
Type *proc_type_ = base_type(value.type);
GB_ASSERT(proc_type_->kind == Type_Proc);
TypeProc *pt = &proc_type_->Proc;
set_procedure_abi_types(heap_allocator(), proc_type_);
if (is_call_expr_field_value(ce)) {
auto args = array_make<lbValue >(heap_allocator(), pt->param_count);
for_array(arg_index, ce->args) {
Ast *arg = ce->args[arg_index];
ast_node(fv, FieldValue, arg);
GB_ASSERT(fv->field->kind == Ast_Ident);
String name = fv->field->Ident.token.string;
isize index = lookup_procedure_parameter(pt, name);
GB_ASSERT(index >= 0);
TypeAndValue tav = type_and_value_of_expr(fv->value);
if (tav.mode == Addressing_Type) {
args[index] = lb_const_nil(tav.type);
} else {
args[index] = lb_build_expr(p, fv->value);
}
}
TypeTuple *params = &pt->params->Tuple;
for (isize i = 0; i < args.count; i++) {
Entity *e = params->variables[i];
if (e->kind == Entity_TypeName) {
args[i] = lb_const_nil(e->type);
} else if (e->kind == Entity_Constant) {
continue;
} else {
GB_ASSERT(e->kind == Entity_Variable);
if (args[i].value == nullptr) {
switch (e->Variable.param_value.kind) {
case ParameterValue_Constant:
args[i] = lb_const_value(p->module, e->type, e->Variable.param_value.value);
break;
case ParameterValue_Nil:
args[i] = lb_const_nil(e->type);
break;
case ParameterValue_Location:
args[i] = lb_emit_source_code_location(p, p->entity->token.string, ast_token(expr).pos);
break;
case ParameterValue_Value:
args[i] = lb_build_expr(p, e->Variable.param_value.ast_value);
break;
}
} else {
args[i] = lb_emit_conv(p, args[i], e->type);
}
}
}
return lb_emit_call(p, value, args, ce->inlining, p->return_ptr_hint_ast == expr);
}
isize arg_index = 0;
isize arg_count = 0;
for_array(i, ce->args) {
Ast *arg = ce->args[i];
TypeAndValue tav = type_and_value_of_expr(arg);
GB_ASSERT_MSG(tav.mode != Addressing_Invalid, "%s %s", expr_to_string(arg), expr_to_string(expr));
GB_ASSERT_MSG(tav.mode != Addressing_ProcGroup, "%s", expr_to_string(arg));
Type *at = tav.type;
if (at->kind == Type_Tuple) {
arg_count += at->Tuple.variables.count;
} else {
arg_count++;
}
}
isize param_count = 0;
if (pt->params) {
GB_ASSERT(pt->params->kind == Type_Tuple);
param_count = pt->params->Tuple.variables.count;
}
auto args = array_make<lbValue >(heap_allocator(), cast(isize)gb_max(param_count, arg_count));
isize variadic_index = pt->variadic_index;
bool variadic = pt->variadic && variadic_index >= 0;
bool vari_expand = ce->ellipsis.pos.line != 0;
bool is_c_vararg = pt->c_vararg;
String proc_name = {};
if (p->entity != nullptr) {
proc_name = p->entity->token.string;
}
TokenPos pos = ast_token(ce->proc).pos;
TypeTuple *param_tuple = nullptr;
if (pt->params) {
GB_ASSERT(pt->params->kind == Type_Tuple);
param_tuple = &pt->params->Tuple;
}
for_array(i, ce->args) {
Ast *arg = ce->args[i];
TypeAndValue arg_tv = type_and_value_of_expr(arg);
if (arg_tv.mode == Addressing_Type) {
args[arg_index++] = lb_const_nil(arg_tv.type);
} else {
lbValue a = lb_build_expr(p, arg);
Type *at = a.type;
if (at->kind == Type_Tuple) {
for_array(i, at->Tuple.variables) {
Entity *e = at->Tuple.variables[i];
lbValue v = lb_emit_ev(p, a, cast(i32)i);
args[arg_index++] = v;
}
} else {
args[arg_index++] = a;
}
}
}
if (param_count > 0) {
GB_ASSERT_MSG(pt->params != nullptr, "%s %td", expr_to_string(expr), pt->param_count);
GB_ASSERT(param_count < 1000000);
if (arg_count < param_count) {
isize end = cast(isize)param_count;
if (variadic) {
end = variadic_index;
}
while (arg_index < end) {
Entity *e = param_tuple->variables[arg_index];
GB_ASSERT(e->kind == Entity_Variable);
switch (e->Variable.param_value.kind) {
case ParameterValue_Constant:
args[arg_index++] = lb_const_value(p->module, e->type, e->Variable.param_value.value);
break;
case ParameterValue_Nil:
args[arg_index++] = lb_const_nil(e->type);
break;
case ParameterValue_Location:
args[arg_index++] = lb_emit_source_code_location(p, proc_name, pos);
break;
case ParameterValue_Value:
args[arg_index++] = lb_build_expr(p, e->Variable.param_value.ast_value);
break;
}
}
}
if (is_c_vararg) {
GB_ASSERT(variadic);
GB_ASSERT(!vari_expand);
isize i = 0;
for (; i < variadic_index; i++) {
Entity *e = param_tuple->variables[i];
if (e->kind == Entity_Variable) {
args[i] = lb_emit_conv(p, args[i], e->type);
}
}
Type *variadic_type = param_tuple->variables[i]->type;
GB_ASSERT(is_type_slice(variadic_type));
variadic_type = base_type(variadic_type)->Slice.elem;
if (!is_type_any(variadic_type)) {
for (; i < arg_count; i++) {
args[i] = lb_emit_conv(p, args[i], variadic_type);
}
} else {
for (; i < arg_count; i++) {
args[i] = lb_emit_conv(p, args[i], default_type(args[i].type));
}
}
} else if (variadic) {
isize i = 0;
for (; i < variadic_index; i++) {
Entity *e = param_tuple->variables[i];
if (e->kind == Entity_Variable) {
args[i] = lb_emit_conv(p, args[i], e->type);
}
}
if (!vari_expand) {
Type *variadic_type = param_tuple->variables[i]->type;
GB_ASSERT(is_type_slice(variadic_type));
variadic_type = base_type(variadic_type)->Slice.elem;
for (; i < arg_count; i++) {
args[i] = lb_emit_conv(p, args[i], variadic_type);
}
}
} else {
for (isize i = 0; i < param_count; i++) {
Entity *e = param_tuple->variables[i];
if (e->kind == Entity_Variable) {
GB_ASSERT(args[i].value != nullptr);
args[i] = lb_emit_conv(p, args[i], e->type);
}
}
}
if (variadic && !vari_expand && !is_c_vararg) {
// variadic call argument generation
gbAllocator allocator = heap_allocator();
Type *slice_type = param_tuple->variables[variadic_index]->type;
Type *elem_type = base_type(slice_type)->Slice.elem;
lbAddr slice = lb_add_local_generated(p, slice_type, true);
isize slice_len = arg_count+1 - (variadic_index+1);
if (slice_len > 0) {
lbAddr base_array = lb_add_local_generated(p, alloc_type_array(elem_type, slice_len), true);
for (isize i = variadic_index, j = 0; i < arg_count; i++, j++) {
lbValue addr = lb_emit_array_epi(p, base_array.addr, cast(i32)j);
lb_emit_store(p, addr, args[i]);
}
lbValue base_elem = lb_emit_array_epi(p, base_array.addr, 0);
lbValue len = lb_const_int(t_int, slice_len);
lb_fill_slice(p, slice, base_elem, len);
}
arg_count = param_count;
args[variadic_index] = lb_addr_load(p, slice);
}
}
if (variadic && variadic_index+1 < param_count) {
for (isize i = variadic_index+1; i < param_count; i++) {
Entity *e = param_tuple->variables[i];
switch (e->Variable.param_value.kind) {
case ParameterValue_Constant:
args[i] = lb_const_value(p->module, e->type, e->Variable.param_value.value);
break;
case ParameterValue_Nil:
args[i] = lb_const_nil(e->type);
break;
case ParameterValue_Location:
args[i] = lb_emit_source_code_location(p, proc_name, pos);
break;
case ParameterValue_Value:
args[i] = lb_build_expr(p, e->Variable.param_value.ast_value);
break;
}
}
}
isize final_count = param_count;
if (is_c_vararg) {
final_count = arg_count;
}
auto call_args = array_slice(args, 0, final_count);
return lb_emit_call(p, value, call_args, ce->inlining, p->return_ptr_hint_ast == expr);
}
lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
expr = unparen_expr(expr);
@@ -1809,7 +2205,7 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
case_end;
case_ast_node(i, Implicit, expr);
// return ir_addr_load(proc, ir_build_addr(proc, expr));
// return ir_addr_load(p, ir_build_addr(p, expr));
GB_PANIC("TODO(bill): Implicit");
case_end;
@@ -1822,7 +2218,7 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
GB_ASSERT_MSG(e != nullptr, "%s", expr_to_string(expr));
if (e->kind == Entity_Builtin) {
Token token = ast_token(expr);
GB_PANIC("TODO(bill): ir_build_expr Entity_Builtin '%.*s'\n"
GB_PANIC("TODO(bill): lb_build_expr Entity_Builtin '%.*s'\n"
"\t at %.*s(%td:%td)", LIT(builtin_procs[e->Builtin.id].name),
LIT(token.pos.file), token.pos.line, token.pos.column);
return {};
@@ -1833,13 +2229,13 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
auto *found = map_get(&p->module->values, hash_entity(e));
if (found) {
auto v = *found;
LLVMTypeKind kind = LLVMGetTypeKind(LLVMTypeOf(v.value));
if (kind == LLVMFunctionTypeKind) {
// NOTE(bill): This is because pointers are already pointers in LLVM
if (is_type_proc(v.type)) {
return v;
}
return lb_emit_load(p, v);
// } else if (e != nullptr && e->kind == Entity_Variable) {
// return ir_addr_load(proc, ir_build_addr(proc, expr));
// return ir_addr_load(p, ir_build_addr(p, expr));
}
GB_PANIC("nullptr value for expression from identifier: %.*s : %s @ %p", LIT(i->token.string), type_to_string(e->type), expr);
return {};
@@ -1848,6 +2244,11 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
case_ast_node(be, BinaryExpr, expr);
return lb_build_binary_expr(p, expr);
case_end;
case_ast_node(ce, CallExpr, expr);
return lb_build_call_expr(p, expr);
case_end;
}
return {};
@@ -1941,17 +2342,7 @@ void lb_generate_module(lbGenerator *gen) {
defer (LLVMDisposeMessage(llvm_error));
// LLVMPassManagerRef pass_manager = LLVMCreatePassManager();
// defer (LLVMDisposePassManager(pass_manager));
// LLVMAddAggressiveInstCombinerPass(pass_manager);
// LLVMAddConstantMergePass(pass_manager);
// LLVMAddDeadArgEliminationPass(pass_manager);
// LLVMRunPassManager(pass_manager, mod);
LLVMVerifyModule(mod, LLVMAbortProcessAction, &llvm_error);
llvm_error = nullptr;
LLVMDumpModule(mod);