fix(mpact): fix vector instruction bugs and refine trap logic Refine RVV implementation in mpact simulator to address several instruction bugs and trap handling mismatches: 1. Trap Handling: Append "&& is_interrupt" to existing trap conditions to resolve PC mismatch in ecall. 2. Mask Search: Correct the implementation for Vmsbf, Vmsif, and Vmsof mask search instructions. 3. Bitwise Ops: Update BitwiseMaskBinaryOp for vmand, vmnor, and vmxor. 4. vsetvli: Fix x0, x0 logic to preserve current_vl when max_vector_length remains unchanged. 5. Reduction: Fix data truncation in Vwredsum/u by aligning the accumulator with the destination's widening width. 6. Vslide: - Introduced is_down flag and corrected Vslideup/down logic. - Refined execution logic for Vslide1up/down single-element slide. (Backported from mpact-riscv-vsi commit 6dac0e2a09d0845f1499f46ca2d05d24e1306605) Note: The VlIndexed fix was omitted from this backport as it was natively fixed in google3 already. PiperOrigin-RevId: 975873345
diff --git a/riscv/riscv_state.cc b/riscv/riscv_state.cc index 3a2d616..69465e8 100644 --- a/riscv/riscv_state.cc +++ b/riscv/riscv_state.cc
@@ -739,7 +739,7 @@ // Get trap destination. int trap_vector_mode = tvec_csr->AsUint64() & 0x3ULL; uint64_t trap_target = tvec_csr->AsUint64() & ~0x3ULL; - if (trap_vector_mode == 1) { + if (trap_vector_mode == 1 && is_interrupt) { trap_target += 4 * exception_code; }
diff --git a/riscv/riscv_vector_opm_instructions.cc b/riscv/riscv_vector_opm_instructions.cc index 21e3157..234a01f 100644 --- a/riscv/riscv_vector_opm_instructions.cc +++ b/riscv/riscv_vector_opm_instructions.cc
@@ -190,8 +190,6 @@ RiscVVectorState* rv_vector, const Instruction* inst, std::function<uint8_t(uint8_t, uint8_t)> op) { if (rv_vector->vector_exception()) return; - int vstart = rv_vector->vstart(); - int vlen = rv_vector->vector_length(); // Get spans for vector source and destination registers. auto* vs2_op = static_cast<RV32VectorSourceOperand*>(inst->Source(0)); auto vs2_span = vs2_op->GetRegister(0)->data_buffer()->Get<uint8_t>(); @@ -202,24 +200,21 @@ auto* vd_db = vd_op->CopyDataBuffer(); auto vd_span = vd_db->Get<uint8_t>(); // Compute start and end locations. + + int vstart = rv_vector->vstart(); int start_byte = vstart / 8; int start_offset = vstart % 8; - uint8_t start_mask = 0b1111'1111 << start_offset; - int end_byte = (vlen - 1) / 8; - int end_offset = (vlen - 1) % 8; - uint8_t end_mask = 0b1111'1111 >> (7 - end_offset); - // The start byte is computed first, applying a mask to mask out any preceding - // bits. - vd_span[start_byte] = - (op(vs2_span[start_byte], vs1_span[start_byte]) & start_mask) | - (vd_span[start_byte] & ~start_mask); - // Perform the bitwise operation on each byte between start and end. - for (int i = start_byte + 1; i < end_byte; i++) { + + if (start_byte < vd_span.size()) { + uint8_t start_mask = 0b1111'1111 << start_offset; + vd_span[start_byte] = + (op(vs2_span[start_byte], vs1_span[start_byte]) & start_mask) | + (vd_span[start_byte] & ~start_mask); + } + + for (int i = start_byte + 1; i < vd_span.size(); i++) { vd_span[i] = op(vs2_span[i], vs1_span[i]); } - // Perform the bitwise operation with a mask on the end byte. - vd_span[end_byte] = (op(vs2_span[end_byte], vs1_span[end_byte]) & end_mask) | - (vd_span[end_byte] & ~end_mask); vd_db->Submit(); rv_vector->clear_vstart(); }
diff --git a/riscv/riscv_vector_permute_instructions.cc b/riscv/riscv_vector_permute_instructions.cc index 9dda8e9..9710286 100644 --- a/riscv/riscv_vector_permute_instructions.cc +++ b/riscv/riscv_vector_permute_instructions.cc
@@ -172,7 +172,8 @@ // This helper function handles the vector slide up/down instructions. template <typename Vd> -void VSlideHelper(RiscVVectorState* rv_vector, Instruction* inst, int offset) { +void VSlideHelper(RiscVVectorState* rv_vector, Instruction* inst, int offset, + bool is_down) { if (rv_vector->vector_exception()) return; int num_elements = rv_vector->vector_length(); int elements_per_vector = @@ -208,17 +209,25 @@ for (int i = item_index; (i < element_count) && (vector_index < num_elements); i++) { // Get the mask value. - int mask_index = i >> 3; - int mask_offset = i & 0b111; + int mask_index = vector_index >> 3; + int mask_offset = vector_index & 0b111; bool mask_value = ((mask_span[mask_index] >> mask_offset) & 0b1); - int src_index = vector_index - offset; - if ((src_index >= 0) && (mask_value)) { - // Compute result. - Vd src_value = 0; - if (src_index < rv_vector->max_vector_length()) { - src_value = generic::GetInstructionSource<Vd>(inst, 0, src_index); + if (mask_value) { + if (is_down) { + uint64_t src_idx = (uint64_t)vector_index + offset; + if (src_idx < rv_vector->max_vector_length()) { + dest_span[i] = + generic::GetInstructionSource<Vd>(inst, 0, (int)src_idx); + } else { + dest_span[i] = 0; + } + } else { + if ((uint64_t)vector_index >= offset) { + uint64_t src_idx = (uint64_t)vector_index - offset; + dest_span[i] = + generic::GetInstructionSource<Vd>(inst, 0, (int)src_idx); + } } - dest_span[i] = src_value; } vector_index++; } @@ -239,13 +248,13 @@ // Slide up amount is positive. switch (sew) { case 1: - return VSlideHelper<uint8_t>(rv_vector, inst, int_offset); + return VSlideHelper<uint8_t>(rv_vector, inst, int_offset, false); case 2: - return VSlideHelper<uint16_t>(rv_vector, inst, int_offset); + return VSlideHelper<uint16_t>(rv_vector, inst, int_offset, false); case 4: - return VSlideHelper<uint32_t>(rv_vector, inst, int_offset); + return VSlideHelper<uint32_t>(rv_vector, inst, int_offset, false); case 8: - return VSlideHelper<uint64_t>(rv_vector, inst, int_offset); + return VSlideHelper<uint64_t>(rv_vector, inst, int_offset, false); default: rv_vector->set_vector_exception(); LOG(ERROR) << "Illegal SEW value"; @@ -257,18 +266,17 @@ using ValueType = RV32Register::ValueType; auto* rv_vector = static_cast<RiscVState*>(inst->state())->rv_vector(); int sew = rv_vector->selected_element_width(); - auto offset = generic::GetInstructionSource<ValueType>(inst, 1, 0); // Slide down amount is negative. - int int_offset = -static_cast<int>(offset); + auto offset = generic::GetInstructionSource<ValueType>(inst, 1, 0); switch (sew) { case 1: - return VSlideHelper<uint8_t>(rv_vector, inst, int_offset); + return VSlideHelper<uint8_t>(rv_vector, inst, offset, true); case 2: - return VSlideHelper<uint16_t>(rv_vector, inst, int_offset); + return VSlideHelper<uint16_t>(rv_vector, inst, offset, true); case 4: - return VSlideHelper<uint32_t>(rv_vector, inst, int_offset); + return VSlideHelper<uint32_t>(rv_vector, inst, offset, true); case 8: - return VSlideHelper<uint64_t>(rv_vector, inst, int_offset); + return VSlideHelper<uint64_t>(rv_vector, inst, offset, true); default: rv_vector->set_vector_exception(); LOG(ERROR) << "Illegal SEW value"; @@ -311,28 +319,31 @@ auto* dest_db = dest_op->CopyDataBuffer(reg); auto dest_span = dest_db->Get<Vd>(); // Write data into register subject to masking. - int element_count = std::min(elements_per_vector, num_elements); + int element_count = elements_per_vector; for (int i = item_index; (i < element_count) && (vector_index < num_elements); i++) { // Get the mask value. - int mask_index = i >> 3; - int mask_offset = i & 0b111; + int mask_index = vector_index >> 3; + int mask_offset = vector_index & 0b111; bool mask_value = ((mask_span[mask_index] >> mask_offset) & 0b1) != 0; + if (mask_value) { // Compute result. - Vd src_value = slide_value; - int src_index = vector_index - offset; - // Fix for slide1 instructions: - // 1. For vslide1up (offset=1), src_index=0 is valid (vs2[0]), so check - // src_index >= 0. - // 2. For vslide1down (offset=-1), when vector_index=vl-1, src_index=vl. - // We must use - // slide_value if src_index >= vl (num_elements), not - // max_vector_length (VLMAX). - if ((src_index >= 0) && (src_index < num_elements)) { - src_value = generic::GetInstructionSource<Vd>(inst, 0, src_index); + Vd result; + if (offset == 1) { // slide1up + if (vector_index == 0) + result = slide_value; + else + result = + generic::GetInstructionSource<Vd>(inst, 0, vector_index - 1); + } else { // slide1down + if (vector_index == num_elements - 1) + result = slide_value; + else + result = + generic::GetInstructionSource<Vd>(inst, 0, vector_index + 1); } - dest_span[i] = src_value; + dest_span[i] = result; } vector_index++; }
diff --git a/riscv/riscv_vector_reduction_instructions.cc b/riscv/riscv_vector_reduction_instructions.cc index 53d099f..df8e82d 100644 --- a/riscv/riscv_vector_reduction_instructions.cc +++ b/riscv/riscv_vector_reduction_instructions.cc
@@ -293,18 +293,18 @@ int sew = rv_vector->selected_element_width(); switch (sew) { case 1: - return RiscVBinaryReductionVectorOp<uint16_t, uint8_t, uint8_t>( + return RiscVBinaryReductionVectorOp<uint16_t, uint8_t, uint16_t>( rv_vector, inst, [](uint16_t acc, uint8_t vs2) -> uint16_t { return acc + static_cast<uint16_t>(vs2); }); case 2: - return RiscVBinaryReductionVectorOp<uint32_t, uint16_t, uint16_t>( + return RiscVBinaryReductionVectorOp<uint32_t, uint16_t, uint32_t>( rv_vector, inst, [](uint32_t acc, uint16_t vs2) -> uint32_t { return acc + static_cast<uint32_t>(vs2); }); return; case 4: - return RiscVBinaryReductionVectorOp<uint64_t, uint32_t, uint32_t>( + return RiscVBinaryReductionVectorOp<uint64_t, uint32_t, uint64_t>( rv_vector, inst, [](uint64_t acc, uint32_t vs2) -> uint64_t { return acc + static_cast<uint64_t>(vs2); }); @@ -323,18 +323,18 @@ int sew = rv_vector->selected_element_width(); switch (sew) { case 1: - return RiscVBinaryReductionVectorOp<int16_t, int8_t, int8_t>( + return RiscVBinaryReductionVectorOp<int16_t, int8_t, int16_t>( rv_vector, inst, [](int16_t acc, int8_t vs2) -> int16_t { return acc + static_cast<int16_t>(vs2); }); case 2: - return RiscVBinaryReductionVectorOp<int32_t, int16_t, int16_t>( + return RiscVBinaryReductionVectorOp<int32_t, int16_t, int32_t>( rv_vector, inst, [](int32_t acc, int16_t vs2) -> int32_t { return acc + static_cast<int32_t>(vs2); }); return; case 4: - return RiscVBinaryReductionVectorOp<int64_t, int32_t, int32_t>( + return RiscVBinaryReductionVectorOp<int64_t, int32_t, int64_t>( rv_vector, inst, [](int64_t acc, int32_t vs2) -> int64_t { return acc + static_cast<int64_t>(vs2); });
diff --git a/riscv/riscv_vector_unary_instructions.cc b/riscv/riscv_vector_unary_instructions.cc index 9183614..6769b71 100644 --- a/riscv/riscv_vector_unary_instructions.cc +++ b/riscv/riscv_vector_unary_instructions.cc
@@ -297,7 +297,6 @@ rv_vector->set_vector_exception(); return; } - int vlen = rv_vector->vector_length(); auto src_op = static_cast<RV32VectorSourceOperand*>(inst->Source(0)); auto src_span = src_op->GetRegister(0)->data_buffer()->Get<uint8_t>(); auto mask_op = static_cast<RV32VectorSourceOperand*>(inst->Source(1)); @@ -306,10 +305,11 @@ static_cast<RV32VectorDestinationOperand*>(inst->Destination(0)); auto* dest_db = dest_op->CopyDataBuffer(0); auto dest_span = dest_db->Get<uint8_t>(); + int physical_bits = dest_span.size() * 8; bool before_first = true; int last = 0; // Set the bits before the first active 1. - for (int i = 0; i < vlen; i++) { + for (int i = 0; i < physical_bits; i++) { last = i; int index = i >> 3; int offset = i & 0b111; @@ -322,11 +322,13 @@ dest_span[index] |= 1 << offset; } } - // Clear the remaining bits. - for (int i = last; !before_first && (i < vlen); i++) { + for (int i = last; !before_first && (i < physical_bits); i++) { int index = i >> 3; int offset = i & 0b111; - dest_span[index] &= ~(1 << offset); + int mask_value = (mask_span[index] >> offset) & 0b1; + if (mask_value) { + dest_span[index] &= ~(1 << offset); + } } dest_db->Submit(); rv_vector->clear_vstart(); @@ -339,7 +341,6 @@ rv_vector->set_vector_exception(); return; } - int vlen = rv_vector->vector_length(); auto src_op = static_cast<RV32VectorSourceOperand*>(inst->Source(0)); auto src_span = src_op->GetRegister(0)->data_buffer()->Get<uint8_t>(); auto mask_op = static_cast<RV32VectorSourceOperand*>(inst->Source(1)); @@ -348,8 +349,9 @@ static_cast<RV32VectorDestinationOperand*>(inst->Destination(0)); auto* dest_db = dest_op->CopyDataBuffer(0); auto dest_span = dest_db->Get<uint8_t>(); + int physical_bits = dest_span.size() * 8; uint8_t value = 1; - for (int i = 0; i < vlen; i++) { + for (int i = 0; i < physical_bits; i++) { int index = i >> 3; int offset = i & 0b111; int mask_value = (mask_span[index] >> offset) & 0b1; @@ -376,17 +378,18 @@ rv_vector->set_vector_exception(); return; } - int vlen = rv_vector->vector_length(); auto src_op = static_cast<RV32VectorSourceOperand*>(inst->Source(0)); auto src_span = src_op->GetRegister(0)->data_buffer()->Get<uint8_t>(); auto mask_op = static_cast<RV32VectorSourceOperand*>(inst->Source(1)); auto mask_span = mask_op->GetRegister(0)->data_buffer()->Get<uint8_t>(); auto dest_op = static_cast<RV32VectorDestinationOperand*>(inst->Destination(0)); + auto* dest_db = dest_op->CopyDataBuffer(0); auto dest_span = dest_db->Get<uint8_t>(); + int physical_bits = dest_span.size() * 8; bool first = true; - for (int i = 0; i < vlen; i++) { + for (int i = 0; i < physical_bits; i++) { int index = i >> 3; int offset = i & 0b111; int mask_value = (mask_span[index] >> offset) & 0b1;
diff --git a/riscv/test/riscv_vector_opm_instructions_test.cc b/riscv/test/riscv_vector_opm_instructions_test.cc index 786e12f..8c8070d 100644 --- a/riscv/test/riscv_vector_opm_instructions_test.cc +++ b/riscv/test/riscv_vector_opm_instructions_test.cc
@@ -120,7 +120,7 @@ int mask_index = i >> 3; int mask_offset = i & 0b111; bool result = (dst_span[mask_index] >> mask_offset) & 0b1; - if ((i < vstart) || (i >= vlen)) { + if (i < vstart) { bool vd = (vd_value[mask_index] >> mask_offset) & 0b1; EXPECT_EQ(result, vd) << "[" << i << "] " << std::hex << "vd: " << (int)vd_value[mask_index]
diff --git a/riscv/test/riscv_vector_reduction_instructions_test.cc b/riscv/test/riscv_vector_reduction_instructions_test.cc index 827419c..3943f4f 100644 --- a/riscv/test/riscv_vector_reduction_instructions_test.cc +++ b/riscv/test/riscv_vector_reduction_instructions_test.cc
@@ -78,15 +78,15 @@ // Input values for 8 registers. Vs2 vs2_value[vs2_size * 8]; auto vs2_span = Span<Vs2>(vs2_value); - Vs2 vs1_value[vs2_size]; - auto vs1_span = Span<Vs2>(vs1_value); + Vd vs1_value[kVectorLengthInBytes / sizeof(Vd)]; + auto vs1_span = Span<Vd>(vs1_value); AppendVectorRegisterOperands({kVs2, kVs1, kVmask}, {kVd}); // Initialize input values. FillArrayWithRandomValues<Vs2>(vs2_span); - vs1_span[0] = RandomValue<Vs2>(); + vs1_span[0] = RandomValue<Vd>(); auto mask_span = Span<const uint8_t>(kA5Mask); SetVectorRegisterValues<uint8_t>({{kVmaskName, mask_span}}); - SetVectorRegisterValues<Vs2>({{kVs1Name, Span<const Vs2>(vs1_span)}}); + SetVectorRegisterValues<Vd>({{kVs1Name, Span<const Vd>(vs1_span)}}); // Initialize the accumulator with the value from vs1[0]. for (int i = 0; i < 8; i++) { auto vs2_name = absl::StrCat("v", kVs2 + i);