aboutsummaryrefslogtreecommitdiff
path: root/src/llvm_backend.cpp
diff options
context:
space:
mode:
authorgingerBill <bill@gingerbill.org>2020-03-04 22:09:58 +0000
committergingerBill <bill@gingerbill.org>2020-03-04 22:09:58 +0000
commite1da631d2620d87085f1a288e57ba39e1d7e92e5 (patch)
tree9c80cab406f2d94f49f129838bba317c480cae12 /src/llvm_backend.cpp
parent6151fdb324714c0350f5c3731357cdf7243ade97 (diff)
General functionality without `context`
Diffstat (limited to 'src/llvm_backend.cpp')
-rw-r--r--src/llvm_backend.cpp227
1 files changed, 205 insertions, 22 deletions
diff --git a/src/llvm_backend.cpp b/src/llvm_backend.cpp
index b4231d61a..3657eec60 100644
--- a/src/llvm_backend.cpp
+++ b/src/llvm_backend.cpp
@@ -1196,13 +1196,17 @@ lbValue lb_add_param(lbProcedure *p, Entity *e, Ast *expr, Type *abi_type, i32 i
return {};
}
-
void lb_start_block(lbProcedure *p, lbBlock *b) {
GB_ASSERT(b != nullptr);
- p->curr_block = b;
+ if (!b->appended) {
+ b->appended = true;
+ LLVMAppendExistingBasicBlock(p->value, b->block);
+ }
LLVMPositionBuilderAtEnd(p->builder, b->block);
+ p->curr_block = b;
}
+
void lb_begin_procedure_body(lbProcedure *p) {
DeclInfo *decl = decl_info_of_entity(p->entity);
if (decl != nullptr) {
@@ -1215,8 +1219,8 @@ void lb_begin_procedure_body(lbProcedure *p) {
p->builder = LLVMCreateBuilder();
- p->decl_block = lb_create_block(p, "decls");
- p->entry_block = lb_create_block(p, "entry");
+ p->decl_block = lb_create_block(p, "decls", true);
+ p->entry_block = lb_create_block(p, "entry", true);
lb_start_block(p, p->entry_block);
GB_ASSERT(p->type != nullptr);
@@ -1391,9 +1395,15 @@ void lb_add_edge(lbBlock *from, lbBlock *to) {
}
-lbBlock *lb_create_block(lbProcedure *p, char const *name) {
+lbBlock *lb_create_block(lbProcedure *p, char const *name, bool append) {
lbBlock *b = gb_alloc_item(heap_allocator(), lbBlock);
- b->block = LLVMAppendBasicBlockInContext(p->module->ctx, p->value, name);
+ b->block = LLVMCreateBasicBlockInContext(p->module->ctx, name);
+ b->appended = false;
+ if (append) {
+ b->appended = true;
+ LLVMAppendExistingBasicBlock(p->value, b->block);
+ }
+
b->scope = p->curr_scope;
b->scope_index = p->scope_index;
@@ -1431,7 +1441,10 @@ void lb_emit_if(lbProcedure *p, lbValue cond, lbBlock *true_block, lbBlock *fals
lb_add_edge(b, true_block);
lb_add_edge(b, false_block);
- LLVMBuildCondBr(p->builder, cond.value, true_block->block, false_block->block);
+
+ LLVMValueRef cv = cond.value;
+ cv = LLVMBuildTruncOrBitCast(p->builder, cv, lb_type(p->module, t_llvm_bool), "");
+ LLVMBuildCondBr(p->builder, cv, true_block->block, false_block->block);
}
lbValue lb_build_cond(lbProcedure *p, Ast *cond, lbBlock *true_block, lbBlock *false_block) {
@@ -2689,8 +2702,9 @@ lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast
lb_start_block(p, rhs);
lbValue edge = lb_build_expr(p, right);
+
incoming_values[done->preds.count] = edge.value;
- incoming_blocks[done->preds.count] = rhs->block;
+ incoming_blocks[done->preds.count] = p->curr_block->block;
lb_emit_jump(p, done);
lb_start_block(p, done);
@@ -2698,10 +2712,10 @@ lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast
lbValue res = {};
res.type = type;
res.value = LLVMBuildPhi(p->builder, lb_type(m, type), "");
-
+ GB_ASSERT(incoming_values.count == incoming_blocks.count);
LLVMAddIncoming(res.value, incoming_values.data, incoming_blocks.data, cast(unsigned)incoming_values.count);
- return res;
+ return short_circuit;
}
@@ -4031,11 +4045,8 @@ lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, Type *type)
switch (op) {
case Token_Not: // Boolean not
- res.value = LLVMBuildNot(p->builder, x.value, "");
- res.type = x.type;
- return res;
case Token_Xor: // Bitwise not
- res.value = LLVMBuildXor(p->builder, x.value, LLVMConstAllOnes(lb_type(p->module, x.type)), "");
+ res.value = LLVMBuildNot(p->builder, x.value, "");
res.type = x.type;
return res;
case Token_Sub: // Number negation
@@ -4058,14 +4069,172 @@ lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, Type *type)
lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type) {
lbModule *m = p->module;
+ if (is_type_array(lhs.type) || is_type_array(rhs.type)) {
+ lhs = lb_emit_conv(p, lhs, type);
+ rhs = lb_emit_conv(p, rhs, type);
+
+ lbValue x = lb_address_from_load_or_generate_local(p, lhs);
+ lbValue y = lb_address_from_load_or_generate_local(p, rhs);
+
+ GB_ASSERT(is_type_array(type));
+ Type *elem_type = base_array_type(type);
+
+ lbAddr res = lb_add_local_generated(p, type, false);
+ i64 count = base_type(type)->Array.count;
+
+ bool inline_array_arith = type_size_of(type) <= build_context.max_align;
+
+ if (inline_array_arith) {
+ for (i64 i = 0; i < count; i++) {
+ lbValue a = lb_emit_load(p, lb_emit_array_epi(p, x, i));
+ lbValue b = lb_emit_load(p, lb_emit_array_epi(p, y, i));
+ lbValue c = lb_emit_arith(p, op, a, b, elem_type);
+ lb_emit_store(p, lb_emit_array_epi(p, res.addr, i), c);
+ }
+ } else {
+ auto loop_data = lb_loop_start(p, count);
+
+ lbValue a = lb_emit_load(p, lb_emit_array_ep(p, x, loop_data.idx));
+ lbValue b = lb_emit_load(p, lb_emit_array_ep(p, y, loop_data.idx));
+ lbValue c = lb_emit_arith(p, op, a, b, elem_type);
+ lb_emit_store(p, lb_emit_array_ep(p, res.addr, loop_data.idx), c);
+
+ lb_loop_end(p, loop_data);
+ }
+
+ return lb_addr_load(p, res);
+ } else if (is_type_complex(type)) {
+ lhs = lb_emit_conv(p, lhs, type);
+ rhs = lb_emit_conv(p, rhs, type);
+
+ Type *ft = base_complex_elem_type(type);
+
+ if (op == Token_Quo) {
+ auto args = array_make<lbValue>(heap_allocator(), 2);
+ args[0] = lhs;
+ args[1] = rhs;
+
+ switch (type_size_of(ft)) {
+ case 4: return lb_emit_runtime_call(p, "quo_complex64", args);
+ case 8: return lb_emit_runtime_call(p, "quo_complex128", args);
+ default: GB_PANIC("Unknown float type"); break;
+ }
+ }
+
+ lbAddr res = lb_add_local_generated(p, type, false); // NOTE: initialized in full later
+ lbValue a = lb_emit_struct_ev(p, lhs, 0);
+ lbValue b = lb_emit_struct_ev(p, lhs, 1);
+ lbValue c = lb_emit_struct_ev(p, rhs, 0);
+ lbValue d = lb_emit_struct_ev(p, rhs, 1);
+
+ lbValue real = {};
+ lbValue imag = {};
+
+ switch (op) {
+ case Token_Add:
+ real = lb_emit_arith(p, Token_Add, a, c, ft);
+ imag = lb_emit_arith(p, Token_Add, b, d, ft);
+ break;
+ case Token_Sub:
+ real = lb_emit_arith(p, Token_Sub, a, c, ft);
+ imag = lb_emit_arith(p, Token_Sub, b, d, ft);
+ break;
+ case Token_Mul: {
+ lbValue x = lb_emit_arith(p, Token_Mul, a, c, ft);
+ lbValue y = lb_emit_arith(p, Token_Mul, b, d, ft);
+ real = lb_emit_arith(p, Token_Sub, x, y, ft);
+ lbValue z = lb_emit_arith(p, Token_Mul, b, c, ft);
+ lbValue w = lb_emit_arith(p, Token_Mul, a, d, ft);
+ imag = lb_emit_arith(p, Token_Add, z, w, ft);
+ break;
+ }
+ }
+
+ lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 0), real);
+ lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 1), imag);
+
+ return lb_addr_load(p, res);
+ } else if (is_type_quaternion(type)) {
+ lhs = lb_emit_conv(p, lhs, type);
+ rhs = lb_emit_conv(p, rhs, type);
+
+ Type *ft = base_complex_elem_type(type);
+
+ if (op == Token_Add || op == Token_Sub) {
+ lbAddr res = lb_add_local_generated(p, type, false); // NOTE: initialized in full later
+ lbValue x0 = lb_emit_struct_ev(p, lhs, 0);
+ lbValue x1 = lb_emit_struct_ev(p, lhs, 1);
+ lbValue x2 = lb_emit_struct_ev(p, lhs, 2);
+ lbValue x3 = lb_emit_struct_ev(p, lhs, 3);
+
+ lbValue y0 = lb_emit_struct_ev(p, rhs, 0);
+ lbValue y1 = lb_emit_struct_ev(p, rhs, 1);
+ lbValue y2 = lb_emit_struct_ev(p, rhs, 2);
+ lbValue y3 = lb_emit_struct_ev(p, rhs, 3);
+
+ lbValue z0 = lb_emit_arith(p, op, x0, y0, ft);
+ lbValue z1 = lb_emit_arith(p, op, x1, y1, ft);
+ lbValue z2 = lb_emit_arith(p, op, x2, y2, ft);
+ lbValue z3 = lb_emit_arith(p, op, x3, y3, ft);
+
+ lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 0), z0);
+ lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 1), z1);
+ lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 2), z2);
+ lb_emit_store(p, lb_emit_struct_ep(p, res.addr, 3), z3);
+
+ return lb_addr_load(p, res);
+ } else if (op == Token_Mul) {
+ auto args = array_make<lbValue>(heap_allocator(), 2);
+ args[0] = lhs;
+ args[1] = rhs;
+
+ switch (8*type_size_of(ft)) {
+ case 32: return lb_emit_runtime_call(p, "mul_quaternion128", args);
+ case 64: return lb_emit_runtime_call(p, "mul_quaternion256", args);
+ default: GB_PANIC("Unknown float type"); break;
+ }
+ } else if (op == Token_Quo) {
+ auto args = array_make<lbValue>(heap_allocator(), 2);
+ args[0] = lhs;
+ args[1] = rhs;
+
+ switch (8*type_size_of(ft)) {
+ case 32: return lb_emit_runtime_call(p, "quo_quaternion128", args);
+ case 64: return lb_emit_runtime_call(p, "quo_quaternion256", args);
+ default: GB_PANIC("Unknown float type"); break;
+ }
+ }
+ }
+
+ if (is_type_integer(type) && is_type_different_to_arch_endianness(type)) {
+ switch (op) {
+ case Token_AndNot:
+ case Token_And:
+ case Token_Or:
+ case Token_Xor:
+ goto handle_op;
+ }
+
+ Type *platform_type = integer_endian_type_to_platform_type(type);
+ lbValue x = lb_emit_byte_swap(p, lhs, integer_endian_type_to_platform_type(lhs.type));
+ lbValue y = lb_emit_byte_swap(p, rhs, integer_endian_type_to_platform_type(rhs.type));
+
+ lbValue res = lb_emit_arith(p, op, x, y, platform_type);
+
+ return lb_emit_byte_swap(p, res, type);
+ }
+
+
+
+handle_op:
lhs = lb_emit_conv(p, lhs, type);
rhs = lb_emit_conv(p, rhs, type);
-
lbValue res = {};
res.type = type;
+
switch (op) {
case Token_Add:
if (is_type_float(type)) {
@@ -4143,8 +4312,7 @@ lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Ty
return res;
case Token_AndNot:
{
- LLVMValueRef all_ones = LLVMConstAllOnes(lb_type(m, type));
- LLVMValueRef new_rhs = LLVMBuildXor(p->builder, all_ones, rhs.value, "");
+ LLVMValueRef new_rhs = LLVMBuildNot(p->builder, rhs.value, "");
res.value = LLVMBuildAnd(p->builder, lhs.value, new_rhs, "");
return res;
}
@@ -4852,7 +5020,7 @@ void lb_emit_init_context(lbProcedure *p, lbValue c) {
gbAllocator a = heap_allocator();
auto args = array_make<lbValue>(a, 1);
args[0] = c.value != nullptr ? c : m->global_default_context.addr;
- // lb_emit_runtime_call(p, "__init_context", args);
+ lb_emit_runtime_call(p, "__init_context", args);
}
void lb_push_context_onto_stack(lbProcedure *p, lbAddr ctx) {
@@ -4866,10 +5034,6 @@ lbAddr lb_find_or_generate_context_ptr(lbProcedure *p) {
return p->context_stack[p->context_stack.count-1].ctx;
}
- // lbBlock *tmp_block = p->curr_block;
- // p->curr_block = p->blocks[0];
- // defer (p->curr_block = tmp_block);
-
lbAddr c = lb_add_local_generated(p, t_context, false);
c.kind = lbAddr_Context;
lb_push_context_onto_stack(p, c);
@@ -6495,10 +6659,29 @@ void lb_emit_increment(lbProcedure *p, lbValue addr) {
lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *platform_type) {
Type *vt = core_type(value.type);
GB_ASSERT(type_size_of(vt) == type_size_of(platform_type));
+ GB_ASSERT(is_type_integer(vt));
+
// TODO(bill): lb_emit_byte_swap
lbValue res = {};
res.type = platform_type;
res.value = value.value;
+
+ // int sz = cast(int)type_size_of(vt);
+ // if (sz > 1) {
+ // char buf[32] = {};
+ // gb_snprintf(buf, gb_count_of(buf), "llvm.bswap.i%d", sz*8);
+ // unsigned id = LLVMLookupIntrinsicID(buf, gb_strlen(buf));
+ // gb_printf(">>> %s %u\n", buf, id);
+
+ // LLVMTypeRef types[2] = {};
+ // types[0] = lb_type(p->module, value.type);
+ // types[1] = lb_type(p->module, value.type);
+
+ // LLVMValueRef fn = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
+
+ // res.value = LLVMBuildCall(p->builder, fn, &value.value, 1, "");
+ // }
+
return res;
}