By default, the RTX generation pass conservatively expands bit-field
insertion to an insn sequence consisting of the bit mask and shift of
the inserted value, the bit-inversion mask of the destination, and finally
a logical-OR.
However, if the logical-AND operation on an inverted bit-field mask is
relatively expensive, it is more advantageous to shift the inserted value
without masking it and then follow the idiom '(A & M) | (B & ~M)' ->
'((A ^ B) & M) ^ B'.
/* example */
struct foo {
unsigned int x:10;
unsigned int y:11;
unsigned int z:11;
};
struct foo test0(struct foo a, unsigned int b) {
a.x = b;
return a;
}
struct foo test1(struct foo a, unsigned int b) {
a.y = b;
return a;
}
;; before (-Os ; !BITS_BIG_ENDIAN | !TARGET_DEPBITS)
test0:
entry sp, 32
movi a8, -0x400 ;; = ~0x000003FF
extui a3, a3, 0, 10 ;; mask
and a2, a2, a8 ;; inverted mask
or a2, a2, a3 ;; logical-OR
retw.n
.literal_position
.literal .LC0, -2096129 ;; = ~0x001FFC00
test1:
entry sp, 32
l32r a8, .LC0
extui a3, a3, 0, 11 ;; mask
slli a3, a3, 10 ;;
and a2, a2, a8 ;; inverted mask
or a2, a2, a3 ;; logical-OR
retw.n
;; after (-Os ; !BITS_BIG_ENDIAN | !TARGET_DEPBITS)
test0:
entry sp, 32
xor a3, a2, a3
extui a3, a3, 0, 10 ;; mask
xor a2, a2, a3
retw.n
test1:
entry sp, 32
slli a3, a3, 10 ;; bit-position alignment
xor a3, a2, a3
extui a3, a3, 10, 11 ;; mask
slli a3, a3, 10 ;;
xor a2, a2, a3
retw.n
gcc/ChangeLog:
* config/xtensa/xtensa.md (insvsi_intermal):
Rename from 'insvsi'.
(insvsi): New expansion pattern that also addresses situations
where the DEPBITS machine instruction is unavailable.
---
gcc/config/xtensa/xtensa.md | 30 +++++++++++++++++++++++++++++-
1 file changed, 29 insertions(+), 1 deletion(-)
diff --git a/gcc/config/xtensa/xtensa.md b/gcc/config/xtensa/xtensa.md
index 8354ab250a1..31abbc8aa2d 100644
--- a/gcc/config/xtensa/xtensa.md
+++ b/gcc/config/xtensa/xtensa.md
@@ -1079,7 +1079,35 @@
(set_attr "mode" "SI")
(set_attr "length" "6")])
-(define_insn "insvsi"
+(define_expand "insvsi"
+ [(set (zero_extract:SI (match_operand:SI 0 "register_operand")
+ (match_operand:SI 1 "extui_fldsz_operand")
+ (match_operand:SI 2 "const_int_operand"))
+ (match_operand:SI 3 "register_operand"))]
+ ""
+{
+ if (TARGET_DEPBITS)
+ emit_insn (gen_insvsi_internal (operands[0], operands[1], operands[2],
+ operands[3]));
+ else
+ {
+ int fldsz = INTVAL (operands[1]), shift;
+ rtx temp = gen_reg_rtx (SImode), mask;
+ if (BITS_BIG_ENDIAN)
+ shift = (32 - (fldsz + INTVAL (operands[2]))) & 0x1f;
+ else
+ shift = INTVAL (operands[2]) & 0x1f;
+ mask = GEN_INT (((1 << fldsz) - 1) << shift);
+ emit_insn (shift ? gen_ashlsi3 (temp, operands[3], GEN_INT (shift))
+ : gen_rtx_SET (temp, operands[3]));
+ emit_insn (gen_xorsi3 (temp, operands[0], temp));
+ emit_insn (gen_andsi3 (temp, temp, force_reg (SImode, mask)));
+ emit_insn (gen_xorsi3 (operands[0], operands[0], temp));
+ }
+ DONE;
+})
+
+(define_insn "insvsi_internal"
[(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+a")
(match_operand:SI 1 "extui_fldsz_operand" "")
(match_operand:SI 2 "const_int_operand" ""))
--
2.39.5