diff options
Diffstat (limited to 'src/llvm_backend_general.cpp')
| -rw-r--r-- | src/llvm_backend_general.cpp | 44 |
1 files changed, 44 insertions, 0 deletions
diff --git a/src/llvm_backend_general.cpp b/src/llvm_backend_general.cpp index 61625a374..74aaafe94 100644 --- a/src/llvm_backend_general.cpp +++ b/src/llvm_backend_general.cpp @@ -301,6 +301,14 @@ lbAddr lb_addr_swizzle(lbValue addr, Type *array_type, u8 swizzle_count, u8 swiz return v; } +lbAddr lb_addr_swizzle_large(lbValue addr, Type *array_type, Slice<i32> const &swizzle_indices) { + GB_ASSERT_MSG(is_type_array(array_type), "%s", type_to_string(array_type)); + lbAddr v = {lbAddr_SwizzleLarge, addr}; + v.swizzle_large.type = array_type; + v.swizzle_large.indices = swizzle_indices; + return v; +} + Type *lb_addr_type(lbAddr const &addr) { if (addr.addr.value == nullptr) { return nullptr; @@ -313,6 +321,9 @@ Type *lb_addr_type(lbAddr const &addr) { if (addr.kind == lbAddr_Swizzle) { return addr.swizzle.type; } + if (addr.kind == lbAddr_SwizzleLarge) { + return addr.swizzle_large.type; + } return type_deref(addr.addr.type); } LLVMTypeRef lb_addr_lb_type(lbAddr const &addr) { @@ -372,6 +383,7 @@ lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) { break; case lbAddr_Swizzle: + case lbAddr_SwizzleLarge: // TOOD(bill): is this good enough logic? break; } @@ -692,6 +704,19 @@ void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value) { } } return; + } else if (addr.kind == lbAddr_SwizzleLarge) { + GB_ASSERT(value.value != nullptr); + value = lb_emit_conv(p, value, lb_addr_type(addr)); + + lbValue dst = lb_addr_get_ptr(p, addr); + lbValue src = lb_address_from_load_or_generate_local(p, value); + for_array(i, addr.swizzle_large.indices) { + lbValue src_ptr = lb_emit_array_epi(p, src, i); + lbValue dst_ptr = lb_emit_array_epi(p, dst, addr.swizzle_large.indices[i]); + lbValue src_load = lb_emit_load(p, src_ptr); + lb_emit_store(p, dst_ptr, src_load); + } + return; } GB_ASSERT(value.value != nullptr); @@ -1014,6 +1039,25 @@ lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr) { } } return lb_addr_load(p, res); + } else if (addr.kind == lbAddr_SwizzleLarge) { + Type *array_type = base_type(addr.swizzle_large.type); + GB_ASSERT(array_type->kind == Type_Array); + + unsigned res_align = cast(unsigned)type_align_of(addr.swizzle_large.type); + + Type *elem_type = base_type(array_type->Array.elem); + lbAddr res = lb_add_local_generated(p, addr.swizzle_large.type, false); + lbValue ptr = lb_addr_get_ptr(p, res); + GB_ASSERT(is_type_pointer(ptr.type)); + + for_array(i, addr.swizzle_large.indices) { + i32 index = addr.swizzle_large.indices[i]; + lbValue dst = lb_emit_array_epi(p, ptr, i); + lbValue src = lb_emit_array_epi(p, addr.addr, index); + lb_emit_store(p, dst, lb_emit_load(p, src)); + } + + return lb_addr_load(p, res); } if (is_type_proc(addr.addr.type)) { |