diff options
| author | gingerBill <bill@gingerbill.org> | 2021-08-09 19:37:58 +0100 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2021-08-09 19:37:58 +0100 |
| commit | 01f431b01fea18b0844d0475839c68426e95fd2c (patch) | |
| tree | 7420e056934a923083249fa4863b168877b9855f /src/llvm_backend_expr.cpp | |
| parent | aebfa4b28e5d92e493010593f4177f53249aa6b2 (diff) | |
Unify semantics of the built-in `swizzle` procedure with the selector expression semantics e.g. `.xyz`
Diffstat (limited to 'src/llvm_backend_expr.cpp')
| -rw-r--r-- | src/llvm_backend_expr.cpp | 56 |
1 files changed, 56 insertions, 0 deletions
diff --git a/src/llvm_backend_expr.cpp b/src/llvm_backend_expr.cpp index e5a57d3d3..1c5f03722 100644 --- a/src/llvm_backend_expr.cpp +++ b/src/llvm_backend_expr.cpp @@ -2497,6 +2497,41 @@ lbAddr lb_build_addr_from_entity(lbProcedure *p, Entity *e, Ast *expr) { return lb_addr(v); } +lbAddr lb_build_array_swizzle_addr(lbProcedure *p, AstCallExpr *ce, TypeAndValue const &tv) { + isize index_count = ce->args.count-1; + lbAddr addr = lb_build_addr(p, ce->args[0]); + if (index_count == 0) { + return addr; + } + Type *type = base_type(lb_addr_type(addr)); + GB_ASSERT(type->kind == Type_Array); + i64 count = type->Array.count; + if (count <= 4) { + u8 indices[4] = {}; + u8 index_count = 0; + for (i32 i = 1; i < ce->args.count; i++) { + TypeAndValue tv = type_and_value_of_expr(ce->args[i]); + GB_ASSERT(is_type_integer(tv.type)); + GB_ASSERT(tv.value.kind == ExactValue_Integer); + + i64 src_index = big_int_to_i64(&tv.value.value_integer); + indices[index_count++] = cast(u8)src_index; + } + return lb_addr_swizzle(lb_addr_get_ptr(p, addr), tv.type, index_count, indices); + } + auto indices = slice_make<i32>(permanent_allocator(), ce->args.count-1); + isize index_index = 0; + for (i32 i = 1; i < ce->args.count; i++) { + TypeAndValue tv = type_and_value_of_expr(ce->args[i]); + GB_ASSERT(is_type_integer(tv.type)); + GB_ASSERT(tv.value.kind == ExactValue_Integer); + + i64 src_index = big_int_to_i64(&tv.value.value_integer); + indices[index_index++] = cast(i32)src_index; + } + return lb_addr_swizzle_large(lb_addr_get_ptr(p, addr), tv.type, indices); +} + lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { expr = unparen_expr(expr); @@ -2617,6 +2652,10 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { GB_ASSERT(sel.index.count > 0); // NOTE(bill): just patch the index in place sel.index[0] = addr.swizzle.indices[sel.index[0]]; + } else if (addr.kind == lbAddr_SwizzleLarge) { + GB_ASSERT(sel.index.count > 0); + // NOTE(bill): just patch the index in place + sel.index[0] = addr.swizzle.indices[sel.index[0]]; } lbValue a = lb_addr_get_ptr(p, addr); a = lb_emit_deep_field_gep(p, a, sel); @@ -3028,6 +3067,23 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) { case_end; case_ast_node(ce, CallExpr, expr); + BuiltinProcId builtin_id = BuiltinProc_Invalid; + if (ce->proc->tav.mode == Addressing_Builtin) { + Entity *e = entity_of_node(ce->proc); + if (e != nullptr) { + builtin_id = cast(BuiltinProcId)e->Builtin.id; + } else { + builtin_id = BuiltinProc_DIRECTIVE; + } + } + auto const &tv = expr->tav; + if (builtin_id == BuiltinProc_swizzle && + is_type_array(tv.type)) { + // NOTE(bill, 2021-08-09): `swizzle` has some bizarre semantics so it needs to be + // specialized here for to be addressable + return lb_build_array_swizzle_addr(p, ce, tv); + } + // NOTE(bill): This is make sure you never need to have an 'array_ev' lbValue e = lb_build_expr(p, expr); #if 1 |