diff --git a/frontends/ast/simplify.cc b/frontends/ast/simplify.cc
index 64191cd7ebf..98dc5015af9 100644
--- a/frontends/ast/simplify.cc
+++ b/frontends/ast/simplify.cc
@@ -2875,12 +2875,23 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
 		{
 			// big case block
 
+			// Optimization for the common case of a two-dimensional packed array -
+			// remove multiplication of index by stride.
+			int div_stride = 1;
+			if (!source_offset && shift_expr->type == AST_MUL && shift_expr->children[1]->type == AST_CONSTANT && (int)shift_expr->children[1]->integer == stride)
+			{
+				AstNode *tmp = shift_expr->children[0]->clone();
+				delete shift_expr;
+				shift_expr = tmp;
+				div_stride = stride;
+			}
+
 			did_something = true;
 			newNode = new AstNode(AST_CASE, shift_expr);
 			for (int i = 0; i < source_width; i += stride) {
 				int start_bit = source_offset + i;
 				int end_bit = std::min(start_bit+result_width,source_width) - 1;
-				AstNode *cond = new AstNode(AST_COND, mkconst_int(start_bit, true));
+				AstNode *cond = new AstNode(AST_COND, mkconst_int(start_bit/div_stride, true));
 				AstNode *lvalue = children[0]->clone();
 				lvalue->delete_children();
 				if (member_node)
@@ -2893,7 +2904,7 @@ bool AstNode::simplify(bool const_fold, bool in_lvalue, int stage, int width_hin
 		}
 		else
 		{
-			// mask and shift operations, disabled for now
+			// mask and shift operations
 
 			AstNode *wire_mask = new AstNode(AST_WIRE, new AstNode(AST_RANGE, mkconst_int(source_width-1, true), mkconst_int(0, true)));
 			wire_mask->str = stringf("$bitselwrite$mask$%s:%d$%d", RTLIL::encode_filename(filename).c_str(), location.first_line, autoidx++);
diff --git a/tests/svtypes/struct_dynamic_range.ys b/tests/svtypes/struct_dynamic_range.ys
index 9606e73840c..3891c2b3a8b 100644
--- a/tests/svtypes/struct_dynamic_range.ys
+++ b/tests/svtypes/struct_dynamic_range.ys
@@ -1,5 +1,5 @@
 read_verilog -sv struct_dynamic_range.sv
-select -assert-count 4 t:$mul
+select -assert-count 3 t:$mul
 select -assert-count 2 t:$shift
 select -assert-count 2 t:$shiftx
 prep -top top