aboutsummaryrefslogtreecommitdiff
path: root/src/llvm_backend_general.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/llvm_backend_general.cpp')
-rw-r--r--src/llvm_backend_general.cpp127
1 files changed, 98 insertions, 29 deletions
diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp
index 0d8d9258a..02afa628c 100644
--- a/src/llvm_backend_general.cpp
+++ b/src/llvm_backend_general.cpp
@@ -211,7 +211,7 @@ gb_internal void lb_loop_end(lbProcedure *p, lbLoopData const &data) {
gb_internal void lb_make_global_private_const(LLVMValueRef global_data) {
- LLVMSetLinkage(global_data, LLVMPrivateLinkage);
+ LLVMSetLinkage(global_data, LLVMLinkerPrivateLinkage);
LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
LLVMSetGlobalConstant(global_data, true);
}
@@ -450,14 +450,13 @@ gb_internal lbAddr lb_addr_swizzle_large(lbValue addr, Type *array_type, Slice<i
return v;
}
-gb_internal lbAddr lb_addr_bit_field(lbValue addr, Type *type, i64 index, i64 bit_offset, i64 bit_size) {
+gb_internal lbAddr lb_addr_bit_field(lbValue addr, Type *type, i64 bit_offset, i64 bit_size) {
GB_ASSERT(is_type_pointer(addr.type));
Type *mt = type_deref(addr.type);
GB_ASSERT_MSG(is_type_bit_field(mt), "%s", type_to_string(mt));
lbAddr v = {lbAddr_BitField, addr};
v.bitfield.type = type;
- v.bitfield.index = index;
v.bitfield.bit_offset = bit_offset;
v.bitfield.bit_size = bit_size;
return v;
@@ -774,13 +773,40 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) {
if (addr.kind == lbAddr_BitField) {
lbValue dst = addr.addr;
+ if (is_type_endian_big(addr.bitfield.type)) {
+ i64 shift_amount = 8*type_size_of(value.type) - addr.bitfield.bit_size;
+ lbValue shifted_value = value;
+ shifted_value.value = LLVMBuildLShr(p->builder,
+ shifted_value.value,
+ LLVMConstInt(LLVMTypeOf(shifted_value.value), shift_amount, false), "");
+
+ lbValue src = lb_address_from_load_or_generate_local(p, shifted_value);
+
+ auto args = array_make<lbValue>(temporary_allocator(), 4);
+ args[0] = dst;
+ args[1] = src;
+ args[2] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_offset);
+ args[3] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_size);
+ lb_emit_runtime_call(p, "__write_bits", args);
+ } else if ((addr.bitfield.bit_offset % 8) == 0 &&
+ (addr.bitfield.bit_size % 8) == 0) {
+ lbValue src = lb_address_from_load_or_generate_local(p, value);
+
+ lbValue byte_offset = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_offset/8);
+ lbValue byte_size = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_size/8);
+ lbValue dst_offset = lb_emit_conv(p, dst, t_u8_ptr);
+ dst_offset = lb_emit_ptr_offset(p, dst_offset, byte_offset);
+ lb_mem_copy_non_overlapping(p, dst_offset, src, byte_size);
+ } else {
+ lbValue src = lb_address_from_load_or_generate_local(p, value);
- auto args = array_make<lbValue>(temporary_allocator(), 4);
- args[0] = dst;
- args[1] = lb_address_from_load_or_generate_local(p, value);
- args[2] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_offset);
- args[3] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_size);
- lb_emit_runtime_call(p, "__write_bits", args);
+ auto args = array_make<lbValue>(temporary_allocator(), 4);
+ args[0] = dst;
+ args[1] = src;
+ args[2] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_offset);
+ args[3] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_size);
+ lb_emit_runtime_call(p, "__write_bits", args);
+ }
return;
} else if (addr.kind == lbAddr_RelativePointer) {
Type *rel_ptr = base_type(lb_addr_type(addr));
@@ -954,16 +980,6 @@ gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) {
GB_ASSERT(value.value != nullptr);
value = lb_emit_conv(p, value, lb_addr_type(addr));
- // if (lb_is_const_or_global(value)) {
- // // NOTE(bill): Just bypass the actual storage and set the initializer
- // if (LLVMGetValueKind(addr.addr.value) == LLVMGlobalVariableValueKind) {
- // LLVMValueRef dst = addr.addr.value;
- // LLVMValueRef src = value.value;
- // LLVMSetInitializer(dst, src);
- // return;
- // }
- // }
-
lb_emit_store(p, addr.addr, value);
}
@@ -1098,23 +1114,76 @@ gb_internal lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) {
GB_ASSERT(addr.addr.value != nullptr);
if (addr.kind == lbAddr_BitField) {
+ Type *ct = core_type(addr.bitfield.type);
+ bool do_mask = false;
+ if (is_type_unsigned(ct) || is_type_boolean(ct)) {
+ // Mask
+ if (addr.bitfield.bit_size != 8*type_size_of(ct)) {
+ do_mask = true;
+ }
+ }
+
+ i64 total_bitfield_bit_size = 8*type_size_of(lb_addr_type(addr));
+ i64 dst_byte_size = type_size_of(addr.bitfield.type);
lbAddr dst = lb_add_local_generated(p, addr.bitfield.type, true);
lbValue src = addr.addr;
- auto args = array_make<lbValue>(temporary_allocator(), 4);
- args[0] = dst.addr;
- args[1] = src;
- args[2] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_offset);
- args[3] = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_size);
- lb_emit_runtime_call(p, "__read_bits", args);
+ lbValue bit_offset = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_offset);
+ lbValue bit_size = lb_const_int(p->module, t_uintptr, addr.bitfield.bit_size);
+ lbValue byte_offset = lb_const_int(p->module, t_uintptr, (addr.bitfield.bit_offset+7)/8);
+ lbValue byte_size = lb_const_int(p->module, t_uintptr, (addr.bitfield.bit_size+7)/8);
+
+ GB_ASSERT(type_size_of(addr.bitfield.type) >= ((addr.bitfield.bit_size+7)/8));
+
+ lbValue r = {};
+ if (is_type_endian_big(addr.bitfield.type)) {
+ auto args = array_make<lbValue>(temporary_allocator(), 4);
+ args[0] = dst.addr;
+ args[1] = src;
+ args[2] = bit_offset;
+ args[3] = bit_size;
+ lb_emit_runtime_call(p, "__read_bits", args);
+
+ LLVMValueRef shift_amount = LLVMConstInt(
+ lb_type(p->module, lb_addr_type(dst)),
+ 8*dst_byte_size - addr.bitfield.bit_size,
+ false
+ );
+ r = lb_addr_load(p, dst);
+ r.value = LLVMBuildShl(p->builder, r.value, shift_amount, "");
+ } else if ((addr.bitfield.bit_offset % 8) == 0) {
+ lbValue copy_size = byte_size;
+ lbValue src_offset = lb_emit_conv(p, src, t_u8_ptr);
+ src_offset = lb_emit_ptr_offset(p, src_offset, byte_offset);
+ if (addr.bitfield.bit_offset + dst_byte_size <= total_bitfield_bit_size) {
+ do_mask = true;
+ copy_size = lb_const_int(p->module, t_uintptr, dst_byte_size);
+ }
+ lb_mem_copy_non_overlapping(p, dst.addr, src_offset, copy_size, false);
+ r = lb_addr_load(p, dst);
+ } else {
+ auto args = array_make<lbValue>(temporary_allocator(), 4);
+ args[0] = dst.addr;
+ args[1] = src;
+ args[2] = bit_offset;
+ args[3] = bit_size;
+ lb_emit_runtime_call(p, "__read_bits", args);
+ r = lb_addr_load(p, dst);
+ }
- lbValue r = lb_addr_load(p, dst);
+ Type *t = addr.bitfield.type;
+
+ if (do_mask) {
+ GB_ASSERT(addr.bitfield.bit_size < 8*type_size_of(ct));
+
+ lbValue mask = lb_const_int(p->module, t, (1ull<<cast(u64)addr.bitfield.bit_size)-1);
+ r = lb_emit_arith(p, Token_And, r, mask, t);
+ }
- if (!is_type_unsigned(core_type(addr.bitfield.type))) {
+ if (!is_type_unsigned(ct) && !is_type_boolean(ct)) {
// Sign extension
// m := 1<<(bit_size-1)
// r = (r XOR m) - m
- Type *t = addr.bitfield.type;
lbValue m = lb_const_int(p->module, t, 1ull<<(addr.bitfield.bit_size-1));
r = lb_emit_arith(p, Token_Xor, r, m, t);
r = lb_emit_arith(p, Token_Sub, r, m, t);
@@ -2080,7 +2149,7 @@ gb_internal LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
break;
case Type_Map:
- init_map_internal_types(type);
+ init_map_internal_debug_types(type);
GB_ASSERT(t_raw_map != nullptr);
return lb_type_internal(m, t_raw_map);