gcc.old: vax: PR port-vax/57646 patch provided by Kalvis Duckmanton [21/21]

Define separate instruction patterns for extzv for the cases where the fiel
d width and offset happen to be a multiple of a byte or word.

If in PIC mode, and the source operand to extzv is a memory
reference, and the address of the memory location is an external
symbol, load the address into a temporary register before expanding
the instruction.

Adjust the constraints to the zero_extract instruction pattern to
disallow indexed source operands, as the VAX extzv instruction
computes offsets based on the size of a byte (not a word or a
longword)
This commit is contained in:
rin 2023-10-07 12:10:59 +00:00
parent 53a1228e9d
commit 8b0d23297f
1 changed files with 155 additions and 37 deletions

View File

@ -827,32 +827,87 @@
return \"movw %3,%0\";
}")
(define_insn ""
[(set (match_operand:SI 0 "nonimmediate_operand" "=&g")
(zero_extract:SI (match_operand:SI 1 "register_operand" "ro")
;;
;; Register source, field width is either 8 or 16, field start
;; is zero - simple, this is a mov[bl].
;;
(define_insn "*extzvQISI"
[(set (match_operand:SI 0 "nonimmediate_operand" "=g")
(zero_extract:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:QI 2 "const_int_operand" "n")
(match_operand:SI 3 "const_int_operand" "n")))]
"(INTVAL (operands[2]) == 8 || INTVAL (operands[2]) == 16)
&& INTVAL (operands[3]) % INTVAL (operands[2]) == 0
&& (REG_P (operands[1])
|| (MEM_P (operands[1])
&& ! mode_dependent_address_p (XEXP (operands[1], 0),
MEM_ADDR_SPACE (operands[1]))))"
"INTVAL (operands[3]) == 0
&& INTVAL (operands[2]) == GET_MODE_BITSIZE ( QImode )"
"movzbl %1, %0"
)
(define_insn "*extzvHISI"
[(set (match_operand:SI 0 "nonimmediate_operand" "=g")
(zero_extract:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:QI 2 "const_int_operand" "n")
(match_operand:SI 3 "const_int_operand" "n")))]
"INTVAL (operands[3]) == 0
&& INTVAL (operands[2]) == GET_MODE_BITSIZE ( HImode )"
"movzwl %1, %0"
)
;;
;; Register source, field width is the entire register
;;
(define_insn "*extzvSISI"
[(set (match_operand:SI 0 "nonimmediate_operand" "=g")
(zero_extract:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:QI 2 "const_int_operand" "n")
(match_operand:SI 3 "const_int_operand" "n")
))]
"INTVAL (operands[3]) == 0
&& INTVAL (operands[2]) == GET_MODE_BITSIZE ( SImode )"
"*
{
if (REG_P (operands[1]))
{
if (INTVAL (operands[3]) != 0)
return \"extzv %3,%2,%1,%0\";
}
else
operands[1]
= adjust_address (operands[1],
INTVAL (operands[2]) == 8 ? QImode : HImode,
INTVAL (operands[3]) / 8);
if (rtx_equal_p (operands[0], operands[1]))
return \"\"; /* no-op */
return \"movl %1,%0\";
}")
if (INTVAL (operands[2]) == 8)
return \"movzbl %1,%0\";
;; Register source, non-zero field start is handled elsewhere
;; Offsettable memory, field width 8 or 16, field start on
;; boundary matching the field width.
(define_insn "*extzvQISI2"
[(set (match_operand:SI 0 "nonimmediate_operand" "=g")
(zero_extract:SI (match_operand:SI 1 "memory_operand" "o")
(match_operand:QI 2 "const_int_operand" "n")
(match_operand:SI 3 "const_int_operand" "n")))]
"INTVAL (operands[2]) == 8
&& INTVAL (operands[3]) % INTVAL (operands[2]) == 0
&& ! mode_dependent_address_p (XEXP (operands[1], 0),
MEM_ADDR_SPACE (operands[1]))"
"*
{
operands[1]
= adjust_address (operands[1],
QImode,
INTVAL (operands[3]) / 8);
return \"movzbl %1,%0\";
}")
(define_insn "*extzvHISI2"
[(set (match_operand:SI 0 "nonimmediate_operand" "=g")
(zero_extract:SI (match_operand:SI 1 "memory_operand" "o")
(match_operand:QI 2 "const_int_operand" "n")
(match_operand:SI 3 "const_int_operand" "n")))]
"INTVAL (operands[2]) == 16
&& INTVAL (operands[3]) % INTVAL (operands[2]) == 0
&& ! mode_dependent_address_p (XEXP (operands[1], 0),
MEM_ADDR_SPACE (operands[1]))"
"*
{
operands[1]
= adjust_address (operands[1],
HImode,
INTVAL (operands[3]) / 8);
return \"movzwl %1,%0\";
}")
@ -929,17 +984,26 @@
return \"rotl %R3,%1,%0\;cvtwl %0,%0\";
}")
;; When the field position and size are constant and the destination
;; is a register, extv and extzv are much slower than a rotate followed
;; by a bicl or sign extension. Because we might end up choosing ext[z]v
;; anyway, we can't allow immediate values for the primary source operand.
;; Because some of the instruction sequences generated by this pattern
;; overwrite the output operand part way through, the output operand
;; must be marked earlyclobber, may only be a register or memory
;; operand and must not have any side effects (e.g. pre/post increment)
;;
(define_insn ""
[(set (match_operand:SI 0 "nonimmediate_operand" "=g")
(zero_extract:SI (match_operand:SI 1 "register_operand" "ro")
(match_operand:QI 2 "general_operand" "g")
(match_operand:SI 3 "general_operand" "nrmT")))]
""
[(set (match_operand:SI 0 "nonimmediate_operand" "=&ro")
(zero_extract:SI (match_operand:SI 1 "register_operand" "r")
(match_operand:QI 2 "const_int_operand" "n")
(match_operand:SI 3 "const_int_operand" "n")
))]
"INTVAL (operands[3]) != 0"
"*
{
if (! CONST_INT_P (operands[3]) || ! CONST_INT_P (operands[2])
|| ! REG_P (operands[0]))
return \"extzv %3,%2,%1,%0\";
if (INTVAL (operands[2]) == 8)
return \"rotl %R3,%1,%0\;movzbl %0,%0\";
if (INTVAL (operands[2]) == 16)
@ -1041,13 +1105,70 @@
[(set (match_operand:SI 0 "general_operand" "")
(zero_extract:SI (match_operand:SI 1 "general_operand" "")
(match_operand:QI 2 "general_operand" "")
(match_operand:SI 3 "general_operand" "")))]
(match_operand:SI 3 "general_operand" ""))
)]
""
"")
"{
if (CONST_INT_P (operands[1]))
{
/*
* extzv of a constant doesn't work, so load the constant
* into a register.
*/
rtx temp = gen_reg_rtx (SImode);
emit_move_insn (temp, operands[1]);
operands[1] = temp;
}
/*
* If the source operand is a memory reference, and the address
* is a symbol, and we're in PIC mode, load the address into a
* register. Don't evaluate the field start or width at this time.
*/
if (flag_pic
/* && !reload_completed */
&& MEM_P (operands[1])
&& !mode_dependent_address_p (XEXP (operands[1], 0),
MEM_ADDR_SPACE (operands[1]))
&& SYMBOL_REF_P (XEXP (operands[1], 0))
&& !SYMBOL_REF_LOCAL_P (XEXP (operands[1], 0))
)
{
rtx address = XEXP (operands[1], 0);
rtx temp = gen_reg_rtx (Pmode);
emit_move_insn (temp, address);
/* copy the original memory reference, replacing the address */
operands[1] = change_address (operands[1], VOIDmode, temp);
set_mem_align (operands[1], MEM_ALIGN (operands[1]));
}
else
if ((MEM_P (operands[1]) && !CONST_INT_P (operands[2]))
|| SUBREG_P (operands[1])
)
{
/* Memory addresses for extzv are bytes, so load the source
operand into a register */
rtx temp = gen_reg_rtx (SImode);
emit_move_insn (temp, operands[1]);
operands[1] = temp;
}
else if (address_operand (operands[1], SImode))
{
operands[1] = force_reg (SImode, operands[1]);
}
}"
)
;;
;; Operand 1 must not, under any circumstances, be an indexed operand
;; as extzv computes indices based on the size of a byte.
;;
(define_insn ""
[(set (match_operand:SI 0 "nonimmediate_operand" "=g")
(zero_extract:SI (match_operand:QI 1 "memory_operand" "m")
[(set (match_operand:SI 0 "nonimmediate_operand" "=&g")
(zero_extract:SI (match_operand:SI 1 "nonimmediate_operand" "rQ")
(match_operand:QI 2 "general_operand" "g")
(match_operand:SI 3 "general_operand" "nrmT")))]
""
@ -1056,10 +1177,7 @@
if (! REG_P (operands[0]) || ! CONST_INT_P (operands[2])
|| ! CONST_INT_P (operands[3])
|| INTVAL (operands[2]) + INTVAL (operands[3]) > 32
|| side_effects_p (operands[1])
|| (MEM_P (operands[1])
&& mode_dependent_address_p (XEXP (operands[1], 0),
MEM_ADDR_SPACE (operands[1]))))
|| side_effects_p (operands[1]))
return \"extzv %3,%2,%1,%0\";
if (INTVAL (operands[2]) == 8)
return \"rotl %R3,%1,%0\;movzbl %0,%0\";