From dfbdae6a3bb98a5075fbbad713e16d5b75b8b6d4 Mon Sep 17 00:00:00 2001 From: Nick Gasson Date: Fri, 14 Jan 2022 17:42:19 +0800 Subject: [PATCH] Separate vcode opcode for pointer addition --- src/cgen.c | 63 +++++++++++++++++++--------- src/cprop.c | 16 ++++++- src/exec.c | 30 ++++++++----- src/lower.c | 104 +++++++++++++++++++++++++--------------------- src/vcode.c | 64 +++++++++++++++++++--------- src/vcode.h | 2 + test/test_lower.c | 87 ++++++++++++++++++++++++-------------- 7 files changed, 234 insertions(+), 132 deletions(-) diff --git a/src/cgen.c b/src/cgen.c index 9c4a64e8..830e037a 100644 --- a/src/cgen.c +++ b/src/cgen.c @@ -1255,30 +1255,11 @@ static void cgen_op_load_indirect(int op, cgen_ctx_t *ctx) static void cgen_op_add(int op, cgen_ctx_t *ctx) { vcode_reg_t result = vcode_get_result(op); - vtype_kind_t kind = vtype_kind(vcode_reg_type(result)); LLVMValueRef lhs = cgen_get_arg(op, 0, ctx); LLVMValueRef rhs = cgen_get_arg(op, 1, ctx); - if (kind == VCODE_TYPE_POINTER) { - LLVMValueRef index[] = { rhs }; - ctx->regs[result] = LLVMBuildInBoundsGEP(builder, lhs, - index, ARRAY_LEN(index), - cgen_reg_name(result)); - } - else if (kind == VCODE_TYPE_SIGNAL) { - LLVMValueRef base = LLVMBuildExtractValue(builder, lhs, 1, "base"); - vcode_type_t vtype = vtype_base(vcode_reg_type(vcode_get_arg(op, 0))); - LLVMValueRef null = LLVMConstNull(LLVMPointerType(cgen_type(vtype), 0)); - LLVMValueRef index[] = { rhs }; - LLVMValueRef gep = LLVMBuildInBoundsGEP(builder, null, index, 1, ""); - LLVMValueRef scaled = - LLVMBuildPtrToInt(builder, gep, llvm_int32_type(), ""); - LLVMValueRef add = LLVMBuildAdd(builder, base, scaled, ""); - ctx->regs[result] = LLVMBuildInsertValue(builder, lhs, - add, 1, cgen_reg_name(result)); - } - else if (vcode_reg_kind(result) == VCODE_TYPE_REAL) + if (vcode_reg_kind(result) == VCODE_TYPE_REAL) ctx->regs[result] = LLVMBuildFAdd(builder, lhs, rhs, cgen_reg_name(result)); else @@ -2101,6 +2082,45 @@ static void cgen_op_copy(int op, cgen_ctx_t *ctx) memcpy_args, ARRAY_LEN(memcpy_args), ""); } +static void cgen_op_array_ref(int op, cgen_ctx_t *ctx) +{ + vcode_reg_t result = vcode_get_result(op); + + LLVMValueRef lhs = cgen_get_arg(op, 0, ctx); + LLVMValueRef rhs = cgen_get_arg(op, 1, ctx); + + switch (vcode_reg_kind(result)) { + case VCODE_TYPE_POINTER: + { + LLVMValueRef index[] = { rhs }; + ctx->regs[result] = LLVMBuildInBoundsGEP(builder, lhs, + index, ARRAY_LEN(index), + cgen_reg_name(result)); + } + break; + + case VCODE_TYPE_SIGNAL: + { + LLVMValueRef base = LLVMBuildExtractValue(builder, lhs, 1, "base"); + vcode_type_t vtype = vtype_base(vcode_reg_type(vcode_get_arg(op, 0))); + LLVMValueRef null = + LLVMConstNull(LLVMPointerType(cgen_type(vtype), 0)); + LLVMValueRef index[] = { rhs }; + LLVMValueRef gep = LLVMBuildInBoundsGEP(builder, null, index, 1, ""); + LLVMValueRef scaled = + LLVMBuildPtrToInt(builder, gep, llvm_int32_type(), ""); + LLVMValueRef add = LLVMBuildAdd(builder, base, scaled, ""); + ctx->regs[result] = LLVMBuildInsertValue(builder, lhs, + add, 1, cgen_reg_name(result)); + } + break; + + default: + vcode_dump_with_mark(op, NULL, NULL); + fatal_trace("unexpected array ref result kind"); + } +} + static void cgen_op_record_ref(int op, cgen_ctx_t *ctx) { vcode_reg_t result = vcode_get_result(op); @@ -3022,6 +3042,9 @@ static void cgen_op(int i, cgen_ctx_t *ctx) case VCODE_OP_RECORD_REF: cgen_op_record_ref(i, ctx); break; + case VCODE_OP_ARRAY_REF: + cgen_op_array_ref(i, ctx); + break; case VCODE_OP_SCHED_EVENT: cgen_op_sched_event(i, ctx); break; diff --git a/src/cprop.c b/src/cprop.c index ac6e4e87..ed85789f 100644 --- a/src/cprop.c +++ b/src/cprop.c @@ -353,8 +353,20 @@ void cprop(cprop_req_t *req) regs[result].base = arg0; regs[result].scale = arg1; } - else if (kind == VCODE_OP_ADD - && vcode_reg_kind(result) == VCODE_TYPE_SIGNAL) { + else + regs[result].tag = CP_UNKNOWN; + } + break; + + case VCODE_OP_ARRAY_REF: + { + vcode_reg_t arg0 = vcode_get_arg(op, 0); + vcode_reg_t arg1 = vcode_get_arg(op, 1); + + vcode_reg_t result = vcode_get_result(op); + assert(result != VCODE_INVALID_REG); + + if (vcode_reg_kind(result) == VCODE_TYPE_SIGNAL) { const unsigned stride = cprop_count_subsignals(vtype_base(vcode_reg_type(arg0))); regs[result].tag = CP_OFFSET; diff --git a/src/exec.c b/src/exec.c index 8a608539..309a0718 100644 --- a/src/exec.c +++ b/src/exec.c @@ -564,16 +564,6 @@ static void eval_op_add(int op, eval_state_t *state) dst->real = lhs->real + rhs->real; break; - case VALUE_POINTER: - { - EVAL_ASSERT_VALUE(op, rhs, VALUE_INTEGER); - vcode_type_t vtype = vtype_pointed(vcode_reg_type(result)); - const int stride = eval_slots_for_type(vtype); - eval_make_pointer_to(dst, lhs->pointer + rhs->integer * stride); - EVAL_ASSERT_VALID(op, dst->pointer); - } - break; - default: fatal_trace("invalid value type in %s", __func__); } @@ -1639,6 +1629,22 @@ static void eval_op_record_ref(int op, eval_state_t *state) eval_make_pointer_to(dst, field); } +static void eval_op_array_ref(int op, eval_state_t *state) +{ + vcode_reg_t result = vcode_get_result(op); + value_t *ptr = eval_get_reg(vcode_get_arg(op, 0), state); + value_t *offset = eval_get_reg(vcode_get_arg(op, 1), state); + value_t *dst = eval_get_reg(result, state); + + EVAL_ASSERT_VALUE(op, ptr, VALUE_POINTER); + EVAL_ASSERT_VALUE(op, offset, VALUE_INTEGER); + + vcode_type_t vtype = vtype_pointed(vcode_reg_type(result)); + const int stride = eval_slots_for_type(vtype); + eval_make_pointer_to(dst, ptr->pointer + offset->integer * stride); + EVAL_ASSERT_VALID(op, dst->pointer); +} + static void eval_op_memset(int op, eval_state_t *state) { value_t *dst = eval_get_reg(vcode_get_arg(op, 0), state); @@ -2041,6 +2047,10 @@ static void eval_vcode(eval_state_t *state) eval_op_record_ref(state->op, state); break; + case VCODE_OP_ARRAY_REF: + eval_op_array_ref(state->op, state); + break; + case VCODE_OP_MEMSET: eval_op_memset(state->op, state); break; diff --git a/src/lower.c b/src/lower.c index eba31a96..b73c7d5c 100644 --- a/src/lower.c +++ b/src/lower.c @@ -1994,8 +1994,8 @@ static vcode_reg_t lower_array_ref(tree_t ref, expr_ctx_t ctx) offset_reg = emit_mul(offset_reg, lower_array_stride(array, value_type)); - vcode_reg_t data_reg = lower_array_data(array); - return emit_add(data_reg, offset_reg); + vcode_reg_t data_reg = lower_array_data(array); + return emit_array_ref(data_reg, offset_reg); } static vcode_reg_t lower_array_slice(tree_t slice, expr_ctx_t ctx) @@ -2042,8 +2042,9 @@ static vcode_reg_t lower_array_slice(tree_t slice, expr_ctx_t ctx) vcode_reg_t stride_reg = lower_array_stride(array_reg, type); vcode_reg_t data_reg = lower_array_data(array_reg); - vcode_reg_t off_reg = lower_array_off(left_reg, array_reg, type, 0); - vcode_reg_t ptr_reg = emit_add(data_reg, emit_mul(off_reg, stride_reg)); + vcode_reg_t off_reg = lower_array_off(left_reg, array_reg, type, 0); + vcode_reg_t ptr_reg = + emit_array_ref(data_reg, emit_mul(off_reg, stride_reg)); if (lower_const_bounds(type)) return ptr_reg; @@ -2476,7 +2477,7 @@ static vcode_reg_t lower_array_aggregate(tree_t expr, vcode_reg_t hint) vcode_reg_t next_reg = emit_add(i_reg, inc_reg); emit_store(next_reg, i_var); - vcode_reg_t ptr_reg = emit_add(mem_reg, i_reg); + vcode_reg_t ptr_reg = emit_array_ref(mem_reg, i_reg); if (def_reg == VCODE_INVALID_REG) { if (tree_kind(def_value) == T_AGGREGATE) @@ -2573,7 +2574,7 @@ static vcode_reg_t lower_array_aggregate(tree_t expr, vcode_reg_t hint) if (stride != VCODE_INVALID_REG) off_reg = emit_mul(off_reg, stride); - vcode_reg_t ptr_reg = emit_add(mem_reg, off_reg); + vcode_reg_t ptr_reg = emit_array_ref(mem_reg, off_reg); if (value_reg == VCODE_INVALID_REG) { // Prefer generating aggregates in-place @@ -2738,17 +2739,17 @@ static vcode_reg_t lower_concat(tree_t expr, expr_ctx_t ctx) emit_copy(ptr, data_reg, src_len); if (i + 1 < args.count) - ptr = emit_add(ptr, src_len); + ptr = emit_array_ref(ptr, src_len); } else if (type_is_record(p->type)) { emit_copy(ptr, p->reg, VCODE_INVALID_REG); if (i + 1 < args.count) - ptr = emit_add(ptr, emit_const(vtype_offset(), 1)); + ptr = emit_array_ref(ptr, emit_const(vtype_offset(), 1)); } else { emit_store_indirect(lower_reify(p->reg), ptr); if (i + 1 < args.count) - ptr = emit_add(ptr, emit_const(vtype_offset(), 1)); + ptr = emit_array_ref(ptr, emit_const(vtype_offset(), 1)); } } @@ -3644,7 +3645,7 @@ static void lower_var_assign_target(target_part_t **ptr, tree_t where, if (p->kind == PART_ELEM) { assert(vcode_reg_kind(src_reg) == VCODE_TYPE_POINTER); - rhs = emit_add(src_reg, emit_const(vtype_offset(), 1)); + rhs = emit_array_ref(src_reg, emit_const(vtype_offset(), 1)); } } } @@ -3792,7 +3793,7 @@ static void lower_signal_assign_target(target_part_t **ptr, tree_t where, if (p->kind == PART_ELEM) { assert(vcode_reg_kind(src_reg) == VCODE_TYPE_POINTER); - rhs = emit_add(src_reg, emit_const(vtype_offset(), 1)); + rhs = emit_array_ref(src_reg, emit_const(vtype_offset(), 1)); } } } @@ -4364,7 +4365,7 @@ static void lower_case_array(tree_t stmt, loop_stack_t *loops) enc_type = voffset; enc_reg = emit_const(enc_type, 0); for (int64_t i = 0; i < length; i++) { - vcode_reg_t ptr_reg = emit_add(data_ptr, emit_const(voffset, i)); + vcode_reg_t ptr_reg = emit_array_ref(data_ptr, emit_const(voffset, i)); vcode_reg_t byte_reg = emit_load_indirect(ptr_reg); enc_reg = emit_mul(enc_reg, emit_const(enc_type, 1 << nbits)); enc_reg = emit_add(enc_reg, emit_cast(enc_type, enc_type, byte_reg)); @@ -4385,10 +4386,11 @@ static void lower_case_array(tree_t stmt, loop_stack_t *loops) vcode_select_block(body_bb); - vcode_reg_t i_reg = emit_load(i_var); - vcode_reg_t ptr_reg = emit_add(data_ptr, i_reg); + vcode_reg_t i_reg = emit_load(i_var); + vcode_reg_t ptr_reg = emit_array_ref(data_ptr, i_reg); vcode_reg_t byte_reg = emit_load_indirect(ptr_reg); - vcode_reg_t tmp_reg = emit_load(enc_var); + vcode_reg_t tmp_reg = emit_load(enc_var); + if (exact_map) tmp_reg = emit_mul(tmp_reg, emit_const(enc_type, 1 << nbits)); else @@ -4857,8 +4859,8 @@ static void lower_sub_signals(type_t type, tree_t where, vcode_reg_t subsig, vcode_select_block(body_bb); - vcode_reg_t ptr_reg = emit_add(subsig, i_reg); - vcode_reg_t data_reg = emit_add(lower_array_data(init_reg), i_reg); + vcode_reg_t ptr_reg = emit_array_ref(subsig, i_reg); + vcode_reg_t data_reg = emit_array_ref(lower_array_data(init_reg), i_reg); lower_sub_signals(type_elem(type), where, ptr_reg, data_reg, resolution); emit_store(emit_add(i_reg, emit_const(voffset, 1)), i_var); @@ -5113,11 +5115,12 @@ static void lower_physical_image_helper(type_t type, vcode_reg_t preg) vcode_reg_t mem_reg = emit_alloca(ctype, ctype, total_len); emit_copy(mem_reg, emit_unwrap(num_reg), num_len); - vcode_reg_t ptr0_reg = emit_add(mem_reg, num_len); + vcode_reg_t ptr0_reg = emit_array_ref(mem_reg, num_len); emit_store_indirect(emit_const(ctype, ' '), ptr0_reg); vcode_reg_t unit_reg = lower_wrap_string(unit0); - vcode_reg_t ptr1_reg = emit_add(ptr0_reg, emit_const(vtype_offset(), 1)); + vcode_reg_t ptr1_reg = + emit_array_ref(ptr0_reg, emit_const(vtype_offset(), 1)); emit_copy(ptr1_reg, emit_unwrap(unit_reg), emit_const(vtype_offset(), strlen(unit0))); @@ -5265,14 +5268,14 @@ static vcode_reg_t lower_enum_value_helper(type_t type, vcode_reg_t preg) vcode_block_t skip_bb = emit_block(); vcode_block_t match_bb = emit_block(); - vcode_reg_t len_ptr = emit_add(len_array_ptr, i_reg); + vcode_reg_t len_ptr = emit_array_ref(len_array_ptr, i_reg); vcode_reg_t len_reg = emit_load_indirect(len_ptr); vcode_reg_t len_eq = emit_cmp(VCODE_CMP_EQ, len_reg, canon_len_reg); emit_cond(len_eq, memcmp_bb, skip_bb); vcode_select_block(memcmp_bb); vcode_reg_t char_off = emit_mul(i_reg, emit_const(voffset, stride)); - vcode_reg_t char_ptr = emit_add(char_array_ptr, char_off); + vcode_reg_t char_ptr = emit_array_ref(char_array_ptr, char_off); vcode_dim_t dims[] = { { .left = emit_const(vtype_offset(), 1), @@ -5315,10 +5318,10 @@ static vcode_reg_t lower_enum_value_helper(type_t type, vcode_reg_t preg) emit_store_indirect(emit_const(vchar, '\"'), mem_reg); - vcode_reg_t ptr1_reg = emit_add(mem_reg, emit_const(voffset, 1)); + vcode_reg_t ptr1_reg = emit_array_ref(mem_reg, emit_const(voffset, 1)); emit_copy(ptr1_reg, arg_data_reg, arg_len_reg); - vcode_reg_t ptr2_reg = emit_add(ptr1_reg, arg_len_reg); + vcode_reg_t ptr2_reg = emit_array_ref(ptr1_reg, arg_len_reg); emit_copy(ptr2_reg, emit_unwrap(const_str_reg), const_str_len); vcode_reg_t locus = lower_debug_locus(type_enum_literal(type, 0)); @@ -5416,14 +5419,14 @@ static vcode_reg_t lower_physical_value_helper(type_t type, vcode_reg_t preg) vcode_block_t skip_bb = emit_block(); vcode_block_t match_bb = emit_block(); - vcode_reg_t len_ptr = emit_add(len_array_ptr, i_reg); + vcode_reg_t len_ptr = emit_array_ref(len_array_ptr, i_reg); vcode_reg_t len_reg = emit_load_indirect(len_ptr); vcode_reg_t len_eq = emit_cmp(VCODE_CMP_EQ, len_reg, canon_len_reg); emit_cond(len_eq, memcmp_bb, skip_bb); vcode_select_block(memcmp_bb); vcode_reg_t char_off = emit_mul(i_reg, emit_const(voffset, stride)); - vcode_reg_t char_ptr = emit_add(char_array_ptr, char_off); + vcode_reg_t char_ptr = emit_array_ref(char_array_ptr, char_off); vcode_dim_t dims[] = { { .left = emit_const(vtype_offset(), 1), @@ -5465,10 +5468,10 @@ static vcode_reg_t lower_physical_value_helper(type_t type, vcode_reg_t preg) emit_store_indirect(emit_const(vchar, '\"'), mem_reg); - vcode_reg_t ptr1_reg = emit_add(mem_reg, emit_const(voffset, 1)); + vcode_reg_t ptr1_reg = emit_array_ref(mem_reg, emit_const(voffset, 1)); emit_copy(ptr1_reg, tail_reg, tail_len); - vcode_reg_t ptr2_reg = emit_add(ptr1_reg, tail_len); + vcode_reg_t ptr2_reg = emit_array_ref(ptr1_reg, tail_len); emit_copy(ptr2_reg, emit_unwrap(const_str_reg), const_str_len); vcode_reg_t locus = lower_debug_locus(type_unit(type, 0)); @@ -5477,7 +5480,7 @@ static vcode_reg_t lower_physical_value_helper(type_t type, vcode_reg_t preg) vcode_select_block(match_bb); - vcode_reg_t mul_ptr = emit_add(mul_array_ptr, i_reg); + vcode_reg_t mul_ptr = emit_array_ref(mul_array_ptr, i_reg); vcode_reg_t mul_reg = emit_load_indirect(mul_ptr); return emit_mul(int_reg, mul_reg); } @@ -5864,8 +5867,8 @@ static void lower_array_cmp_inner(vcode_reg_t lhs_data, vcode_reg_t i_eq_len = emit_cmp(VCODE_CMP_EQ, inc, left_len); - vcode_reg_t l_ptr = emit_add(lhs_data, ptr_inc); - vcode_reg_t r_ptr = emit_add(rhs_data, ptr_inc); + vcode_reg_t l_ptr = emit_array_ref(lhs_data, ptr_inc); + vcode_reg_t r_ptr = emit_array_ref(rhs_data, ptr_inc); if (type_is_array(elem_type)) { lower_array_cmp_inner(l_ptr, r_ptr, @@ -6014,7 +6017,8 @@ static void lower_predef_scalar_to_string(type_t arg_type, type_t std_string, vcode_select_block(char_bb); - vcode_reg_t char1_ptr = emit_add(data_reg, emit_const(vtype_offset(), 1)); + vcode_reg_t one_reg = emit_const(vtype_offset(), 1); + vcode_reg_t char1_ptr = emit_array_ref(data_reg, one_reg); vcode_reg_t left_reg = emit_uarray_left(str_reg, 0); vcode_reg_t dir_reg = emit_uarray_dir(str_reg, 0); @@ -6078,11 +6082,11 @@ static void lower_predef_array_to_string(type_t arg_type, type_t std_string, vcode_select_block(body_bb); vcode_reg_t i_reg = emit_load(i_var); - vcode_reg_t sptr_reg = emit_add(lower_array_data(array_reg), i_reg); + vcode_reg_t sptr_reg = emit_array_ref(lower_array_data(array_reg), i_reg); vcode_reg_t src_reg = emit_load_indirect(sptr_reg); vcode_reg_t off_reg = emit_cast(vtype_offset(), vtype_offset(), src_reg); - vcode_reg_t lptr_reg = emit_add(emit_address_of(map_reg), off_reg); - vcode_reg_t dptr_reg = emit_add(lower_array_data(mem_reg), i_reg); + vcode_reg_t lptr_reg = emit_array_ref(emit_address_of(map_reg), off_reg); + vcode_reg_t dptr_reg = emit_array_ref(lower_array_data(mem_reg), i_reg); emit_store_indirect(emit_load_indirect(lptr_reg), dptr_reg); vcode_reg_t next_reg = emit_add(i_reg, emit_const(vtype_offset(), 1)); @@ -6159,8 +6163,8 @@ static void lower_predef_bit_shift(tree_t decl, vcode_unit_t context, break; case S_SRA: { - vcode_reg_t last_ptr = - emit_add(data_reg, emit_sub(len_reg, emit_const(voffset, 1))); + vcode_reg_t len_minus_1 = emit_sub(len_reg, emit_const(voffset, 1)); + vcode_reg_t last_ptr = emit_array_ref(data_reg, len_minus_1); def_reg = emit_load_indirect(last_ptr); } break; @@ -6210,7 +6214,7 @@ static void lower_predef_bit_shift(tree_t decl, vcode_unit_t context, break; } - vcode_reg_t dst_ptr = emit_add(mem_reg, i_reg); + vcode_reg_t dst_ptr = emit_array_ref(mem_reg, i_reg); vcode_reg_t next_reg = emit_add(i_reg, emit_const(vtype_offset(), 1)); emit_store(next_reg, i_var); @@ -6242,7 +6246,7 @@ static void lower_predef_bit_shift(tree_t decl, vcode_unit_t context, break; } - vcode_reg_t load_reg = emit_load_indirect(emit_add(data_reg, src_reg)); + vcode_reg_t load_reg = emit_load_indirect(emit_array_ref(data_reg, src_reg)); emit_store_indirect(load_reg, dst_ptr); emit_jump(cmp_bb); @@ -6323,12 +6327,12 @@ static void lower_predef_bit_vec_op(tree_t decl, vcode_unit_t context, vcode_select_block(body_bb); - vcode_reg_t dst_ptr = emit_add(mem_reg, i_reg); + vcode_reg_t dst_ptr = emit_array_ref(mem_reg, i_reg); - vcode_reg_t src0_reg = emit_load_indirect(emit_add(data0_reg, i_reg)); + vcode_reg_t src0_reg = emit_load_indirect(emit_array_ref(data0_reg, i_reg)); vcode_reg_t src1_reg = VCODE_INVALID_REG; if (kind != S_ARRAY_NOT) - src1_reg = emit_load_indirect(emit_add(data1_reg, i_reg)); + src1_reg = emit_load_indirect(emit_array_ref(data1_reg, i_reg)); vcode_reg_t op_reg; switch (kind) { @@ -6396,7 +6400,7 @@ static void lower_predef_mixed_bit_vec_op(tree_t decl, vcode_unit_t context, vcode_select_block(body_bb); vcode_reg_t i_reg = emit_load(i_var); - vcode_reg_t l_reg = emit_load_indirect(emit_add(data_reg, i_reg)); + vcode_reg_t l_reg = emit_load_indirect(emit_array_ref(data_reg, i_reg)); vcode_reg_t r_reg = r0_is_array ? r1 : r0; vcode_reg_t result_reg = VCODE_INVALID_REG; @@ -6410,7 +6414,7 @@ static void lower_predef_mixed_bit_vec_op(tree_t decl, vcode_unit_t context, default: break; } - emit_store_indirect(result_reg, emit_add(mem_reg, i_reg)); + emit_store_indirect(result_reg, emit_array_ref(mem_reg, i_reg)); vcode_reg_t next_reg = emit_add(i_reg, emit_const(voffset, 1)); vcode_reg_t cmp_reg = emit_cmp(VCODE_CMP_EQ, next_reg, len_reg); @@ -6461,7 +6465,7 @@ static void lower_predef_reduction_op(tree_t decl, vcode_unit_t context, vcode_select_block(body_bb); vcode_reg_t i_reg = emit_load(i_var); - vcode_reg_t src_reg = emit_load_indirect(emit_add(data_reg, i_reg)); + vcode_reg_t src_reg = emit_load_indirect(emit_array_ref(data_reg, i_reg)); vcode_reg_t cur_reg = emit_load(result_var); vcode_reg_t result_reg = VCODE_INVALID_REG; @@ -6591,8 +6595,11 @@ static void lower_predef_match_op(tree_t decl, vcode_unit_t context, vcode_reg_t i_reg = emit_load(i_var); - vcode_reg_t r0_src_reg = emit_load_indirect(emit_add(r0_ptr, i_reg)); - vcode_reg_t r1_src_reg = emit_load_indirect(emit_add(r1_ptr, i_reg)); + vcode_reg_t i0_ptr = emit_array_ref(r0_ptr, i_reg); + vcode_reg_t i1_ptr = emit_array_ref(r1_ptr, i_reg); + + vcode_reg_t r0_src_reg = emit_load_indirect(i0_ptr); + vcode_reg_t r1_src_reg = emit_load_indirect(i1_ptr); vcode_reg_t tmp; if (is_bit) @@ -6603,7 +6610,7 @@ static void lower_predef_match_op(tree_t decl, vcode_unit_t context, vcode_reg_t args[] = { context_reg, r0_src_reg, r1_src_reg }; tmp = emit_fcall(func, vtype, vbounds, VCODE_CC_PREDEF, args, 3); } - emit_store_indirect(tmp, emit_add(mem_reg, i_reg)); + emit_store_indirect(tmp, emit_array_ref(mem_reg, i_reg)); vcode_reg_t next_reg = emit_add(i_reg, emit_const(vtype_offset(), 1)); vcode_reg_t cmp_reg = emit_cmp(VCODE_CMP_EQ, next_reg, len0_reg); @@ -6708,7 +6715,8 @@ static void lower_predef_min_max(tree_t decl, vcode_unit_t context, vcode_select_block(body_bb); vcode_reg_t i_reg = emit_load(i_var); - vcode_reg_t elem_reg = emit_load_indirect(emit_add(data_reg, i_reg)); + vcode_reg_t elem_ptr = emit_array_ref(data_reg, i_reg); + vcode_reg_t elem_reg = emit_load_indirect(elem_ptr); vcode_reg_t cur_reg = emit_load(result_var); vcode_reg_t cmp_reg = emit_cmp(cmp, elem_reg, cur_reg); vcode_reg_t next_reg = emit_select(cmp_reg, elem_reg, cur_reg); diff --git a/src/vcode.c b/src/vcode.c index 308c0391..da39216e 100644 --- a/src/vcode.c +++ b/src/vcode.c @@ -367,8 +367,7 @@ void vcode_heap_allocate(vcode_reg_t reg) // TODO: check this break; - case VCODE_OP_ADD: - // When adding pointers only the first argument is a pointer + case VCODE_OP_ARRAY_REF: vcode_heap_allocate(defn->args.items[0]); break; @@ -454,6 +453,7 @@ void vcode_heap_allocate(vcode_reg_t reg) case VCODE_OP_MOD: case VCODE_OP_REM: case VCODE_OP_ENDFILE: + case VCODE_OP_ADD: // Result cannot reference pointer break; @@ -602,6 +602,7 @@ void vcode_opt(void) case VCODE_OP_LOAD: case VCODE_OP_LOAD_INDIRECT: case VCODE_OP_ADD: + case VCODE_OP_ARRAY_REF: case VCODE_OP_SUB: case VCODE_OP_MUL: case VCODE_OP_CMP: @@ -894,7 +895,7 @@ const char *vcode_op_string(vcode_op_t op) "driving value", "address of", "closure", "protected init", "context upref", "const rep", "protected free", "sched static", "implicit signal", "disconnect", "link package", "index check", - "debug locus", "length check", "range check" + "debug locus", "length check", "range check", "array ref", }; if ((unsigned)op >= ARRAY_LEN(strs)) return "???"; @@ -1696,6 +1697,17 @@ void vcode_dump_with_mark(int mark_op, vcode_dump_fn_t callback, void *arg) } break; + case VCODE_OP_ARRAY_REF: + { + col += vcode_dump_reg(op->result); + col += printf(" := %s ", vcode_op_string(op->kind)); + col += vcode_dump_reg(op->args.items[0]); + col += printf(" offset "); + col += vcode_dump_reg(op->args.items[1]); + vcode_dump_result_type(col, op); + } + break; + case VCODE_OP_COPY: { vcode_dump_reg(op->args.items[0]); @@ -3312,16 +3324,8 @@ static vcode_reg_t emit_arith(vcode_op_t kind, vcode_reg_t lhs, vcode_reg_t rhs, vcode_type_t lhs_type = vcode_reg_type(lhs); vcode_type_t rhs_type = vcode_reg_type(rhs); - const vtype_kind_t ltypek = vtype_kind(vcode_reg_type(lhs)); - const bool is_pointer = - ltypek == VCODE_TYPE_POINTER || ltypek == VCODE_TYPE_SIGNAL; - - if (is_pointer && vtype_kind(rhs_type) == VCODE_TYPE_OFFSET) - ; - else - VCODE_ASSERT(vtype_eq(lhs_type, rhs_type), - "arguments to %s are not the same type", - vcode_op_string(kind)); + VCODE_ASSERT(vtype_eq(lhs_type, rhs_type), + "arguments to %s are not the same type", vcode_op_string(kind)); return op->result; } @@ -3443,10 +3447,6 @@ vcode_reg_t emit_rem(vcode_reg_t lhs, vcode_reg_t rhs) vcode_reg_t emit_add(vcode_reg_t lhs, vcode_reg_t rhs) { - const vtype_kind_t ltypek = vtype_kind(vcode_reg_type(lhs)); - const bool is_pointer = - ltypek == VCODE_TYPE_POINTER || ltypek == VCODE_TYPE_SIGNAL; - int64_t lconst, rconst; const bool l_is_const = vcode_reg_const(lhs, &lconst); const bool r_is_const = vcode_reg_const(rhs, &rconst); @@ -3460,9 +3460,7 @@ vcode_reg_t emit_add(vcode_reg_t lhs, vcode_reg_t rhs) vcode_reg_t reg = emit_arith(VCODE_OP_ADD, lhs, rhs, VCODE_INVALID_REG); reg_t *rr = vcode_reg_data(reg); - if (is_pointer) - rr->bounds = vcode_reg_data(lhs)->bounds; - else if (ltypek != VCODE_TYPE_REAL) { + if (vcode_reg_kind(lhs) != VCODE_TYPE_REAL) { vtype_t *bl = vcode_type_data(vcode_reg_data(lhs)->bounds); vtype_t *br = vcode_type_data(vcode_reg_data(rhs)->bounds); @@ -4322,6 +4320,32 @@ vcode_reg_t emit_record_ref(vcode_reg_t record, unsigned field) return op->result; } +vcode_reg_t emit_array_ref(vcode_reg_t array, vcode_reg_t offset) +{ + VCODE_FOR_EACH_MATCHING_OP(other, VCODE_OP_ARRAY_REF) { + if (other->args.items[0] == array && other->args.items[1] == offset) + return other->result; + } + + op_t *op = vcode_add_op(VCODE_OP_ARRAY_REF); + vcode_add_arg(op, array); + vcode_add_arg(op, offset); + + vcode_type_t rtype = vcode_reg_type(array); + VCODE_ASSERT(vtype_kind(rtype) == VCODE_TYPE_POINTER + || vtype_kind(rtype) == VCODE_TYPE_SIGNAL, + "argument to array ref must a pointer or signal"); + VCODE_ASSERT(vcode_reg_kind(offset) == VCODE_TYPE_OFFSET, + "array ref offset argument must have offset type"); + + op->result = vcode_add_reg(rtype); + + reg_t *rr = vcode_reg_data(op->result); + rr->bounds = vcode_reg_bounds(array); + + return op->result; +} + void emit_copy(vcode_reg_t dest, vcode_reg_t src, vcode_reg_t count) { int64_t cconst; diff --git a/src/vcode.h b/src/vcode.h index 5f63bcc6..6c39d7e7 100644 --- a/src/vcode.h +++ b/src/vcode.h @@ -135,6 +135,7 @@ typedef enum { VCODE_OP_DEBUG_LOCUS, VCODE_OP_LENGTH_CHECK, VCODE_OP_RANGE_CHECK, + VCODE_OP_ARRAY_REF, } vcode_op_t; typedef enum { @@ -404,6 +405,7 @@ vcode_reg_t emit_last_value(vcode_reg_t sig); vcode_reg_t emit_event_flag(vcode_reg_t nets, vcode_reg_t len); vcode_reg_t emit_active_flag(vcode_reg_t nets, vcode_reg_t len); vcode_reg_t emit_record_ref(vcode_reg_t record, unsigned field); +vcode_reg_t emit_array_ref(vcode_reg_t array, vcode_reg_t offset); void emit_copy(vcode_reg_t dest, vcode_reg_t src, vcode_reg_t count); void emit_sched_event(vcode_reg_t nets, vcode_reg_t n_elems); void emit_sched_static(vcode_reg_t nets, vcode_reg_t n_elems); diff --git a/test/test_lower.c b/test/test_lower.c index a3bbed0f..e0530bc7 100644 --- a/test/test_lower.c +++ b/test/test_lower.c @@ -200,6 +200,7 @@ static void check_bb(int bb, const check_bb_t *expect, int len) case VCODE_OP_NOT: case VCODE_OP_LOAD_INDIRECT: case VCODE_OP_STORE_INDIRECT: + case VCODE_OP_ARRAY_REF: case VCODE_OP_ADDRESS_OF: case VCODE_OP_SCHED_WAVEFORM: case VCODE_OP_SELECT: @@ -538,28 +539,31 @@ START_TEST(test_assign2) EXPECT_BB(1) = { { VCODE_OP_CONST, .value = 2 }, { VCODE_OP_INDEX, .name = "X" }, + { VCODE_OP_CONST, .value = 0 }, { VCODE_OP_CONST, .value = 7 }, - { VCODE_OP_ADD, }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_LOAD_INDIRECT }, { VCODE_OP_CONST, .value = 0 }, { VCODE_OP_CMP }, { VCODE_OP_DEBUG_LOCUS }, { VCODE_OP_ASSERT }, { VCODE_OP_CONST, .value = 3 }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_LOAD_INDIRECT }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_LOAD_INDIRECT }, { VCODE_OP_CMP }, { VCODE_OP_DEBUG_LOCUS }, { VCODE_OP_ASSERT }, { VCODE_OP_CONST, .value = 1 }, { VCODE_OP_CONST, .value = 5 }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_STORE_INDIRECT }, { VCODE_OP_INDEX, .name = "Y" }, { VCODE_OP_CONST, .value = 2 }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_LOAD_INDIRECT }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_STORE_INDIRECT }, { VCODE_OP_WAIT, .target = 2 } }; @@ -1335,10 +1339,12 @@ START_TEST(test_signal4) { VCODE_OP_VAR_UPREF, .hops = 1, .name = "S" }, { VCODE_OP_LOAD_INDIRECT }, { VCODE_OP_RESOLVED }, + { VCODE_OP_CONST, .value = 0 }, { VCODE_OP_CONST, .value = 1 }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_LOAD_INDIRECT }, { VCODE_OP_INDEX, .name = "V" }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_STORE_INDIRECT }, { VCODE_OP_CONST, .value = 0 }, { VCODE_OP_LOAD_INDIRECT }, @@ -1655,7 +1661,7 @@ START_TEST(test_slice1) { VCODE_OP_COPY }, { VCODE_OP_CONST, .value = 0 }, { VCODE_OP_CONST, .value = 1 }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_CONST, .value = 2 }, { VCODE_OP_CONST, .value = 6 }, { VCODE_OP_CONST, .value = 7 }, @@ -1665,7 +1671,7 @@ START_TEST(test_slice1) { VCODE_OP_TEMP_STACK_MARK }, { VCODE_OP_CONST, .value = 2 }, { VCODE_OP_CONTEXT_UPREF, .hops = 1 }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_WRAP }, { VCODE_OP_CONST_ARRAY, .length = 2 }, { VCODE_OP_ADDRESS_OF }, @@ -1871,7 +1877,7 @@ START_TEST(test_bounds1) { VCODE_OP_CONST, .value = 9 }, { VCODE_OP_CONST, .value = 0 }, { VCODE_OP_CAST }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_LOAD_INDIRECT }, { VCODE_OP_CONST, .value = 1 }, { VCODE_OP_CMP, .cmp = VCODE_CMP_EQ }, @@ -1881,7 +1887,7 @@ START_TEST(test_bounds1) { VCODE_OP_DEBUG_LOCUS }, { VCODE_OP_INDEX_CHECK }, { VCODE_OP_CAST }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_LOAD_INDIRECT }, { VCODE_OP_CMP, .cmp = VCODE_CMP_EQ }, { VCODE_OP_DEBUG_LOCUS }, @@ -2003,7 +2009,7 @@ START_TEST(test_issue116) { VCODE_OP_VAR_UPREF, .name = "INTSTAT", .hops = 1 }, { VCODE_OP_LOAD_INDIRECT }, { VCODE_OP_CONST, .value = 1 }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_CONST, .value = 7 }, { VCODE_OP_SCHED_STATIC }, { VCODE_OP_RETURN } @@ -2181,15 +2187,15 @@ START_TEST(test_issue135) { VCODE_OP_WRAP }, { VCODE_OP_UNWRAP }, { VCODE_OP_COPY }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_UNWRAP }, { VCODE_OP_COPY }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_STORE_INDIRECT }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_UNWRAP }, { VCODE_OP_COPY }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_STORE_INDIRECT }, { VCODE_OP_RETURN } }; @@ -2481,7 +2487,7 @@ START_TEST(test_issue203) { VCODE_OP_CONST, .value = 6 }, { VCODE_OP_ALLOCA }, { VCODE_OP_COPY }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_STORE_INDIRECT }, { VCODE_OP_FILE_WRITE }, { VCODE_OP_TEMP_STACK_RESTORE }, @@ -2715,7 +2721,7 @@ START_TEST(test_thunk) { VCODE_OP_CONST_ARRAY, .length = 4 }, { VCODE_OP_ADDRESS_OF }, { VCODE_OP_CONST, .value = 2 }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_LOAD_INDIRECT }, { VCODE_OP_NOT }, { VCODE_OP_RETURN }, @@ -2731,7 +2737,9 @@ START_TEST(test_thunk) EXPECT_BB(0) = { { VCODE_OP_LINK_VAR, .name = "WORK.PACK.D" }, + { VCODE_OP_CONST, .value = 0 }, { VCODE_OP_CONST, .value = 1 }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_RECORD_REF, .field = 0 }, { VCODE_OP_LOAD_INDIRECT }, { VCODE_OP_ADD }, @@ -3064,7 +3072,7 @@ START_TEST(test_hintbug) { VCODE_OP_ALLOCA }, { VCODE_OP_WRAP }, { VCODE_OP_STORE_INDIRECT }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_STORE_INDIRECT }, { VCODE_OP_FCALL , .func = "STD.STANDARD.\"=\"(QQ)B" }, { VCODE_OP_DEBUG_LOCUS }, @@ -3095,7 +3103,7 @@ START_TEST(test_issue351) { VCODE_OP_CONST, .value = 0 }, { VCODE_OP_INDEX, .name = "CURR_QUEUE" }, { VCODE_OP_CAST }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_WRAP }, { VCODE_OP_FCALL, .func = "*WORK.ISSUE351.DUMP_WORDS" }, { VCODE_OP_TEMP_STACK_RESTORE }, @@ -3203,7 +3211,7 @@ START_TEST(test_tounsigned) { VCODE_OP_SELECT }, { VCODE_OP_CAST }, { VCODE_OP_UNWRAP }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_STORE_INDIRECT }, { VCODE_OP_JUMP, .target = 8 }, }; @@ -3225,7 +3233,7 @@ START_TEST(test_tounsigned) { VCODE_OP_SELECT }, { VCODE_OP_CAST }, { VCODE_OP_UNWRAP }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_STORE_INDIRECT }, { VCODE_OP_JUMP, .target = 8 } }; @@ -3357,7 +3365,7 @@ START_TEST(test_sum) { VCODE_OP_SELECT }, { VCODE_OP_CAST }, { VCODE_OP_UNWRAP }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_LOAD_INDIRECT }, { VCODE_OP_ADD }, { VCODE_OP_CONST, .value = INT32_MIN }, @@ -3773,7 +3781,7 @@ START_TEST(test_conv1) { VCODE_OP_INDEX_CHECK }, { VCODE_OP_CAST }, { VCODE_OP_UNWRAP }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_RECORD_REF, .field = 0 }, { VCODE_OP_LOAD_INDIRECT }, { VCODE_OP_CAST }, @@ -3937,7 +3945,7 @@ START_TEST(test_protupref) { VCODE_OP_CAST }, { VCODE_OP_CONST, .value = 7 }, { VCODE_OP_MUL }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_DEBUG_LOCUS }, { VCODE_OP_REPORT }, { VCODE_OP_RETURN }, @@ -4020,9 +4028,11 @@ START_TEST(test_array2) EXPECT_BB(1) = { { VCODE_OP_INDEX, .name = "V" }, { VCODE_OP_LOAD, .name = "X" }, + { VCODE_OP_CONST, .value = 0 }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_STORE_INDIRECT }, { VCODE_OP_CONST, .value = 1 }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_STORE_INDIRECT }, { VCODE_OP_WAIT, .target = 2 }, }; @@ -4040,6 +4050,8 @@ START_TEST(test_array2) { VCODE_OP_CONST, .value = 8 }, { VCODE_OP_MEMSET }, { VCODE_OP_LOAD, .name = "X" }, + { VCODE_OP_CONST, .value = 0 }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_STORE_INDIRECT }, { VCODE_OP_WAIT, .target = 2 }, }; @@ -4055,14 +4067,18 @@ START_TEST(test_array2) { VCODE_OP_INDEX, .name = "V" }, { VCODE_OP_CONST, .value = 2 }, { VCODE_OP_CONST, .value = 1 }, + { VCODE_OP_CONST, .value = 0 }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_LOAD, .name = "X" }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_STORE_INDIRECT }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_STORE_INDIRECT }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_LOAD, .name = "Y" }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_STORE_INDIRECT }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_STORE_INDIRECT }, { VCODE_OP_WAIT, .target = 2 }, }; @@ -4090,11 +4106,13 @@ START_TEST(test_array2) { VCODE_OP_LOAD, .name = "*i" }, { VCODE_OP_ADD }, { VCODE_OP_STORE, .name = "*i" }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_LOAD, .name = "Y" }, + { VCODE_OP_CONST, .value = 0 }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_STORE_INDIRECT }, { VCODE_OP_CONST, .value = 1 }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_STORE_INDIRECT }, { VCODE_OP_CMP, .cmp = VCODE_CMP_EQ }, { VCODE_OP_COND, .target = 3, .target_else = 2 }, @@ -4103,10 +4121,13 @@ START_TEST(test_array2) CHECK_BB(2); EXPECT_BB(3) = { + { VCODE_OP_CONST, .value = 0 }, + { VCODE_OP_ARRAY_REF, .value = 0 }, { VCODE_OP_LOAD, .name = "X" }, + { VCODE_OP_ARRAY_REF, .value = 0 }, { VCODE_OP_STORE_INDIRECT }, { VCODE_OP_CONST, .value = 1 }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_STORE_INDIRECT }, { VCODE_OP_TEMP_STACK_RESTORE }, { VCODE_OP_WAIT, .target = 4 }, @@ -4123,13 +4144,15 @@ START_TEST(test_array2) { VCODE_OP_INDEX, .name = "V" }, { VCODE_OP_CONST, .value = 1 }, { VCODE_OP_CONST, .value = 3 }, + { VCODE_OP_CONST, .value = 0 }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_STORE_INDIRECT }, { VCODE_OP_LOAD, .name = "X" }, { VCODE_OP_CONST, .value = 1 }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_STORE_INDIRECT }, { VCODE_OP_CONST, .value = 2 }, - { VCODE_OP_ADD }, + { VCODE_OP_ARRAY_REF }, { VCODE_OP_STORE_INDIRECT }, { VCODE_OP_WAIT, .target = 2 }, }; -- 2.39.2