Tamar Christina <[email protected]> writes: >> > For LE the first pattern stays the same. We also add these >> > >> > (define_insn "*aarch64_vec_concat_lane<mode>" >> > [(set (match_operand:VP_2E 0 "register_operand" "=w,w") >> > (vec_concat:VP_2E >> > (vec_select:<VEL> >> > (match_operand:VP_2E 1 "register_operand" "0,w") >> > (parallel >> > [(match_operand:SI 3 "immediate_operand" "i,i")])) >> > (vec_select:<VEL> >> > (match_operand:VP_2E 2 "register_operand" "w,0") >> > (parallel >> > [(match_operand:SI 4 "immediate_operand" "i,i")]))))] >> > "TARGET_SIMD >> > && INTVAL (operands[3]) == 0 >> > && INTVAL (operands[4]) == 1" >> > { >> > ... >> > >> > Which essentially is saying concat two vectors together from a vec_select. >> > This then becomes your INS. >> > >> > Then for BE you rewrite the vec_merge into the vec_concat using e.g. >> > >> > (define_insn_and_split >> "*aarch64_simd_vec_copy_lane_same<mode>_be_lowpart" >> > [(set (match_operand:VP_2E 0 "register_operand" "=w,w") >> > (vec_merge:VP_2E >> > (vec_duplicate:VP_2E >> > (match_operand:<VEL> 2 "register_operand" "w,0")) >> > (match_operand:VP_2E 1 "register_operand" "0,w") >> > (match_operand:SI 3 "immediate_operand" "i,i")))] >> > "TARGET_SIMD >> > && BYTES_BIG_ENDIAN >> > && !reload_completed >> > && INTVAL (operands[3]) == 2 >> > && SUBREG_P (operands[2]) >> > && subreg_lowpart_p (operands[2])" >> > "#" >> > "&& true" >> > ... >> > >> > This changes the codegen to target >> > >> > (vec_concat:V2DF >> > (vec_select:DF (reg:V2DF x) [(const_int 0)]) >> > (vec_select:DF (reg:V2DF y) [(const_int 1)])) >> > >> > Which represents the INS without needing the subreg lanes and the subreg >> > goes away way before reload. >> > >> > Hopefully Richard is happy with this one. >> >> But I'm not sure what this subreg stuff is trying to achieve. Are you >> trying to force the case where operand 2 is a "natural scalar" (handwavy >> term) through a different pattern? If so, which one? >> >> The existing vec_merge-of-vec_duplicate patterns don't seem to care >> where the scalar comes from. If the operand is a plain pseudo REG >> defined by a GPR operation then LRA will generate a GPR-to-FPR move. >> One of those is going to be needed somewhere in that case. >> >> So I was more wondering why your original suggestion needed the: >> >> && SUBREG_P (operands[2]) >> && known_eq (SUBREG_BYTE (operands[2]), GET_MODE_SIZE >> (<VEL>mode))" >> >> and couldn't just be: >> >> "TARGET_SIMD && INTVAL (operands[3]) == 2" >> > > Because this pattern is *only* valid for upper inserts, lower inserts is > handled > by the first one, the aarch64_simd_vec_copy_lane<mode>. > > Operand two, since the vec_merge pattern is a bit mask, 2 means your > destination is lane 1, the > known_eq (SUBREG_BYTE (operands[2]), GET_MODE_SIZE> (<VEL>mode)) > > comparison is only valid if the subreg is the high part of a 2 lane > vector. Or in > other words, lane 1. So this pattern is only handling ins[1], ins[1].
Guess I'm just stating common ground in the first few paragraphs below, but: Subregs like that are only allowed in one special case: a 64-bit highpart of a 128-bit AdvSIMD register. The fact that that case is allowed is due to a defective definition of REGMODE_NATURAL_SIZE, which Robin is in the process of fixing. Once the 64-bit highpart of a 128-bit register case is used, we have already lost, since if we have: (subreg:DI (reg:V2DI R) 0) [big-endian] (subreg:DI (reg:V2DI R) 8) [little-endian] LRA will not allocate R to a SIMD register. (This is partly due to the simplifiable_subregs/valid_mode_changes_for_regno stuff.) So the subregs that I listed above wouldn't become references to architectural lane 1. Instead, the RAs would spill R and reload the high 64 bits into the lowpart of a SIMD register, which would become operand 2. I think this would normally happen through memory, but perhaps GPRs are also possible. So after RA, operand 2 would always be the lowpart of a SIMD register (lane 0), and would have the right contents, whatever the SUBREG_BYTE was before RA. The behaviour would be correct, but the spilling would make the subregs above very inefficient. Perhaps you were wanting to prevent the inefficient 64-bit highpart subregs from being formed. But I'm not sure the condition would do that. Even if it does, the same thing would happen for any other DImode SIMD register_operand that had one of the forms above, including the existing vec_merge-of-vec_duplicate patterns. The inefficiency comes from the spilling that LRA is bound to emit, and that inefficiency would apply wherever the subreg occurs, not just to this pattern. The pattern doesn't seem like a special case. So I still think we can ignore whether operand 2 is a subreg. It's the RA's job to ensure that operand 2 occupies the lowpart of a register. Thanks, Richard
